From 99020e391719d3a6d952eb4131721704f87ff4c2 Mon Sep 17 00:00:00 2001 From: Yvo Brevoort Date: Wed, 4 Dec 2024 15:10:29 +0100 Subject: [PATCH] remove simply-backend, create a clean simplycode repo --- 000-default.conf | 32 - Dockerfile | 17 - LICENSE | 2 +- README.md | 3 - .../fonts/CoconRegularFont.woff | Bin .../assets => assets}/img/feather-sprite.svg | 0 .../actions/getComponentNameField.js | 0 .../commands/autoRunPreviews.js | 0 .../commands/resetPreview.js | 0 .../footHtml/Auto run preview.html | 0 .../automatic-preview/meta.json | 0 .../automatic-tests/commands/autoRunTests.js | 0 .../footHtml/Auto run tests.html | 0 .../automatic-tests/meta.json | 0 .../codemirror/commands/codeMirrorInit.js | 0 .../codemirror/footHtml/Codemirror base.html | 0 .../codemirror/footHtml/Codemirror modes.html | 0 .../footHtml/Codemirror styles.html | 0 .../footHtml/Data change codeMirror.html | 0 .../codemirror/meta.json | 0 .../dragdrop/footHtml | 0 .../dragdrop/meta.json | 0 .../font-cocon/headHtml/cocon.html | 0 .../font-cocon/meta.json | 0 .../home/meta.json | 0 .../home/routes/home.js | 0 .../home/routes/home.json | 0 .../footHtml/component-parts-count.html | 0 .../list-counters/meta.json | 0 .../main-menu/bodyHtml/Load main menu.html | 0 .../main-menu/meta.json | 0 .../raw-api/meta.json | 0 .../raw-api/rawApi/delete.js | 0 .../raw-api/rawApi/encodeGetParams.js | 0 .../raw-api/rawApi/get.js | 0 .../raw-api/rawApi/headers.js | 0 .../raw-api/rawApi/post.js | 0 .../raw-api/rawApi/postRaw.js | 0 .../raw-api/rawApi/put.js | 0 .../raw-api/rawApi/putRaw.js | 0 .../raw-api/rawApi/url.js | 0 .../toasts/bodyHtml/HTML structure.html | 0 .../toasts/bodyHtml/Toast styles.html | 0 .../toasts/footHtml/toastAnimation.html | 0 .../toasts/meta.json | 0 .../0-ds-styling/componentCss/extra.css | 0 .../0-ds-styling/componentCss/style.css | 0 .../0-ds-styling/meta.json | 0 .../1-styling/componentCss/extra.css | 0 .../simplycode-component-list.css | 0 .../componentCss/simplycode-ds-mapping.css | 0 .../1-styling/componentCss/style.css | 0 .../1-styling/meta.json | 0 .../component-actions/commands/addAction.js | 0 .../tests/addAction/Add two actions.js | 0 .../componentTemplates/componentActions.html | 0 .../component-actions/meta.json | 0 .../commands/addBodyHtml.js | 0 .../componentTemplates/componentBodyHtml.html | 0 .../component-body-html/meta.json | 0 .../component-commands/commands/addCommand.js | 0 .../componentTemplates/componentCommands.html | 0 .../component-commands/meta.json | 0 .../commands/addComponentCss.js | 0 .../componentComponentCss.html | 0 .../component-component-css/meta.json | 0 .../commands/addComponentTemplate.js | 0 .../componentComponentTemplate.html | 0 .../component-component-html/meta.json | 0 .../commands/addDataApiMethod.js | 0 .../componentTemplates/componentDataApi.html | 0 .../component-data-api/meta.json | 0 .../commands/addDataSource.js | 0 .../componentDataSources.html | 0 .../component-data-sources/meta.json | 0 .../componentDescription.html | 0 .../component-description/meta.json | 0 .../commands/addFootHtml.js | 0 .../componentTemplates/componentFootHtml.html | 0 .../component-foot-html/meta.json | 0 .../commands/addHeadHtml.js | 0 .../componentTemplates/componentHeadHtml.html | 0 .../component-head-html/meta.json | 0 .../component-page-css/commands/addPageCss.js | 0 .../componentTemplates/componentPageCss.html | 0 .../component-page-css/meta.json | 0 .../componentPageFrame.html | 0 .../component-page-frame/meta.json | 0 .../commands/addPageTemplate.js | 0 .../componentPageTemplate.html | 0 .../component-page-template/meta.json | 0 .../component-qunit-tests/commands/addTest.js | 0 .../componentCss/QUnit iframe.css | 0 .../componentQUnitActionRunner.html | 0 .../componentQUnitCommandRunner.html | 0 .../componentQUnitTests.html | 0 .../component-qunit-tests/meta.json | 0 .../commands/addRawApiMethod.js | 0 .../componentTemplates/componentRawApi.html | 0 .../component-raw-api/meta.json | 0 .../component-routes/commands/addRoute.js | 0 .../componentTemplates/componentRoutes.html | 0 .../component-routes/meta.json | 0 .../component-sorters/commands/addSorter.js | 0 .../componentTemplates/componentSorters.html | 0 .../component-sorters/meta.json | 0 .../commands/addTransformer.js | 0 .../componentTransformers.html | 0 .../component-transformers/meta.json | 0 .../commands/deleteEntry.js | 0 .../commands/initEditors.js | 0 .../componentCss/code-method block.css | 0 .../componentCss/deleted-parts.css | 0 .../components-generic/meta.json | 0 .../data-format/dataApi/deletePart.js | 0 .../data-format/dataApi/mergeComponent.js | 0 .../data-format/dataApi/mergePageFrame.js | 0 .../data-format/dataApi/savePart.js | 0 .../data-format/meta.json | 0 .../dragdrop/componentCss/simply dragdrop.css | 0 .../dragdrop/meta.json | 0 .../header/componentTemplates/header.html | 0 .../header/meta.json | 0 .../componentCss/HTML validator.css | 0 .../componentHtmlValidator.html | 0 .../html-validator/meta.json | 0 .../transformers/validateHtml-extract.js | 0 .../transformers/validateHtml-render.js | 0 .../navigation/actions/browse.js | 0 .../navigation/actions/getMainMenu.js | 0 .../navigation/commands/collapseMenu.js | 0 .../navigation/commands/expandMenu.js | 0 .../navigation/commands/navigate.js | 0 .../navigation/componentTemplates/menu.html | 0 .../navigation/dataApi/browse.js | 0 .../navigation/meta.json | 0 .../componentCss/App full preview.css | 0 .../componentTemplates/componentPreview.html | 0 .../componentTemplates/fullAppPreview.html | 0 .../componentTemplates/pagePreview.html | 0 .../previews/meta.json | 0 .../simplyPreviewActions-extract.js | 0 .../simplyPreviewActions-render.js | 0 .../simplyPreviewBodyHtml-extract.js | 0 .../simplyPreviewBodyHtml-render.js | 0 .../simplyPreviewCommands-extract.js | 0 .../simplyPreviewCommands-render.js | 0 .../simplyPreviewComponent-extract.js | 0 .../simplyPreviewComponent-render.js | 0 .../simplyPreviewComponentCss-extract.js | 0 .../simplyPreviewComponentCss-render.js | 0 ...simplyPreviewComponentTemplates-extract.js | 0 .../simplyPreviewComponentTemplates-render.js | 0 .../simplyPreviewDataApi-extract.js | 0 .../simplyPreviewDataApi-render.js | 0 .../simplyPreviewDataSources-extract.js | 0 .../simplyPreviewDataSources-render.js | 0 .../simplyPreviewFootHtml-extract.js | 0 .../simplyPreviewFootHtml-render.js | 0 .../simplyPreviewFullApp-extract.js | 0 .../simplyPreviewFullApp-render.js | 0 .../simplyPreviewHeadHtml-extract.js | 0 .../simplyPreviewHeadHtml-render.js | 0 .../transformers/simplyPreviewPage-extract.js | 0 .../transformers/simplyPreviewPage-render.js | 0 .../simplyPreviewPageCss-extract.js | 0 .../simplyPreviewPageCss-render.js | 0 .../simplyPreviewPageTemplates-extract.js | 0 .../simplyPreviewPageTemplates-render.js | 0 .../simplyPreviewRawApi-extract.js | 0 .../simplyPreviewRawApi-render.js | 0 .../simplyPreviewRoutes-extract.js | 0 .../simplyPreviewRoutes-render.js | 0 .../simplyPreviewSorters-extract.js | 0 .../simplyPreviewSorters-render.js | 0 .../simplyPreviewTransformers-extract.js | 0 .../simplyPreviewTransformers-render.js | 0 .../simply-logo/componentCss/simply-logo.css | 0 .../simply-logo/componentTemplates/logo.html | 0 .../simply-logo/meta.json | 0 .../simply-toolbar/commands/preview.js | 0 .../componentCss/simply-toobar-button.css | 0 .../componentCss/simply-toolbar.css | 0 .../simply-toolbar-base-component.html | 0 .../simply-toolbar-component.html | 0 .../simply-toolbar-default.html | 0 .../simply-toolbar-page-frame.html | 0 .../simply-toolbar-page.html | 0 .../simply-toolbar-publish.html | 0 .../componentTemplates/simply-toolbar.html | 0 .../simply-toolbar/meta.json | 0 docker-compose.yml | 15 - www/api/data/generated.html => generated.html | 0 lib/config.php | 27 - lib/filesystem.php | 432 - lib/http.php | 138 - lib/router.php | 73 - npm_post_install.sh | 58 - package-lock.json | 25 - package.json | 27 - .../componentPreview.html | 0 .../page-frame => page-frame}/fullApp.html | 0 .../pagePreview.html | 0 .../actions/deleteBaseComponent.js | 0 .../actions/getBaseComponent.js | 0 .../actions/saveBaseComponent.js | 0 .../commands/deleteBaseComponent.js | 0 .../commands/saveBaseComponent.js | 0 .../dataApi/deleteBaseComponent.js | 0 .../dataApi/deleteBaseComponentPart.js | 0 .../dataApi/getBaseComponent.js | 0 .../dataApi/saveBaseComponentPart.js | 0 .../pages => pages}/base-component/meta.json | 0 .../pageTemplates/Edit base component.html | 0 .../base-component/routes/base-component.js | 0 .../base-component/routes/base-component.json | 0 .../actions/listBaseComponents.js | 0 .../commands/createBaseComponent.js | 0 .../dataApi/listBaseComponents.js | 0 .../pages => pages}/base-components/meta.json | 0 .../pageTemplates/Base components.html | 0 .../base-components/routes/base-components.js | 0 .../routes/base-components.json | 0 .../transformers/baseComponentLink-extract.js | 0 .../transformers/baseComponentLink-render.js | 0 .../component-list/actions/listComponents.js | 0 .../commands/createComponent.js | 0 .../component-list/dataApi/listComponents.js | 0 .../pages => pages}/component-list/meta.json | 0 .../pageTemplates/List components.html | 0 .../pageTemplates/List components.json | 0 .../component-list/routes/component-list.js | 0 .../component-list/routes/component-list.json | 0 .../transformers/componentLink-extract.js | 0 .../transformers/componentLink-render.js | 0 .../component/actions/deleteComponent.js | 0 .../component/actions/getComponent.js | 0 .../component/actions/saveComponent.js | 0 .../component/commands/deleteComponent.js | 0 .../component/commands/saveComponent.js | 0 .../component/dataApi/deleteComponent.js | 0 .../component/dataApi/deleteComponentPart.js | 0 .../component/dataApi/getComponent.js | 0 .../component/dataApi/saveComponentPart.js | 0 .../data/pages => pages}/component/meta.json | 0 .../pageTemplates/Edit component.html | 0 .../component/routes/component.js | 0 .../component/routes/component.json | 0 .../page-frame/actions/getPageFrame.js | 0 .../page-frame/actions/savePageFrame.js | 0 .../page-frame/commands/savePageFrame.js | 0 .../page-frame/dataApi/deletePageFramePart.js | 0 .../page-frame/dataApi/getPageFrame.js | 0 .../page-frame/dataApi/savePageFramePart.js | 0 .../data/pages => pages}/page-frame/meta.json | 0 .../pageTemplates/Edit page frame.html | 0 .../page-frame/routes/page-frame.js | 0 .../page-frame/routes/page-frame.json | 0 .../page/actions/deletePage.js | 0 .../pages => pages}/page/actions/getPage.js | 0 .../pages => pages}/page/actions/savePage.js | 0 .../page/commands/deletePage.js | 0 .../pages => pages}/page/commands/savePage.js | 0 .../page/dataApi/deletePage.js | 0 .../page/dataApi/deletePagePart.js | 0 .../pages => pages}/page/dataApi/getPage.js | 0 .../page/dataApi/savePagePart.js | 0 {www/api/data/pages => pages}/page/meta.json | 0 .../page/pageTemplates/Edit page.html | 0 .../data/pages => pages}/page/routes/page.js | 0 .../pages => pages}/page/routes/page.json | 0 .../pages/actions/listPages.js | 0 .../pages/commands/createPage.js | 0 .../pages/dataApi/listPages.js | 0 {www/api/data/pages => pages}/pages/meta.json | 0 .../pages/pageTemplates/Pages.html | 0 .../pages => pages}/pages/routes/pages.js | 0 .../pages => pages}/pages/routes/pages.json | 0 .../pages/transformers/pageLink-extract.js | 0 .../pages/transformers/pageLink-render.js | 0 .../data/pages => pages}/preview/meta.json | 0 .../pageCss/simplycode-fullscreen-preview.css | 0 .../preview/pageTemplates/preview-app.html | 0 .../pageTemplates/preview-component.html | 0 .../preview/routes/preview-app.js | 0 .../preview/routes/preview-app.json | 0 .../preview/routes/preview-component.js | 0 .../preview/routes/preview-component.json | 0 .../preview/routes/preview-page.js | 0 .../preview/routes/preview-page.json | 0 .../publish/actions/getAppData.js | 0 .../publish/actions/getBaseComponents.js | 0 .../publish/actions/getComponents.js | 0 .../publish/actions/getPages.js | 0 .../publish/actions/getRouteWeight.js | 0 .../publish/actions/saveAppHtml.js | 0 .../getRouteWeight/Fixed path 3 items.js | 0 .../publish/commands/saveAppHtml.js | 0 .../publish/dataApi/saveAppHtml.js | 0 .../data/pages => pages}/publish/meta.json | 0 .../publish/pageTemplates/Publish App.html | 0 .../pages => pages}/publish/routes/publish.js | 0 .../publish/routes/publish.json | 0 .../transformers/htmlEscape-extract.js | 0 .../publish/transformers/htmlEscape-render.js | 0 .../transformers/indentCode-extract.js | 0 .../publish/transformers/indentCode-render.js | 0 www/.gitignore | 1 - www/.htaccess | 39 - www/api/.htaccess | 9 - www/api/data/simplycode.sh | 10 - www/api/index.php | 132 - www/camil_192x192.png | Bin 26043 -> 0 bytes www/camil_512x512.png | Bin 129854 -> 0 bytes www/data/data.json | 29 - www/data/settings.json | 1 - www/files/feather-sprite.svg | 1 - www/generated.html | 1 - www/hope/hope.annotation.js | 46 - www/hope/hope.editor.events.js | 35 - www/hope/hope.editor.js | 483 - www/hope/hope.editor.selection.js | 347 - www/hope/hope.events.js | 35 - www/hope/hope.fragment.annotations.js | 380 - www/hope/hope.fragment.js | 105 - www/hope/hope.fragment.text.js | 64 - www/hope/hope.js | 58 - www/hope/hope.keyboard.js | 214 - www/hope/hope.mime.js | 85 - www/hope/hope.packed.js | 2354 ---- www/hope/hope.polyfills.js | 30 - www/hope/hope.range.js | 247 - www/hope/hope.render.html.js | 353 - www/hope/hope.test.js | 308 - www/hope/pack | 1 - www/index.html | 5378 --------- www/js/codemirror/lib/codemirror.css | 344 - www/js/codemirror/lib/codemirror.js | 9849 ----------------- www/js/codemirror/mode/css/css.js | 866 -- www/js/codemirror/mode/htmlmixed/htmlmixed.js | 153 - .../codemirror/mode/javascript/javascript.js | 960 -- www/js/codemirror/mode/xml/xml.js | 417 - www/js/codemirror/theme/base16-dark.css | 40 - www/js/simply-edit.js | 3824 ------- www/js/simply.everything.js | 1628 --- www/js/simply.include.next.js | 1 - www/simply-edit/bg1.jpg | Bin 154699 -> 0 bytes www/simply-edit/bg2.jpg | Bin 21158 -> 0 bytes www/simply-edit/checks.php | 287 - www/simply-edit/config.php | 38 - www/simply-edit/filesystem.php | 324 - www/simply-edit/htpasswd.php | 122 - www/simply-edit/http.php | 128 - www/simply-edit/index.php | 1599 --- www/simply-edit/login.php | 22 - www/simply-edit/logout.php | 12 - www/simply-edit/mu.js | 1045 -- www/simply-edit/mu.min.js | 1 - www/simply-edit/prerender.php | 23 - www/simply-edit/router.php | 77 - www/simply-edit/sha1.js | 25 - www/simply-edit/simply-edit-centered.svg | 23 - www/simply-edit/store.php | 78 - www/simply-edit/style.css | 89 - www/simply/css/editor.v9.css | 2265 ---- www/simply/databind.js | 1037 -- www/simply/diff_match_patch.js | 76 - www/simply/pack | 1 - www/simply/plugin.simply-about.html | 191 - www/simply/plugin.simply-baseurl.html | 52 - www/simply/plugin.simply-browse.html | 934 -- www/simply/plugin.simply-diff.html | 284 - www/simply/plugin.simply-dropbox.html | 48 - www/simply/plugin.simply-htmlsource.html | 190 - www/simply/plugin.simply-keyboard.html | 170 - www/simply/plugin.simply-login.html | 67 - www/simply/plugin.simply-meta.html | 143 - www/simply/plugin.simply-paste.html | 362 - www/simply/plugin.simply-plain.html | 62 - www/simply/plugin.simply-save.html | 86 - www/simply/plugin.simply-scaler.html | 221 - www/simply/plugin.simply-symbol.html | 133 - www/simply/plugin.simply-template.html | 134 - www/simply/plugin.simply-undo-redo.html | 233 - www/simply/plugin.toolbar-scroll.html | 103 - www/simply/scripts.js | 2325 ---- www/simply/simply.elementBinding.js | 697 -- www/simply/simply.tripleBinding.js | 575 - www/simply/slip.js | 1095 -- www/simply/toolbar.simply-basepack.html | 5372 --------- www/simply/toolbar.simply-icon.html | 16 - www/simply/toolbar.simply-iframe.html | 82 - www/simply/toolbar.simply-image.html | 674 -- www/simply/toolbar.simply-list.html | 448 - www/simply/toolbar.simply-main-toolbar.html | 38 - www/simply/toolbar.simply-selectable.html | 167 - www/simply/toolbar.simply-text.html | 998 -- www/simply/toolbars.js | 1303 --- 398 files changed, 1 insertion(+), 54151 deletions(-) delete mode 100644 000-default.conf delete mode 100644 Dockerfile rename {www/api/data/assets => assets}/fonts/CoconRegularFont.woff (100%) rename {www/api/data/assets => assets}/img/feather-sprite.svg (100%) rename {www/api/data/base-components => base-components}/automatic-preview/actions/getComponentNameField.js (100%) rename {www/api/data/base-components => base-components}/automatic-preview/commands/autoRunPreviews.js (100%) rename {www/api/data/base-components => base-components}/automatic-preview/commands/resetPreview.js (100%) rename {www/api/data/base-components => base-components}/automatic-preview/footHtml/Auto run preview.html (100%) rename {www/api/data/base-components => base-components}/automatic-preview/meta.json (100%) rename {www/api/data/base-components => base-components}/automatic-tests/commands/autoRunTests.js (100%) rename {www/api/data/base-components => base-components}/automatic-tests/footHtml/Auto run tests.html (100%) rename {www/api/data/base-components => base-components}/automatic-tests/meta.json (100%) rename {www/api/data/base-components => base-components}/codemirror/commands/codeMirrorInit.js (100%) rename {www/api/data/base-components => base-components}/codemirror/footHtml/Codemirror base.html (100%) rename {www/api/data/base-components => base-components}/codemirror/footHtml/Codemirror modes.html (100%) rename {www/api/data/base-components => base-components}/codemirror/footHtml/Codemirror styles.html (100%) rename {www/api/data/base-components => base-components}/codemirror/footHtml/Data change codeMirror.html (100%) rename {www/api/data/base-components => base-components}/codemirror/meta.json (100%) rename {www/api/data/base-components => base-components}/dragdrop/footHtml (100%) rename {www/api/data/base-components => base-components}/dragdrop/meta.json (100%) rename {www/api/data/base-components => base-components}/font-cocon/headHtml/cocon.html (100%) rename {www/api/data/base-components => base-components}/font-cocon/meta.json (100%) rename {www/api/data/base-components => base-components}/home/meta.json (100%) rename {www/api/data/base-components => base-components}/home/routes/home.js (100%) rename {www/api/data/base-components => base-components}/home/routes/home.json (100%) rename {www/api/data/base-components => base-components}/list-counters/footHtml/component-parts-count.html (100%) rename {www/api/data/base-components => base-components}/list-counters/meta.json (100%) rename {www/api/data/base-components => base-components}/main-menu/bodyHtml/Load main menu.html (100%) rename {www/api/data/base-components => base-components}/main-menu/meta.json (100%) rename {www/api/data/base-components => base-components}/raw-api/meta.json (100%) rename {www/api/data/base-components => base-components}/raw-api/rawApi/delete.js (100%) rename {www/api/data/base-components => base-components}/raw-api/rawApi/encodeGetParams.js (100%) rename {www/api/data/base-components => base-components}/raw-api/rawApi/get.js (100%) rename {www/api/data/base-components => base-components}/raw-api/rawApi/headers.js (100%) rename {www/api/data/base-components => base-components}/raw-api/rawApi/post.js (100%) rename {www/api/data/base-components => base-components}/raw-api/rawApi/postRaw.js (100%) rename {www/api/data/base-components => base-components}/raw-api/rawApi/put.js (100%) rename {www/api/data/base-components => base-components}/raw-api/rawApi/putRaw.js (100%) rename {www/api/data/base-components => base-components}/raw-api/rawApi/url.js (100%) rename {www/api/data/base-components => base-components}/toasts/bodyHtml/HTML structure.html (100%) rename {www/api/data/base-components => base-components}/toasts/bodyHtml/Toast styles.html (100%) rename {www/api/data/base-components => base-components}/toasts/footHtml/toastAnimation.html (100%) rename {www/api/data/base-components => base-components}/toasts/meta.json (100%) rename {www/api/data/components => components}/0-ds-styling/componentCss/extra.css (100%) rename {www/api/data/components => components}/0-ds-styling/componentCss/style.css (100%) rename {www/api/data/components => components}/0-ds-styling/meta.json (100%) rename {www/api/data/components => components}/1-styling/componentCss/extra.css (100%) rename {www/api/data/components => components}/1-styling/componentCss/simplycode-component-list.css (100%) rename {www/api/data/components => components}/1-styling/componentCss/simplycode-ds-mapping.css (100%) rename {www/api/data/components => components}/1-styling/componentCss/style.css (100%) rename {www/api/data/components => components}/1-styling/meta.json (100%) rename {www/api/data/components => components}/component-actions/commands/addAction.js (100%) rename {www/api/data/components => components}/component-actions/commands/tests/addAction/Add two actions.js (100%) rename {www/api/data/components => components}/component-actions/componentTemplates/componentActions.html (100%) rename {www/api/data/components => components}/component-actions/meta.json (100%) rename {www/api/data/components => components}/component-body-html/commands/addBodyHtml.js (100%) rename {www/api/data/components => components}/component-body-html/componentTemplates/componentBodyHtml.html (100%) rename {www/api/data/components => components}/component-body-html/meta.json (100%) rename {www/api/data/components => components}/component-commands/commands/addCommand.js (100%) rename {www/api/data/components => components}/component-commands/componentTemplates/componentCommands.html (100%) rename {www/api/data/components => components}/component-commands/meta.json (100%) rename {www/api/data/components => components}/component-component-css/commands/addComponentCss.js (100%) rename {www/api/data/components => components}/component-component-css/componentTemplates/componentComponentCss.html (100%) rename {www/api/data/components => components}/component-component-css/meta.json (100%) rename {www/api/data/components => components}/component-component-html/commands/addComponentTemplate.js (100%) rename {www/api/data/components => components}/component-component-html/componentTemplates/componentComponentTemplate.html (100%) rename {www/api/data/components => components}/component-component-html/meta.json (100%) rename {www/api/data/components => components}/component-data-api/commands/addDataApiMethod.js (100%) rename {www/api/data/components => components}/component-data-api/componentTemplates/componentDataApi.html (100%) rename {www/api/data/components => components}/component-data-api/meta.json (100%) rename {www/api/data/components => components}/component-data-sources/commands/addDataSource.js (100%) rename {www/api/data/components => components}/component-data-sources/componentTemplates/componentDataSources.html (100%) rename {www/api/data/components => components}/component-data-sources/meta.json (100%) rename {www/api/data/components => components}/component-description/componentTemplates/componentDescription.html (100%) rename {www/api/data/components => components}/component-description/meta.json (100%) rename {www/api/data/components => components}/component-foot-html/commands/addFootHtml.js (100%) rename {www/api/data/components => components}/component-foot-html/componentTemplates/componentFootHtml.html (100%) rename {www/api/data/components => components}/component-foot-html/meta.json (100%) rename {www/api/data/components => components}/component-head-html/commands/addHeadHtml.js (100%) rename {www/api/data/components => components}/component-head-html/componentTemplates/componentHeadHtml.html (100%) rename {www/api/data/components => components}/component-head-html/meta.json (100%) rename {www/api/data/components => components}/component-page-css/commands/addPageCss.js (100%) rename {www/api/data/components => components}/component-page-css/componentTemplates/componentPageCss.html (100%) rename {www/api/data/components => components}/component-page-css/meta.json (100%) rename {www/api/data/components => components}/component-page-frame/componentTemplates/componentPageFrame.html (100%) rename {www/api/data/components => components}/component-page-frame/meta.json (100%) rename {www/api/data/components => components}/component-page-template/commands/addPageTemplate.js (100%) rename {www/api/data/components => components}/component-page-template/componentTemplates/componentPageTemplate.html (100%) rename {www/api/data/components => components}/component-page-template/meta.json (100%) rename {www/api/data/components => components}/component-qunit-tests/commands/addTest.js (100%) rename {www/api/data/components => components}/component-qunit-tests/componentCss/QUnit iframe.css (100%) rename {www/api/data/components => components}/component-qunit-tests/componentTemplates/componentQUnitActionRunner.html (100%) rename {www/api/data/components => components}/component-qunit-tests/componentTemplates/componentQUnitCommandRunner.html (100%) rename {www/api/data/components => components}/component-qunit-tests/componentTemplates/componentQUnitTests.html (100%) rename {www/api/data/components => components}/component-qunit-tests/meta.json (100%) rename {www/api/data/components => components}/component-raw-api/commands/addRawApiMethod.js (100%) rename {www/api/data/components => components}/component-raw-api/componentTemplates/componentRawApi.html (100%) rename {www/api/data/components => components}/component-raw-api/meta.json (100%) rename {www/api/data/components => components}/component-routes/commands/addRoute.js (100%) rename {www/api/data/components => components}/component-routes/componentTemplates/componentRoutes.html (100%) rename {www/api/data/components => components}/component-routes/meta.json (100%) rename {www/api/data/components => components}/component-sorters/commands/addSorter.js (100%) rename {www/api/data/components => components}/component-sorters/componentTemplates/componentSorters.html (100%) rename {www/api/data/components => components}/component-sorters/meta.json (100%) rename {www/api/data/components => components}/component-transformers/commands/addTransformer.js (100%) rename {www/api/data/components => components}/component-transformers/componentTemplates/componentTransformers.html (100%) rename {www/api/data/components => components}/component-transformers/meta.json (100%) rename {www/api/data/components => components}/components-generic/commands/deleteEntry.js (100%) rename {www/api/data/components => components}/components-generic/commands/initEditors.js (100%) rename {www/api/data/components => components}/components-generic/componentCss/code-method block.css (100%) rename {www/api/data/components => components}/components-generic/componentCss/deleted-parts.css (100%) rename {www/api/data/components => components}/components-generic/meta.json (100%) rename {www/api/data/components => components}/data-format/dataApi/deletePart.js (100%) rename {www/api/data/components => components}/data-format/dataApi/mergeComponent.js (100%) rename {www/api/data/components => components}/data-format/dataApi/mergePageFrame.js (100%) rename {www/api/data/components => components}/data-format/dataApi/savePart.js (100%) rename {www/api/data/components => components}/data-format/meta.json (100%) rename {www/api/data/components => components}/dragdrop/componentCss/simply dragdrop.css (100%) rename {www/api/data/components => components}/dragdrop/meta.json (100%) rename {www/api/data/components => components}/header/componentTemplates/header.html (100%) rename {www/api/data/components => components}/header/meta.json (100%) rename {www/api/data/components => components}/html-validator/componentCss/HTML validator.css (100%) rename {www/api/data/components => components}/html-validator/componentTemplates/componentHtmlValidator.html (100%) rename {www/api/data/components => components}/html-validator/meta.json (100%) rename {www/api/data/components => components}/html-validator/transformers/validateHtml-extract.js (100%) rename {www/api/data/components => components}/html-validator/transformers/validateHtml-render.js (100%) rename {www/api/data/components => components}/navigation/actions/browse.js (100%) rename {www/api/data/components => components}/navigation/actions/getMainMenu.js (100%) rename {www/api/data/components => components}/navigation/commands/collapseMenu.js (100%) rename {www/api/data/components => components}/navigation/commands/expandMenu.js (100%) rename {www/api/data/components => components}/navigation/commands/navigate.js (100%) rename {www/api/data/components => components}/navigation/componentTemplates/menu.html (100%) rename {www/api/data/components => components}/navigation/dataApi/browse.js (100%) rename {www/api/data/components => components}/navigation/meta.json (100%) rename {www/api/data/components => components}/previews/componentCss/App full preview.css (100%) rename {www/api/data/components => components}/previews/componentTemplates/componentPreview.html (100%) rename {www/api/data/components => components}/previews/componentTemplates/fullAppPreview.html (100%) rename {www/api/data/components => components}/previews/componentTemplates/pagePreview.html (100%) rename {www/api/data/components => components}/previews/meta.json (100%) rename {www/api/data/components => components}/previews/transformers/simplyPreviewActions-extract.js (100%) rename {www/api/data/components => components}/previews/transformers/simplyPreviewActions-render.js (100%) rename {www/api/data/components => components}/previews/transformers/simplyPreviewBodyHtml-extract.js (100%) rename {www/api/data/components => components}/previews/transformers/simplyPreviewBodyHtml-render.js (100%) rename {www/api/data/components => components}/previews/transformers/simplyPreviewCommands-extract.js (100%) rename {www/api/data/components => components}/previews/transformers/simplyPreviewCommands-render.js (100%) rename {www/api/data/components => components}/previews/transformers/simplyPreviewComponent-extract.js (100%) rename {www/api/data/components => components}/previews/transformers/simplyPreviewComponent-render.js (100%) rename {www/api/data/components => components}/previews/transformers/simplyPreviewComponentCss-extract.js (100%) rename {www/api/data/components => components}/previews/transformers/simplyPreviewComponentCss-render.js (100%) rename {www/api/data/components => components}/previews/transformers/simplyPreviewComponentTemplates-extract.js (100%) rename {www/api/data/components => components}/previews/transformers/simplyPreviewComponentTemplates-render.js (100%) rename {www/api/data/components => components}/previews/transformers/simplyPreviewDataApi-extract.js (100%) rename {www/api/data/components => components}/previews/transformers/simplyPreviewDataApi-render.js (100%) rename {www/api/data/components => components}/previews/transformers/simplyPreviewDataSources-extract.js (100%) rename {www/api/data/components => components}/previews/transformers/simplyPreviewDataSources-render.js (100%) rename {www/api/data/components => components}/previews/transformers/simplyPreviewFootHtml-extract.js (100%) rename {www/api/data/components => components}/previews/transformers/simplyPreviewFootHtml-render.js (100%) rename {www/api/data/components => components}/previews/transformers/simplyPreviewFullApp-extract.js (100%) rename {www/api/data/components => components}/previews/transformers/simplyPreviewFullApp-render.js (100%) rename {www/api/data/components => components}/previews/transformers/simplyPreviewHeadHtml-extract.js (100%) rename {www/api/data/components => components}/previews/transformers/simplyPreviewHeadHtml-render.js (100%) rename {www/api/data/components => components}/previews/transformers/simplyPreviewPage-extract.js (100%) rename {www/api/data/components => components}/previews/transformers/simplyPreviewPage-render.js (100%) rename {www/api/data/components => components}/previews/transformers/simplyPreviewPageCss-extract.js (100%) rename {www/api/data/components => components}/previews/transformers/simplyPreviewPageCss-render.js (100%) rename {www/api/data/components => components}/previews/transformers/simplyPreviewPageTemplates-extract.js (100%) rename {www/api/data/components => components}/previews/transformers/simplyPreviewPageTemplates-render.js (100%) rename {www/api/data/components => components}/previews/transformers/simplyPreviewRawApi-extract.js (100%) rename {www/api/data/components => components}/previews/transformers/simplyPreviewRawApi-render.js (100%) rename {www/api/data/components => components}/previews/transformers/simplyPreviewRoutes-extract.js (100%) rename {www/api/data/components => components}/previews/transformers/simplyPreviewRoutes-render.js (100%) rename {www/api/data/components => components}/previews/transformers/simplyPreviewSorters-extract.js (100%) rename {www/api/data/components => components}/previews/transformers/simplyPreviewSorters-render.js (100%) rename {www/api/data/components => components}/previews/transformers/simplyPreviewTransformers-extract.js (100%) rename {www/api/data/components => components}/previews/transformers/simplyPreviewTransformers-render.js (100%) rename {www/api/data/components => components}/simply-logo/componentCss/simply-logo.css (100%) rename {www/api/data/components => components}/simply-logo/componentTemplates/logo.html (100%) rename {www/api/data/components => components}/simply-logo/meta.json (100%) rename {www/api/data/components => components}/simply-toolbar/commands/preview.js (100%) rename {www/api/data/components => components}/simply-toolbar/componentCss/simply-toobar-button.css (100%) rename {www/api/data/components => components}/simply-toolbar/componentCss/simply-toolbar.css (100%) rename {www/api/data/components => components}/simply-toolbar/componentTemplates/simply-toolbar-base-component.html (100%) rename {www/api/data/components => components}/simply-toolbar/componentTemplates/simply-toolbar-component.html (100%) rename {www/api/data/components => components}/simply-toolbar/componentTemplates/simply-toolbar-default.html (100%) rename {www/api/data/components => components}/simply-toolbar/componentTemplates/simply-toolbar-page-frame.html (100%) rename {www/api/data/components => components}/simply-toolbar/componentTemplates/simply-toolbar-page.html (100%) rename {www/api/data/components => components}/simply-toolbar/componentTemplates/simply-toolbar-publish.html (100%) rename {www/api/data/components => components}/simply-toolbar/componentTemplates/simply-toolbar.html (100%) rename {www/api/data/components => components}/simply-toolbar/meta.json (100%) delete mode 100644 docker-compose.yml rename www/api/data/generated.html => generated.html (100%) delete mode 100644 lib/config.php delete mode 100755 lib/filesystem.php delete mode 100755 lib/http.php delete mode 100644 lib/router.php delete mode 100755 npm_post_install.sh delete mode 100644 package-lock.json delete mode 100644 package.json rename {www/api/data/page-frame => page-frame}/componentPreview.html (100%) rename {www/api/data/page-frame => page-frame}/fullApp.html (100%) rename {www/api/data/page-frame => page-frame}/pagePreview.html (100%) rename {www/api/data/pages => pages}/base-component/actions/deleteBaseComponent.js (100%) rename {www/api/data/pages => pages}/base-component/actions/getBaseComponent.js (100%) rename {www/api/data/pages => pages}/base-component/actions/saveBaseComponent.js (100%) rename {www/api/data/pages => pages}/base-component/commands/deleteBaseComponent.js (100%) rename {www/api/data/pages => pages}/base-component/commands/saveBaseComponent.js (100%) rename {www/api/data/pages => pages}/base-component/dataApi/deleteBaseComponent.js (100%) rename {www/api/data/pages => pages}/base-component/dataApi/deleteBaseComponentPart.js (100%) rename {www/api/data/pages => pages}/base-component/dataApi/getBaseComponent.js (100%) rename {www/api/data/pages => pages}/base-component/dataApi/saveBaseComponentPart.js (100%) rename {www/api/data/pages => pages}/base-component/meta.json (100%) rename {www/api/data/pages => pages}/base-component/pageTemplates/Edit base component.html (100%) rename {www/api/data/pages => pages}/base-component/routes/base-component.js (100%) rename {www/api/data/pages => pages}/base-component/routes/base-component.json (100%) rename {www/api/data/pages => pages}/base-components/actions/listBaseComponents.js (100%) rename {www/api/data/pages => pages}/base-components/commands/createBaseComponent.js (100%) rename {www/api/data/pages => pages}/base-components/dataApi/listBaseComponents.js (100%) rename {www/api/data/pages => pages}/base-components/meta.json (100%) rename {www/api/data/pages => pages}/base-components/pageTemplates/Base components.html (100%) rename {www/api/data/pages => pages}/base-components/routes/base-components.js (100%) rename {www/api/data/pages => pages}/base-components/routes/base-components.json (100%) rename {www/api/data/pages => pages}/base-components/transformers/baseComponentLink-extract.js (100%) rename {www/api/data/pages => pages}/base-components/transformers/baseComponentLink-render.js (100%) rename {www/api/data/pages => pages}/component-list/actions/listComponents.js (100%) rename {www/api/data/pages => pages}/component-list/commands/createComponent.js (100%) rename {www/api/data/pages => pages}/component-list/dataApi/listComponents.js (100%) rename {www/api/data/pages => pages}/component-list/meta.json (100%) rename {www/api/data/pages => pages}/component-list/pageTemplates/List components.html (100%) rename {www/api/data/pages => pages}/component-list/pageTemplates/List components.json (100%) rename {www/api/data/pages => pages}/component-list/routes/component-list.js (100%) rename {www/api/data/pages => pages}/component-list/routes/component-list.json (100%) rename {www/api/data/pages => pages}/component-list/transformers/componentLink-extract.js (100%) rename {www/api/data/pages => pages}/component-list/transformers/componentLink-render.js (100%) rename {www/api/data/pages => pages}/component/actions/deleteComponent.js (100%) rename {www/api/data/pages => pages}/component/actions/getComponent.js (100%) rename {www/api/data/pages => pages}/component/actions/saveComponent.js (100%) rename {www/api/data/pages => pages}/component/commands/deleteComponent.js (100%) rename {www/api/data/pages => pages}/component/commands/saveComponent.js (100%) rename {www/api/data/pages => pages}/component/dataApi/deleteComponent.js (100%) rename {www/api/data/pages => pages}/component/dataApi/deleteComponentPart.js (100%) rename {www/api/data/pages => pages}/component/dataApi/getComponent.js (100%) rename {www/api/data/pages => pages}/component/dataApi/saveComponentPart.js (100%) rename {www/api/data/pages => pages}/component/meta.json (100%) rename {www/api/data/pages => pages}/component/pageTemplates/Edit component.html (100%) rename {www/api/data/pages => pages}/component/routes/component.js (100%) rename {www/api/data/pages => pages}/component/routes/component.json (100%) rename {www/api/data/pages => pages}/page-frame/actions/getPageFrame.js (100%) rename {www/api/data/pages => pages}/page-frame/actions/savePageFrame.js (100%) rename {www/api/data/pages => pages}/page-frame/commands/savePageFrame.js (100%) rename {www/api/data/pages => pages}/page-frame/dataApi/deletePageFramePart.js (100%) rename {www/api/data/pages => pages}/page-frame/dataApi/getPageFrame.js (100%) rename {www/api/data/pages => pages}/page-frame/dataApi/savePageFramePart.js (100%) rename {www/api/data/pages => pages}/page-frame/meta.json (100%) rename {www/api/data/pages => pages}/page-frame/pageTemplates/Edit page frame.html (100%) rename {www/api/data/pages => pages}/page-frame/routes/page-frame.js (100%) rename {www/api/data/pages => pages}/page-frame/routes/page-frame.json (100%) rename {www/api/data/pages => pages}/page/actions/deletePage.js (100%) rename {www/api/data/pages => pages}/page/actions/getPage.js (100%) rename {www/api/data/pages => pages}/page/actions/savePage.js (100%) rename {www/api/data/pages => pages}/page/commands/deletePage.js (100%) rename {www/api/data/pages => pages}/page/commands/savePage.js (100%) rename {www/api/data/pages => pages}/page/dataApi/deletePage.js (100%) rename {www/api/data/pages => pages}/page/dataApi/deletePagePart.js (100%) rename {www/api/data/pages => pages}/page/dataApi/getPage.js (100%) rename {www/api/data/pages => pages}/page/dataApi/savePagePart.js (100%) rename {www/api/data/pages => pages}/page/meta.json (100%) rename {www/api/data/pages => pages}/page/pageTemplates/Edit page.html (100%) rename {www/api/data/pages => pages}/page/routes/page.js (100%) rename {www/api/data/pages => pages}/page/routes/page.json (100%) rename {www/api/data/pages => pages}/pages/actions/listPages.js (100%) rename {www/api/data/pages => pages}/pages/commands/createPage.js (100%) rename {www/api/data/pages => pages}/pages/dataApi/listPages.js (100%) rename {www/api/data/pages => pages}/pages/meta.json (100%) rename {www/api/data/pages => pages}/pages/pageTemplates/Pages.html (100%) rename {www/api/data/pages => pages}/pages/routes/pages.js (100%) rename {www/api/data/pages => pages}/pages/routes/pages.json (100%) rename {www/api/data/pages => pages}/pages/transformers/pageLink-extract.js (100%) rename {www/api/data/pages => pages}/pages/transformers/pageLink-render.js (100%) rename {www/api/data/pages => pages}/preview/meta.json (100%) rename {www/api/data/pages => pages}/preview/pageCss/simplycode-fullscreen-preview.css (100%) rename {www/api/data/pages => pages}/preview/pageTemplates/preview-app.html (100%) rename {www/api/data/pages => pages}/preview/pageTemplates/preview-component.html (100%) rename {www/api/data/pages => pages}/preview/routes/preview-app.js (100%) rename {www/api/data/pages => pages}/preview/routes/preview-app.json (100%) rename {www/api/data/pages => pages}/preview/routes/preview-component.js (100%) rename {www/api/data/pages => pages}/preview/routes/preview-component.json (100%) rename {www/api/data/pages => pages}/preview/routes/preview-page.js (100%) rename {www/api/data/pages => pages}/preview/routes/preview-page.json (100%) rename {www/api/data/pages => pages}/publish/actions/getAppData.js (100%) rename {www/api/data/pages => pages}/publish/actions/getBaseComponents.js (100%) rename {www/api/data/pages => pages}/publish/actions/getComponents.js (100%) rename {www/api/data/pages => pages}/publish/actions/getPages.js (100%) rename {www/api/data/pages => pages}/publish/actions/getRouteWeight.js (100%) rename {www/api/data/pages => pages}/publish/actions/saveAppHtml.js (100%) rename {www/api/data/pages => pages}/publish/actions/tests/getRouteWeight/Fixed path 3 items.js (100%) rename {www/api/data/pages => pages}/publish/commands/saveAppHtml.js (100%) rename {www/api/data/pages => pages}/publish/dataApi/saveAppHtml.js (100%) rename {www/api/data/pages => pages}/publish/meta.json (100%) rename {www/api/data/pages => pages}/publish/pageTemplates/Publish App.html (100%) rename {www/api/data/pages => pages}/publish/routes/publish.js (100%) rename {www/api/data/pages => pages}/publish/routes/publish.json (100%) rename {www/api/data/pages => pages}/publish/transformers/htmlEscape-extract.js (100%) rename {www/api/data/pages => pages}/publish/transformers/htmlEscape-render.js (100%) rename {www/api/data/pages => pages}/publish/transformers/indentCode-extract.js (100%) rename {www/api/data/pages => pages}/publish/transformers/indentCode-render.js (100%) delete mode 100644 www/.gitignore delete mode 100644 www/.htaccess delete mode 100644 www/api/.htaccess delete mode 100755 www/api/data/simplycode.sh delete mode 100755 www/api/index.php delete mode 100644 www/camil_192x192.png delete mode 100644 www/camil_512x512.png delete mode 100644 www/data/data.json delete mode 100644 www/data/settings.json delete mode 100644 www/files/feather-sprite.svg delete mode 120000 www/generated.html delete mode 100644 www/hope/hope.annotation.js delete mode 100644 www/hope/hope.editor.events.js delete mode 100644 www/hope/hope.editor.js delete mode 100644 www/hope/hope.editor.selection.js delete mode 100644 www/hope/hope.events.js delete mode 100644 www/hope/hope.fragment.annotations.js delete mode 100644 www/hope/hope.fragment.js delete mode 100644 www/hope/hope.fragment.text.js delete mode 100644 www/hope/hope.js delete mode 100644 www/hope/hope.keyboard.js delete mode 100644 www/hope/hope.mime.js delete mode 100644 www/hope/hope.packed.js delete mode 100644 www/hope/hope.polyfills.js delete mode 100644 www/hope/hope.range.js delete mode 100644 www/hope/hope.render.html.js delete mode 100644 www/hope/hope.test.js delete mode 100755 www/hope/pack delete mode 100644 www/index.html delete mode 100644 www/js/codemirror/lib/codemirror.css delete mode 100644 www/js/codemirror/lib/codemirror.js delete mode 100644 www/js/codemirror/mode/css/css.js delete mode 100644 www/js/codemirror/mode/htmlmixed/htmlmixed.js delete mode 100644 www/js/codemirror/mode/javascript/javascript.js delete mode 100644 www/js/codemirror/mode/xml/xml.js delete mode 100644 www/js/codemirror/theme/base16-dark.css delete mode 100755 www/js/simply-edit.js delete mode 100644 www/js/simply.everything.js delete mode 100644 www/js/simply.include.next.js delete mode 100644 www/simply-edit/bg1.jpg delete mode 100644 www/simply-edit/bg2.jpg delete mode 100755 www/simply-edit/checks.php delete mode 100644 www/simply-edit/config.php delete mode 100644 www/simply-edit/filesystem.php delete mode 100644 www/simply-edit/htpasswd.php delete mode 100755 www/simply-edit/http.php delete mode 100644 www/simply-edit/index.php delete mode 100644 www/simply-edit/login.php delete mode 100644 www/simply-edit/logout.php delete mode 100644 www/simply-edit/mu.js delete mode 100644 www/simply-edit/mu.min.js delete mode 100644 www/simply-edit/prerender.php delete mode 100755 www/simply-edit/router.php delete mode 100644 www/simply-edit/sha1.js delete mode 100644 www/simply-edit/simply-edit-centered.svg delete mode 100755 www/simply-edit/store.php delete mode 100644 www/simply-edit/style.css delete mode 100644 www/simply/css/editor.v9.css delete mode 100644 www/simply/databind.js delete mode 100644 www/simply/diff_match_patch.js delete mode 100755 www/simply/pack delete mode 100755 www/simply/plugin.simply-about.html delete mode 100644 www/simply/plugin.simply-baseurl.html delete mode 100644 www/simply/plugin.simply-browse.html delete mode 100644 www/simply/plugin.simply-diff.html delete mode 100644 www/simply/plugin.simply-dropbox.html delete mode 100644 www/simply/plugin.simply-htmlsource.html delete mode 100644 www/simply/plugin.simply-keyboard.html delete mode 100644 www/simply/plugin.simply-login.html delete mode 100644 www/simply/plugin.simply-meta.html delete mode 100644 www/simply/plugin.simply-paste.html delete mode 100644 www/simply/plugin.simply-plain.html delete mode 100644 www/simply/plugin.simply-save.html delete mode 100644 www/simply/plugin.simply-scaler.html delete mode 100644 www/simply/plugin.simply-symbol.html delete mode 100644 www/simply/plugin.simply-template.html delete mode 100644 www/simply/plugin.simply-undo-redo.html delete mode 100644 www/simply/plugin.toolbar-scroll.html delete mode 100644 www/simply/scripts.js delete mode 100644 www/simply/simply.elementBinding.js delete mode 100644 www/simply/simply.tripleBinding.js delete mode 100644 www/simply/slip.js delete mode 100644 www/simply/toolbar.simply-basepack.html delete mode 100644 www/simply/toolbar.simply-icon.html delete mode 100644 www/simply/toolbar.simply-iframe.html delete mode 100644 www/simply/toolbar.simply-image.html delete mode 100755 www/simply/toolbar.simply-list.html delete mode 100755 www/simply/toolbar.simply-main-toolbar.html delete mode 100644 www/simply/toolbar.simply-selectable.html delete mode 100644 www/simply/toolbar.simply-text.html delete mode 100755 www/simply/toolbars.js diff --git a/000-default.conf b/000-default.conf deleted file mode 100644 index 7ec48bc..0000000 --- a/000-default.conf +++ /dev/null @@ -1,32 +0,0 @@ - - Options Indexes FollowSymLinks - AllowOverride All - Require all granted - - - - ServerAdmin webmaster@localhost - DocumentRoot /opt/simplycode/www - ErrorLog ${APACHE_LOG_DIR}/error.log - CustomLog ${APACHE_LOG_DIR}/access.log combined - - - - - ServerAdmin webmaster@localhost - DocumentRoot /opt/simplycode/www - ErrorLog ${APACHE_LOG_DIR}/error.log - CustomLog ${APACHE_LOG_DIR}/access.log combined - - SSLEngine on - SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem - SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key - - - SSLOptions +StdEnvVars - - - SSLOptions +StdEnvVars - - - diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index d46005b..0000000 --- a/Dockerfile +++ /dev/null @@ -1,17 +0,0 @@ -FROM php:7.4-apache -RUN apt-get update && \ - apt-get install -y \ - git ssl-cert - -WORKDIR /opt/simplycode/ -COPY . /opt/simplycode/ -COPY 000-default.conf /etc/apache2/sites-available/000-default.conf - -RUN htpasswd -cb /opt/simplycode/www/data/.htpasswd demo demo -RUN a2enmod rewrite ssl headers -RUN chown -R www-data:www-data /opt/simplycode/www/data -RUN chown -R www-data:www-data /opt/simplycode/www/api/data - -EXPOSE 80 -EXPOSE 443 -CMD ["apache2-foreground"] \ No newline at end of file diff --git a/LICENSE b/LICENSE index 36b45e5..8a24809 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2022 SimplyEdit +Copyright (c) 2022-2025 SimplyEdit Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index c61a90f..16202f1 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,6 @@ This project allows coding in a structured environment to create apps following the Simply App Architecture. -## Installation -The codebase runs on Apache+PHP - # Sample application As a sample application, we've built SimplyCode in SimplyCode. The code for is bundled with this project. You can browse the code in the /www/api/data/ directory of this project, or from SimplyCode once you have the environment setup. SimplyCode can of course be used to build other applications as well. diff --git a/www/api/data/assets/fonts/CoconRegularFont.woff b/assets/fonts/CoconRegularFont.woff similarity index 100% rename from www/api/data/assets/fonts/CoconRegularFont.woff rename to assets/fonts/CoconRegularFont.woff diff --git a/www/api/data/assets/img/feather-sprite.svg b/assets/img/feather-sprite.svg similarity index 100% rename from www/api/data/assets/img/feather-sprite.svg rename to assets/img/feather-sprite.svg diff --git a/www/api/data/base-components/automatic-preview/actions/getComponentNameField.js b/base-components/automatic-preview/actions/getComponentNameField.js similarity index 100% rename from www/api/data/base-components/automatic-preview/actions/getComponentNameField.js rename to base-components/automatic-preview/actions/getComponentNameField.js diff --git a/www/api/data/base-components/automatic-preview/commands/autoRunPreviews.js b/base-components/automatic-preview/commands/autoRunPreviews.js similarity index 100% rename from www/api/data/base-components/automatic-preview/commands/autoRunPreviews.js rename to base-components/automatic-preview/commands/autoRunPreviews.js diff --git a/www/api/data/base-components/automatic-preview/commands/resetPreview.js b/base-components/automatic-preview/commands/resetPreview.js similarity index 100% rename from www/api/data/base-components/automatic-preview/commands/resetPreview.js rename to base-components/automatic-preview/commands/resetPreview.js diff --git a/www/api/data/base-components/automatic-preview/footHtml/Auto run preview.html b/base-components/automatic-preview/footHtml/Auto run preview.html similarity index 100% rename from www/api/data/base-components/automatic-preview/footHtml/Auto run preview.html rename to base-components/automatic-preview/footHtml/Auto run preview.html diff --git a/www/api/data/base-components/automatic-preview/meta.json b/base-components/automatic-preview/meta.json similarity index 100% rename from www/api/data/base-components/automatic-preview/meta.json rename to base-components/automatic-preview/meta.json diff --git a/www/api/data/base-components/automatic-tests/commands/autoRunTests.js b/base-components/automatic-tests/commands/autoRunTests.js similarity index 100% rename from www/api/data/base-components/automatic-tests/commands/autoRunTests.js rename to base-components/automatic-tests/commands/autoRunTests.js diff --git a/www/api/data/base-components/automatic-tests/footHtml/Auto run tests.html b/base-components/automatic-tests/footHtml/Auto run tests.html similarity index 100% rename from www/api/data/base-components/automatic-tests/footHtml/Auto run tests.html rename to base-components/automatic-tests/footHtml/Auto run tests.html diff --git a/www/api/data/base-components/automatic-tests/meta.json b/base-components/automatic-tests/meta.json similarity index 100% rename from www/api/data/base-components/automatic-tests/meta.json rename to base-components/automatic-tests/meta.json diff --git a/www/api/data/base-components/codemirror/commands/codeMirrorInit.js b/base-components/codemirror/commands/codeMirrorInit.js similarity index 100% rename from www/api/data/base-components/codemirror/commands/codeMirrorInit.js rename to base-components/codemirror/commands/codeMirrorInit.js diff --git a/www/api/data/base-components/codemirror/footHtml/Codemirror base.html b/base-components/codemirror/footHtml/Codemirror base.html similarity index 100% rename from www/api/data/base-components/codemirror/footHtml/Codemirror base.html rename to base-components/codemirror/footHtml/Codemirror base.html diff --git a/www/api/data/base-components/codemirror/footHtml/Codemirror modes.html b/base-components/codemirror/footHtml/Codemirror modes.html similarity index 100% rename from www/api/data/base-components/codemirror/footHtml/Codemirror modes.html rename to base-components/codemirror/footHtml/Codemirror modes.html diff --git a/www/api/data/base-components/codemirror/footHtml/Codemirror styles.html b/base-components/codemirror/footHtml/Codemirror styles.html similarity index 100% rename from www/api/data/base-components/codemirror/footHtml/Codemirror styles.html rename to base-components/codemirror/footHtml/Codemirror styles.html diff --git a/www/api/data/base-components/codemirror/footHtml/Data change codeMirror.html b/base-components/codemirror/footHtml/Data change codeMirror.html similarity index 100% rename from www/api/data/base-components/codemirror/footHtml/Data change codeMirror.html rename to base-components/codemirror/footHtml/Data change codeMirror.html diff --git a/www/api/data/base-components/codemirror/meta.json b/base-components/codemirror/meta.json similarity index 100% rename from www/api/data/base-components/codemirror/meta.json rename to base-components/codemirror/meta.json diff --git a/www/api/data/base-components/dragdrop/footHtml b/base-components/dragdrop/footHtml similarity index 100% rename from www/api/data/base-components/dragdrop/footHtml rename to base-components/dragdrop/footHtml diff --git a/www/api/data/base-components/dragdrop/meta.json b/base-components/dragdrop/meta.json similarity index 100% rename from www/api/data/base-components/dragdrop/meta.json rename to base-components/dragdrop/meta.json diff --git a/www/api/data/base-components/font-cocon/headHtml/cocon.html b/base-components/font-cocon/headHtml/cocon.html similarity index 100% rename from www/api/data/base-components/font-cocon/headHtml/cocon.html rename to base-components/font-cocon/headHtml/cocon.html diff --git a/www/api/data/base-components/font-cocon/meta.json b/base-components/font-cocon/meta.json similarity index 100% rename from www/api/data/base-components/font-cocon/meta.json rename to base-components/font-cocon/meta.json diff --git a/www/api/data/base-components/home/meta.json b/base-components/home/meta.json similarity index 100% rename from www/api/data/base-components/home/meta.json rename to base-components/home/meta.json diff --git a/www/api/data/base-components/home/routes/home.js b/base-components/home/routes/home.js similarity index 100% rename from www/api/data/base-components/home/routes/home.js rename to base-components/home/routes/home.js diff --git a/www/api/data/base-components/home/routes/home.json b/base-components/home/routes/home.json similarity index 100% rename from www/api/data/base-components/home/routes/home.json rename to base-components/home/routes/home.json diff --git a/www/api/data/base-components/list-counters/footHtml/component-parts-count.html b/base-components/list-counters/footHtml/component-parts-count.html similarity index 100% rename from www/api/data/base-components/list-counters/footHtml/component-parts-count.html rename to base-components/list-counters/footHtml/component-parts-count.html diff --git a/www/api/data/base-components/list-counters/meta.json b/base-components/list-counters/meta.json similarity index 100% rename from www/api/data/base-components/list-counters/meta.json rename to base-components/list-counters/meta.json diff --git a/www/api/data/base-components/main-menu/bodyHtml/Load main menu.html b/base-components/main-menu/bodyHtml/Load main menu.html similarity index 100% rename from www/api/data/base-components/main-menu/bodyHtml/Load main menu.html rename to base-components/main-menu/bodyHtml/Load main menu.html diff --git a/www/api/data/base-components/main-menu/meta.json b/base-components/main-menu/meta.json similarity index 100% rename from www/api/data/base-components/main-menu/meta.json rename to base-components/main-menu/meta.json diff --git a/www/api/data/base-components/raw-api/meta.json b/base-components/raw-api/meta.json similarity index 100% rename from www/api/data/base-components/raw-api/meta.json rename to base-components/raw-api/meta.json diff --git a/www/api/data/base-components/raw-api/rawApi/delete.js b/base-components/raw-api/rawApi/delete.js similarity index 100% rename from www/api/data/base-components/raw-api/rawApi/delete.js rename to base-components/raw-api/rawApi/delete.js diff --git a/www/api/data/base-components/raw-api/rawApi/encodeGetParams.js b/base-components/raw-api/rawApi/encodeGetParams.js similarity index 100% rename from www/api/data/base-components/raw-api/rawApi/encodeGetParams.js rename to base-components/raw-api/rawApi/encodeGetParams.js diff --git a/www/api/data/base-components/raw-api/rawApi/get.js b/base-components/raw-api/rawApi/get.js similarity index 100% rename from www/api/data/base-components/raw-api/rawApi/get.js rename to base-components/raw-api/rawApi/get.js diff --git a/www/api/data/base-components/raw-api/rawApi/headers.js b/base-components/raw-api/rawApi/headers.js similarity index 100% rename from www/api/data/base-components/raw-api/rawApi/headers.js rename to base-components/raw-api/rawApi/headers.js diff --git a/www/api/data/base-components/raw-api/rawApi/post.js b/base-components/raw-api/rawApi/post.js similarity index 100% rename from www/api/data/base-components/raw-api/rawApi/post.js rename to base-components/raw-api/rawApi/post.js diff --git a/www/api/data/base-components/raw-api/rawApi/postRaw.js b/base-components/raw-api/rawApi/postRaw.js similarity index 100% rename from www/api/data/base-components/raw-api/rawApi/postRaw.js rename to base-components/raw-api/rawApi/postRaw.js diff --git a/www/api/data/base-components/raw-api/rawApi/put.js b/base-components/raw-api/rawApi/put.js similarity index 100% rename from www/api/data/base-components/raw-api/rawApi/put.js rename to base-components/raw-api/rawApi/put.js diff --git a/www/api/data/base-components/raw-api/rawApi/putRaw.js b/base-components/raw-api/rawApi/putRaw.js similarity index 100% rename from www/api/data/base-components/raw-api/rawApi/putRaw.js rename to base-components/raw-api/rawApi/putRaw.js diff --git a/www/api/data/base-components/raw-api/rawApi/url.js b/base-components/raw-api/rawApi/url.js similarity index 100% rename from www/api/data/base-components/raw-api/rawApi/url.js rename to base-components/raw-api/rawApi/url.js diff --git a/www/api/data/base-components/toasts/bodyHtml/HTML structure.html b/base-components/toasts/bodyHtml/HTML structure.html similarity index 100% rename from www/api/data/base-components/toasts/bodyHtml/HTML structure.html rename to base-components/toasts/bodyHtml/HTML structure.html diff --git a/www/api/data/base-components/toasts/bodyHtml/Toast styles.html b/base-components/toasts/bodyHtml/Toast styles.html similarity index 100% rename from www/api/data/base-components/toasts/bodyHtml/Toast styles.html rename to base-components/toasts/bodyHtml/Toast styles.html diff --git a/www/api/data/base-components/toasts/footHtml/toastAnimation.html b/base-components/toasts/footHtml/toastAnimation.html similarity index 100% rename from www/api/data/base-components/toasts/footHtml/toastAnimation.html rename to base-components/toasts/footHtml/toastAnimation.html diff --git a/www/api/data/base-components/toasts/meta.json b/base-components/toasts/meta.json similarity index 100% rename from www/api/data/base-components/toasts/meta.json rename to base-components/toasts/meta.json diff --git a/www/api/data/components/0-ds-styling/componentCss/extra.css b/components/0-ds-styling/componentCss/extra.css similarity index 100% rename from www/api/data/components/0-ds-styling/componentCss/extra.css rename to components/0-ds-styling/componentCss/extra.css diff --git a/www/api/data/components/0-ds-styling/componentCss/style.css b/components/0-ds-styling/componentCss/style.css similarity index 100% rename from www/api/data/components/0-ds-styling/componentCss/style.css rename to components/0-ds-styling/componentCss/style.css diff --git a/www/api/data/components/0-ds-styling/meta.json b/components/0-ds-styling/meta.json similarity index 100% rename from www/api/data/components/0-ds-styling/meta.json rename to components/0-ds-styling/meta.json diff --git a/www/api/data/components/1-styling/componentCss/extra.css b/components/1-styling/componentCss/extra.css similarity index 100% rename from www/api/data/components/1-styling/componentCss/extra.css rename to components/1-styling/componentCss/extra.css diff --git a/www/api/data/components/1-styling/componentCss/simplycode-component-list.css b/components/1-styling/componentCss/simplycode-component-list.css similarity index 100% rename from www/api/data/components/1-styling/componentCss/simplycode-component-list.css rename to components/1-styling/componentCss/simplycode-component-list.css diff --git a/www/api/data/components/1-styling/componentCss/simplycode-ds-mapping.css b/components/1-styling/componentCss/simplycode-ds-mapping.css similarity index 100% rename from www/api/data/components/1-styling/componentCss/simplycode-ds-mapping.css rename to components/1-styling/componentCss/simplycode-ds-mapping.css diff --git a/www/api/data/components/1-styling/componentCss/style.css b/components/1-styling/componentCss/style.css similarity index 100% rename from www/api/data/components/1-styling/componentCss/style.css rename to components/1-styling/componentCss/style.css diff --git a/www/api/data/components/1-styling/meta.json b/components/1-styling/meta.json similarity index 100% rename from www/api/data/components/1-styling/meta.json rename to components/1-styling/meta.json diff --git a/www/api/data/components/component-actions/commands/addAction.js b/components/component-actions/commands/addAction.js similarity index 100% rename from www/api/data/components/component-actions/commands/addAction.js rename to components/component-actions/commands/addAction.js diff --git a/www/api/data/components/component-actions/commands/tests/addAction/Add two actions.js b/components/component-actions/commands/tests/addAction/Add two actions.js similarity index 100% rename from www/api/data/components/component-actions/commands/tests/addAction/Add two actions.js rename to components/component-actions/commands/tests/addAction/Add two actions.js diff --git a/www/api/data/components/component-actions/componentTemplates/componentActions.html b/components/component-actions/componentTemplates/componentActions.html similarity index 100% rename from www/api/data/components/component-actions/componentTemplates/componentActions.html rename to components/component-actions/componentTemplates/componentActions.html diff --git a/www/api/data/components/component-actions/meta.json b/components/component-actions/meta.json similarity index 100% rename from www/api/data/components/component-actions/meta.json rename to components/component-actions/meta.json diff --git a/www/api/data/components/component-body-html/commands/addBodyHtml.js b/components/component-body-html/commands/addBodyHtml.js similarity index 100% rename from www/api/data/components/component-body-html/commands/addBodyHtml.js rename to components/component-body-html/commands/addBodyHtml.js diff --git a/www/api/data/components/component-body-html/componentTemplates/componentBodyHtml.html b/components/component-body-html/componentTemplates/componentBodyHtml.html similarity index 100% rename from www/api/data/components/component-body-html/componentTemplates/componentBodyHtml.html rename to components/component-body-html/componentTemplates/componentBodyHtml.html diff --git a/www/api/data/components/component-body-html/meta.json b/components/component-body-html/meta.json similarity index 100% rename from www/api/data/components/component-body-html/meta.json rename to components/component-body-html/meta.json diff --git a/www/api/data/components/component-commands/commands/addCommand.js b/components/component-commands/commands/addCommand.js similarity index 100% rename from www/api/data/components/component-commands/commands/addCommand.js rename to components/component-commands/commands/addCommand.js diff --git a/www/api/data/components/component-commands/componentTemplates/componentCommands.html b/components/component-commands/componentTemplates/componentCommands.html similarity index 100% rename from www/api/data/components/component-commands/componentTemplates/componentCommands.html rename to components/component-commands/componentTemplates/componentCommands.html diff --git a/www/api/data/components/component-commands/meta.json b/components/component-commands/meta.json similarity index 100% rename from www/api/data/components/component-commands/meta.json rename to components/component-commands/meta.json diff --git a/www/api/data/components/component-component-css/commands/addComponentCss.js b/components/component-component-css/commands/addComponentCss.js similarity index 100% rename from www/api/data/components/component-component-css/commands/addComponentCss.js rename to components/component-component-css/commands/addComponentCss.js diff --git a/www/api/data/components/component-component-css/componentTemplates/componentComponentCss.html b/components/component-component-css/componentTemplates/componentComponentCss.html similarity index 100% rename from www/api/data/components/component-component-css/componentTemplates/componentComponentCss.html rename to components/component-component-css/componentTemplates/componentComponentCss.html diff --git a/www/api/data/components/component-component-css/meta.json b/components/component-component-css/meta.json similarity index 100% rename from www/api/data/components/component-component-css/meta.json rename to components/component-component-css/meta.json diff --git a/www/api/data/components/component-component-html/commands/addComponentTemplate.js b/components/component-component-html/commands/addComponentTemplate.js similarity index 100% rename from www/api/data/components/component-component-html/commands/addComponentTemplate.js rename to components/component-component-html/commands/addComponentTemplate.js diff --git a/www/api/data/components/component-component-html/componentTemplates/componentComponentTemplate.html b/components/component-component-html/componentTemplates/componentComponentTemplate.html similarity index 100% rename from www/api/data/components/component-component-html/componentTemplates/componentComponentTemplate.html rename to components/component-component-html/componentTemplates/componentComponentTemplate.html diff --git a/www/api/data/components/component-component-html/meta.json b/components/component-component-html/meta.json similarity index 100% rename from www/api/data/components/component-component-html/meta.json rename to components/component-component-html/meta.json diff --git a/www/api/data/components/component-data-api/commands/addDataApiMethod.js b/components/component-data-api/commands/addDataApiMethod.js similarity index 100% rename from www/api/data/components/component-data-api/commands/addDataApiMethod.js rename to components/component-data-api/commands/addDataApiMethod.js diff --git a/www/api/data/components/component-data-api/componentTemplates/componentDataApi.html b/components/component-data-api/componentTemplates/componentDataApi.html similarity index 100% rename from www/api/data/components/component-data-api/componentTemplates/componentDataApi.html rename to components/component-data-api/componentTemplates/componentDataApi.html diff --git a/www/api/data/components/component-data-api/meta.json b/components/component-data-api/meta.json similarity index 100% rename from www/api/data/components/component-data-api/meta.json rename to components/component-data-api/meta.json diff --git a/www/api/data/components/component-data-sources/commands/addDataSource.js b/components/component-data-sources/commands/addDataSource.js similarity index 100% rename from www/api/data/components/component-data-sources/commands/addDataSource.js rename to components/component-data-sources/commands/addDataSource.js diff --git a/www/api/data/components/component-data-sources/componentTemplates/componentDataSources.html b/components/component-data-sources/componentTemplates/componentDataSources.html similarity index 100% rename from www/api/data/components/component-data-sources/componentTemplates/componentDataSources.html rename to components/component-data-sources/componentTemplates/componentDataSources.html diff --git a/www/api/data/components/component-data-sources/meta.json b/components/component-data-sources/meta.json similarity index 100% rename from www/api/data/components/component-data-sources/meta.json rename to components/component-data-sources/meta.json diff --git a/www/api/data/components/component-description/componentTemplates/componentDescription.html b/components/component-description/componentTemplates/componentDescription.html similarity index 100% rename from www/api/data/components/component-description/componentTemplates/componentDescription.html rename to components/component-description/componentTemplates/componentDescription.html diff --git a/www/api/data/components/component-description/meta.json b/components/component-description/meta.json similarity index 100% rename from www/api/data/components/component-description/meta.json rename to components/component-description/meta.json diff --git a/www/api/data/components/component-foot-html/commands/addFootHtml.js b/components/component-foot-html/commands/addFootHtml.js similarity index 100% rename from www/api/data/components/component-foot-html/commands/addFootHtml.js rename to components/component-foot-html/commands/addFootHtml.js diff --git a/www/api/data/components/component-foot-html/componentTemplates/componentFootHtml.html b/components/component-foot-html/componentTemplates/componentFootHtml.html similarity index 100% rename from www/api/data/components/component-foot-html/componentTemplates/componentFootHtml.html rename to components/component-foot-html/componentTemplates/componentFootHtml.html diff --git a/www/api/data/components/component-foot-html/meta.json b/components/component-foot-html/meta.json similarity index 100% rename from www/api/data/components/component-foot-html/meta.json rename to components/component-foot-html/meta.json diff --git a/www/api/data/components/component-head-html/commands/addHeadHtml.js b/components/component-head-html/commands/addHeadHtml.js similarity index 100% rename from www/api/data/components/component-head-html/commands/addHeadHtml.js rename to components/component-head-html/commands/addHeadHtml.js diff --git a/www/api/data/components/component-head-html/componentTemplates/componentHeadHtml.html b/components/component-head-html/componentTemplates/componentHeadHtml.html similarity index 100% rename from www/api/data/components/component-head-html/componentTemplates/componentHeadHtml.html rename to components/component-head-html/componentTemplates/componentHeadHtml.html diff --git a/www/api/data/components/component-head-html/meta.json b/components/component-head-html/meta.json similarity index 100% rename from www/api/data/components/component-head-html/meta.json rename to components/component-head-html/meta.json diff --git a/www/api/data/components/component-page-css/commands/addPageCss.js b/components/component-page-css/commands/addPageCss.js similarity index 100% rename from www/api/data/components/component-page-css/commands/addPageCss.js rename to components/component-page-css/commands/addPageCss.js diff --git a/www/api/data/components/component-page-css/componentTemplates/componentPageCss.html b/components/component-page-css/componentTemplates/componentPageCss.html similarity index 100% rename from www/api/data/components/component-page-css/componentTemplates/componentPageCss.html rename to components/component-page-css/componentTemplates/componentPageCss.html diff --git a/www/api/data/components/component-page-css/meta.json b/components/component-page-css/meta.json similarity index 100% rename from www/api/data/components/component-page-css/meta.json rename to components/component-page-css/meta.json diff --git a/www/api/data/components/component-page-frame/componentTemplates/componentPageFrame.html b/components/component-page-frame/componentTemplates/componentPageFrame.html similarity index 100% rename from www/api/data/components/component-page-frame/componentTemplates/componentPageFrame.html rename to components/component-page-frame/componentTemplates/componentPageFrame.html diff --git a/www/api/data/components/component-page-frame/meta.json b/components/component-page-frame/meta.json similarity index 100% rename from www/api/data/components/component-page-frame/meta.json rename to components/component-page-frame/meta.json diff --git a/www/api/data/components/component-page-template/commands/addPageTemplate.js b/components/component-page-template/commands/addPageTemplate.js similarity index 100% rename from www/api/data/components/component-page-template/commands/addPageTemplate.js rename to components/component-page-template/commands/addPageTemplate.js diff --git a/www/api/data/components/component-page-template/componentTemplates/componentPageTemplate.html b/components/component-page-template/componentTemplates/componentPageTemplate.html similarity index 100% rename from www/api/data/components/component-page-template/componentTemplates/componentPageTemplate.html rename to components/component-page-template/componentTemplates/componentPageTemplate.html diff --git a/www/api/data/components/component-page-template/meta.json b/components/component-page-template/meta.json similarity index 100% rename from www/api/data/components/component-page-template/meta.json rename to components/component-page-template/meta.json diff --git a/www/api/data/components/component-qunit-tests/commands/addTest.js b/components/component-qunit-tests/commands/addTest.js similarity index 100% rename from www/api/data/components/component-qunit-tests/commands/addTest.js rename to components/component-qunit-tests/commands/addTest.js diff --git a/www/api/data/components/component-qunit-tests/componentCss/QUnit iframe.css b/components/component-qunit-tests/componentCss/QUnit iframe.css similarity index 100% rename from www/api/data/components/component-qunit-tests/componentCss/QUnit iframe.css rename to components/component-qunit-tests/componentCss/QUnit iframe.css diff --git a/www/api/data/components/component-qunit-tests/componentTemplates/componentQUnitActionRunner.html b/components/component-qunit-tests/componentTemplates/componentQUnitActionRunner.html similarity index 100% rename from www/api/data/components/component-qunit-tests/componentTemplates/componentQUnitActionRunner.html rename to components/component-qunit-tests/componentTemplates/componentQUnitActionRunner.html diff --git a/www/api/data/components/component-qunit-tests/componentTemplates/componentQUnitCommandRunner.html b/components/component-qunit-tests/componentTemplates/componentQUnitCommandRunner.html similarity index 100% rename from www/api/data/components/component-qunit-tests/componentTemplates/componentQUnitCommandRunner.html rename to components/component-qunit-tests/componentTemplates/componentQUnitCommandRunner.html diff --git a/www/api/data/components/component-qunit-tests/componentTemplates/componentQUnitTests.html b/components/component-qunit-tests/componentTemplates/componentQUnitTests.html similarity index 100% rename from www/api/data/components/component-qunit-tests/componentTemplates/componentQUnitTests.html rename to components/component-qunit-tests/componentTemplates/componentQUnitTests.html diff --git a/www/api/data/components/component-qunit-tests/meta.json b/components/component-qunit-tests/meta.json similarity index 100% rename from www/api/data/components/component-qunit-tests/meta.json rename to components/component-qunit-tests/meta.json diff --git a/www/api/data/components/component-raw-api/commands/addRawApiMethod.js b/components/component-raw-api/commands/addRawApiMethod.js similarity index 100% rename from www/api/data/components/component-raw-api/commands/addRawApiMethod.js rename to components/component-raw-api/commands/addRawApiMethod.js diff --git a/www/api/data/components/component-raw-api/componentTemplates/componentRawApi.html b/components/component-raw-api/componentTemplates/componentRawApi.html similarity index 100% rename from www/api/data/components/component-raw-api/componentTemplates/componentRawApi.html rename to components/component-raw-api/componentTemplates/componentRawApi.html diff --git a/www/api/data/components/component-raw-api/meta.json b/components/component-raw-api/meta.json similarity index 100% rename from www/api/data/components/component-raw-api/meta.json rename to components/component-raw-api/meta.json diff --git a/www/api/data/components/component-routes/commands/addRoute.js b/components/component-routes/commands/addRoute.js similarity index 100% rename from www/api/data/components/component-routes/commands/addRoute.js rename to components/component-routes/commands/addRoute.js diff --git a/www/api/data/components/component-routes/componentTemplates/componentRoutes.html b/components/component-routes/componentTemplates/componentRoutes.html similarity index 100% rename from www/api/data/components/component-routes/componentTemplates/componentRoutes.html rename to components/component-routes/componentTemplates/componentRoutes.html diff --git a/www/api/data/components/component-routes/meta.json b/components/component-routes/meta.json similarity index 100% rename from www/api/data/components/component-routes/meta.json rename to components/component-routes/meta.json diff --git a/www/api/data/components/component-sorters/commands/addSorter.js b/components/component-sorters/commands/addSorter.js similarity index 100% rename from www/api/data/components/component-sorters/commands/addSorter.js rename to components/component-sorters/commands/addSorter.js diff --git a/www/api/data/components/component-sorters/componentTemplates/componentSorters.html b/components/component-sorters/componentTemplates/componentSorters.html similarity index 100% rename from www/api/data/components/component-sorters/componentTemplates/componentSorters.html rename to components/component-sorters/componentTemplates/componentSorters.html diff --git a/www/api/data/components/component-sorters/meta.json b/components/component-sorters/meta.json similarity index 100% rename from www/api/data/components/component-sorters/meta.json rename to components/component-sorters/meta.json diff --git a/www/api/data/components/component-transformers/commands/addTransformer.js b/components/component-transformers/commands/addTransformer.js similarity index 100% rename from www/api/data/components/component-transformers/commands/addTransformer.js rename to components/component-transformers/commands/addTransformer.js diff --git a/www/api/data/components/component-transformers/componentTemplates/componentTransformers.html b/components/component-transformers/componentTemplates/componentTransformers.html similarity index 100% rename from www/api/data/components/component-transformers/componentTemplates/componentTransformers.html rename to components/component-transformers/componentTemplates/componentTransformers.html diff --git a/www/api/data/components/component-transformers/meta.json b/components/component-transformers/meta.json similarity index 100% rename from www/api/data/components/component-transformers/meta.json rename to components/component-transformers/meta.json diff --git a/www/api/data/components/components-generic/commands/deleteEntry.js b/components/components-generic/commands/deleteEntry.js similarity index 100% rename from www/api/data/components/components-generic/commands/deleteEntry.js rename to components/components-generic/commands/deleteEntry.js diff --git a/www/api/data/components/components-generic/commands/initEditors.js b/components/components-generic/commands/initEditors.js similarity index 100% rename from www/api/data/components/components-generic/commands/initEditors.js rename to components/components-generic/commands/initEditors.js diff --git a/www/api/data/components/components-generic/componentCss/code-method block.css b/components/components-generic/componentCss/code-method block.css similarity index 100% rename from www/api/data/components/components-generic/componentCss/code-method block.css rename to components/components-generic/componentCss/code-method block.css diff --git a/www/api/data/components/components-generic/componentCss/deleted-parts.css b/components/components-generic/componentCss/deleted-parts.css similarity index 100% rename from www/api/data/components/components-generic/componentCss/deleted-parts.css rename to components/components-generic/componentCss/deleted-parts.css diff --git a/www/api/data/components/components-generic/meta.json b/components/components-generic/meta.json similarity index 100% rename from www/api/data/components/components-generic/meta.json rename to components/components-generic/meta.json diff --git a/www/api/data/components/data-format/dataApi/deletePart.js b/components/data-format/dataApi/deletePart.js similarity index 100% rename from www/api/data/components/data-format/dataApi/deletePart.js rename to components/data-format/dataApi/deletePart.js diff --git a/www/api/data/components/data-format/dataApi/mergeComponent.js b/components/data-format/dataApi/mergeComponent.js similarity index 100% rename from www/api/data/components/data-format/dataApi/mergeComponent.js rename to components/data-format/dataApi/mergeComponent.js diff --git a/www/api/data/components/data-format/dataApi/mergePageFrame.js b/components/data-format/dataApi/mergePageFrame.js similarity index 100% rename from www/api/data/components/data-format/dataApi/mergePageFrame.js rename to components/data-format/dataApi/mergePageFrame.js diff --git a/www/api/data/components/data-format/dataApi/savePart.js b/components/data-format/dataApi/savePart.js similarity index 100% rename from www/api/data/components/data-format/dataApi/savePart.js rename to components/data-format/dataApi/savePart.js diff --git a/www/api/data/components/data-format/meta.json b/components/data-format/meta.json similarity index 100% rename from www/api/data/components/data-format/meta.json rename to components/data-format/meta.json diff --git a/www/api/data/components/dragdrop/componentCss/simply dragdrop.css b/components/dragdrop/componentCss/simply dragdrop.css similarity index 100% rename from www/api/data/components/dragdrop/componentCss/simply dragdrop.css rename to components/dragdrop/componentCss/simply dragdrop.css diff --git a/www/api/data/components/dragdrop/meta.json b/components/dragdrop/meta.json similarity index 100% rename from www/api/data/components/dragdrop/meta.json rename to components/dragdrop/meta.json diff --git a/www/api/data/components/header/componentTemplates/header.html b/components/header/componentTemplates/header.html similarity index 100% rename from www/api/data/components/header/componentTemplates/header.html rename to components/header/componentTemplates/header.html diff --git a/www/api/data/components/header/meta.json b/components/header/meta.json similarity index 100% rename from www/api/data/components/header/meta.json rename to components/header/meta.json diff --git a/www/api/data/components/html-validator/componentCss/HTML validator.css b/components/html-validator/componentCss/HTML validator.css similarity index 100% rename from www/api/data/components/html-validator/componentCss/HTML validator.css rename to components/html-validator/componentCss/HTML validator.css diff --git a/www/api/data/components/html-validator/componentTemplates/componentHtmlValidator.html b/components/html-validator/componentTemplates/componentHtmlValidator.html similarity index 100% rename from www/api/data/components/html-validator/componentTemplates/componentHtmlValidator.html rename to components/html-validator/componentTemplates/componentHtmlValidator.html diff --git a/www/api/data/components/html-validator/meta.json b/components/html-validator/meta.json similarity index 100% rename from www/api/data/components/html-validator/meta.json rename to components/html-validator/meta.json diff --git a/www/api/data/components/html-validator/transformers/validateHtml-extract.js b/components/html-validator/transformers/validateHtml-extract.js similarity index 100% rename from www/api/data/components/html-validator/transformers/validateHtml-extract.js rename to components/html-validator/transformers/validateHtml-extract.js diff --git a/www/api/data/components/html-validator/transformers/validateHtml-render.js b/components/html-validator/transformers/validateHtml-render.js similarity index 100% rename from www/api/data/components/html-validator/transformers/validateHtml-render.js rename to components/html-validator/transformers/validateHtml-render.js diff --git a/www/api/data/components/navigation/actions/browse.js b/components/navigation/actions/browse.js similarity index 100% rename from www/api/data/components/navigation/actions/browse.js rename to components/navigation/actions/browse.js diff --git a/www/api/data/components/navigation/actions/getMainMenu.js b/components/navigation/actions/getMainMenu.js similarity index 100% rename from www/api/data/components/navigation/actions/getMainMenu.js rename to components/navigation/actions/getMainMenu.js diff --git a/www/api/data/components/navigation/commands/collapseMenu.js b/components/navigation/commands/collapseMenu.js similarity index 100% rename from www/api/data/components/navigation/commands/collapseMenu.js rename to components/navigation/commands/collapseMenu.js diff --git a/www/api/data/components/navigation/commands/expandMenu.js b/components/navigation/commands/expandMenu.js similarity index 100% rename from www/api/data/components/navigation/commands/expandMenu.js rename to components/navigation/commands/expandMenu.js diff --git a/www/api/data/components/navigation/commands/navigate.js b/components/navigation/commands/navigate.js similarity index 100% rename from www/api/data/components/navigation/commands/navigate.js rename to components/navigation/commands/navigate.js diff --git a/www/api/data/components/navigation/componentTemplates/menu.html b/components/navigation/componentTemplates/menu.html similarity index 100% rename from www/api/data/components/navigation/componentTemplates/menu.html rename to components/navigation/componentTemplates/menu.html diff --git a/www/api/data/components/navigation/dataApi/browse.js b/components/navigation/dataApi/browse.js similarity index 100% rename from www/api/data/components/navigation/dataApi/browse.js rename to components/navigation/dataApi/browse.js diff --git a/www/api/data/components/navigation/meta.json b/components/navigation/meta.json similarity index 100% rename from www/api/data/components/navigation/meta.json rename to components/navigation/meta.json diff --git a/www/api/data/components/previews/componentCss/App full preview.css b/components/previews/componentCss/App full preview.css similarity index 100% rename from www/api/data/components/previews/componentCss/App full preview.css rename to components/previews/componentCss/App full preview.css diff --git a/www/api/data/components/previews/componentTemplates/componentPreview.html b/components/previews/componentTemplates/componentPreview.html similarity index 100% rename from www/api/data/components/previews/componentTemplates/componentPreview.html rename to components/previews/componentTemplates/componentPreview.html diff --git a/www/api/data/components/previews/componentTemplates/fullAppPreview.html b/components/previews/componentTemplates/fullAppPreview.html similarity index 100% rename from www/api/data/components/previews/componentTemplates/fullAppPreview.html rename to components/previews/componentTemplates/fullAppPreview.html diff --git a/www/api/data/components/previews/componentTemplates/pagePreview.html b/components/previews/componentTemplates/pagePreview.html similarity index 100% rename from www/api/data/components/previews/componentTemplates/pagePreview.html rename to components/previews/componentTemplates/pagePreview.html diff --git a/www/api/data/components/previews/meta.json b/components/previews/meta.json similarity index 100% rename from www/api/data/components/previews/meta.json rename to components/previews/meta.json diff --git a/www/api/data/components/previews/transformers/simplyPreviewActions-extract.js b/components/previews/transformers/simplyPreviewActions-extract.js similarity index 100% rename from www/api/data/components/previews/transformers/simplyPreviewActions-extract.js rename to components/previews/transformers/simplyPreviewActions-extract.js diff --git a/www/api/data/components/previews/transformers/simplyPreviewActions-render.js b/components/previews/transformers/simplyPreviewActions-render.js similarity index 100% rename from www/api/data/components/previews/transformers/simplyPreviewActions-render.js rename to components/previews/transformers/simplyPreviewActions-render.js diff --git a/www/api/data/components/previews/transformers/simplyPreviewBodyHtml-extract.js b/components/previews/transformers/simplyPreviewBodyHtml-extract.js similarity index 100% rename from www/api/data/components/previews/transformers/simplyPreviewBodyHtml-extract.js rename to components/previews/transformers/simplyPreviewBodyHtml-extract.js diff --git a/www/api/data/components/previews/transformers/simplyPreviewBodyHtml-render.js b/components/previews/transformers/simplyPreviewBodyHtml-render.js similarity index 100% rename from www/api/data/components/previews/transformers/simplyPreviewBodyHtml-render.js rename to components/previews/transformers/simplyPreviewBodyHtml-render.js diff --git a/www/api/data/components/previews/transformers/simplyPreviewCommands-extract.js b/components/previews/transformers/simplyPreviewCommands-extract.js similarity index 100% rename from www/api/data/components/previews/transformers/simplyPreviewCommands-extract.js rename to components/previews/transformers/simplyPreviewCommands-extract.js diff --git a/www/api/data/components/previews/transformers/simplyPreviewCommands-render.js b/components/previews/transformers/simplyPreviewCommands-render.js similarity index 100% rename from www/api/data/components/previews/transformers/simplyPreviewCommands-render.js rename to components/previews/transformers/simplyPreviewCommands-render.js diff --git a/www/api/data/components/previews/transformers/simplyPreviewComponent-extract.js b/components/previews/transformers/simplyPreviewComponent-extract.js similarity index 100% rename from www/api/data/components/previews/transformers/simplyPreviewComponent-extract.js rename to components/previews/transformers/simplyPreviewComponent-extract.js diff --git a/www/api/data/components/previews/transformers/simplyPreviewComponent-render.js b/components/previews/transformers/simplyPreviewComponent-render.js similarity index 100% rename from www/api/data/components/previews/transformers/simplyPreviewComponent-render.js rename to components/previews/transformers/simplyPreviewComponent-render.js diff --git a/www/api/data/components/previews/transformers/simplyPreviewComponentCss-extract.js b/components/previews/transformers/simplyPreviewComponentCss-extract.js similarity index 100% rename from www/api/data/components/previews/transformers/simplyPreviewComponentCss-extract.js rename to components/previews/transformers/simplyPreviewComponentCss-extract.js diff --git a/www/api/data/components/previews/transformers/simplyPreviewComponentCss-render.js b/components/previews/transformers/simplyPreviewComponentCss-render.js similarity index 100% rename from www/api/data/components/previews/transformers/simplyPreviewComponentCss-render.js rename to components/previews/transformers/simplyPreviewComponentCss-render.js diff --git a/www/api/data/components/previews/transformers/simplyPreviewComponentTemplates-extract.js b/components/previews/transformers/simplyPreviewComponentTemplates-extract.js similarity index 100% rename from www/api/data/components/previews/transformers/simplyPreviewComponentTemplates-extract.js rename to components/previews/transformers/simplyPreviewComponentTemplates-extract.js diff --git a/www/api/data/components/previews/transformers/simplyPreviewComponentTemplates-render.js b/components/previews/transformers/simplyPreviewComponentTemplates-render.js similarity index 100% rename from www/api/data/components/previews/transformers/simplyPreviewComponentTemplates-render.js rename to components/previews/transformers/simplyPreviewComponentTemplates-render.js diff --git a/www/api/data/components/previews/transformers/simplyPreviewDataApi-extract.js b/components/previews/transformers/simplyPreviewDataApi-extract.js similarity index 100% rename from www/api/data/components/previews/transformers/simplyPreviewDataApi-extract.js rename to components/previews/transformers/simplyPreviewDataApi-extract.js diff --git a/www/api/data/components/previews/transformers/simplyPreviewDataApi-render.js b/components/previews/transformers/simplyPreviewDataApi-render.js similarity index 100% rename from www/api/data/components/previews/transformers/simplyPreviewDataApi-render.js rename to components/previews/transformers/simplyPreviewDataApi-render.js diff --git a/www/api/data/components/previews/transformers/simplyPreviewDataSources-extract.js b/components/previews/transformers/simplyPreviewDataSources-extract.js similarity index 100% rename from www/api/data/components/previews/transformers/simplyPreviewDataSources-extract.js rename to components/previews/transformers/simplyPreviewDataSources-extract.js diff --git a/www/api/data/components/previews/transformers/simplyPreviewDataSources-render.js b/components/previews/transformers/simplyPreviewDataSources-render.js similarity index 100% rename from www/api/data/components/previews/transformers/simplyPreviewDataSources-render.js rename to components/previews/transformers/simplyPreviewDataSources-render.js diff --git a/www/api/data/components/previews/transformers/simplyPreviewFootHtml-extract.js b/components/previews/transformers/simplyPreviewFootHtml-extract.js similarity index 100% rename from www/api/data/components/previews/transformers/simplyPreviewFootHtml-extract.js rename to components/previews/transformers/simplyPreviewFootHtml-extract.js diff --git a/www/api/data/components/previews/transformers/simplyPreviewFootHtml-render.js b/components/previews/transformers/simplyPreviewFootHtml-render.js similarity index 100% rename from www/api/data/components/previews/transformers/simplyPreviewFootHtml-render.js rename to components/previews/transformers/simplyPreviewFootHtml-render.js diff --git a/www/api/data/components/previews/transformers/simplyPreviewFullApp-extract.js b/components/previews/transformers/simplyPreviewFullApp-extract.js similarity index 100% rename from www/api/data/components/previews/transformers/simplyPreviewFullApp-extract.js rename to components/previews/transformers/simplyPreviewFullApp-extract.js diff --git a/www/api/data/components/previews/transformers/simplyPreviewFullApp-render.js b/components/previews/transformers/simplyPreviewFullApp-render.js similarity index 100% rename from www/api/data/components/previews/transformers/simplyPreviewFullApp-render.js rename to components/previews/transformers/simplyPreviewFullApp-render.js diff --git a/www/api/data/components/previews/transformers/simplyPreviewHeadHtml-extract.js b/components/previews/transformers/simplyPreviewHeadHtml-extract.js similarity index 100% rename from www/api/data/components/previews/transformers/simplyPreviewHeadHtml-extract.js rename to components/previews/transformers/simplyPreviewHeadHtml-extract.js diff --git a/www/api/data/components/previews/transformers/simplyPreviewHeadHtml-render.js b/components/previews/transformers/simplyPreviewHeadHtml-render.js similarity index 100% rename from www/api/data/components/previews/transformers/simplyPreviewHeadHtml-render.js rename to components/previews/transformers/simplyPreviewHeadHtml-render.js diff --git a/www/api/data/components/previews/transformers/simplyPreviewPage-extract.js b/components/previews/transformers/simplyPreviewPage-extract.js similarity index 100% rename from www/api/data/components/previews/transformers/simplyPreviewPage-extract.js rename to components/previews/transformers/simplyPreviewPage-extract.js diff --git a/www/api/data/components/previews/transformers/simplyPreviewPage-render.js b/components/previews/transformers/simplyPreviewPage-render.js similarity index 100% rename from www/api/data/components/previews/transformers/simplyPreviewPage-render.js rename to components/previews/transformers/simplyPreviewPage-render.js diff --git a/www/api/data/components/previews/transformers/simplyPreviewPageCss-extract.js b/components/previews/transformers/simplyPreviewPageCss-extract.js similarity index 100% rename from www/api/data/components/previews/transformers/simplyPreviewPageCss-extract.js rename to components/previews/transformers/simplyPreviewPageCss-extract.js diff --git a/www/api/data/components/previews/transformers/simplyPreviewPageCss-render.js b/components/previews/transformers/simplyPreviewPageCss-render.js similarity index 100% rename from www/api/data/components/previews/transformers/simplyPreviewPageCss-render.js rename to components/previews/transformers/simplyPreviewPageCss-render.js diff --git a/www/api/data/components/previews/transformers/simplyPreviewPageTemplates-extract.js b/components/previews/transformers/simplyPreviewPageTemplates-extract.js similarity index 100% rename from www/api/data/components/previews/transformers/simplyPreviewPageTemplates-extract.js rename to components/previews/transformers/simplyPreviewPageTemplates-extract.js diff --git a/www/api/data/components/previews/transformers/simplyPreviewPageTemplates-render.js b/components/previews/transformers/simplyPreviewPageTemplates-render.js similarity index 100% rename from www/api/data/components/previews/transformers/simplyPreviewPageTemplates-render.js rename to components/previews/transformers/simplyPreviewPageTemplates-render.js diff --git a/www/api/data/components/previews/transformers/simplyPreviewRawApi-extract.js b/components/previews/transformers/simplyPreviewRawApi-extract.js similarity index 100% rename from www/api/data/components/previews/transformers/simplyPreviewRawApi-extract.js rename to components/previews/transformers/simplyPreviewRawApi-extract.js diff --git a/www/api/data/components/previews/transformers/simplyPreviewRawApi-render.js b/components/previews/transformers/simplyPreviewRawApi-render.js similarity index 100% rename from www/api/data/components/previews/transformers/simplyPreviewRawApi-render.js rename to components/previews/transformers/simplyPreviewRawApi-render.js diff --git a/www/api/data/components/previews/transformers/simplyPreviewRoutes-extract.js b/components/previews/transformers/simplyPreviewRoutes-extract.js similarity index 100% rename from www/api/data/components/previews/transformers/simplyPreviewRoutes-extract.js rename to components/previews/transformers/simplyPreviewRoutes-extract.js diff --git a/www/api/data/components/previews/transformers/simplyPreviewRoutes-render.js b/components/previews/transformers/simplyPreviewRoutes-render.js similarity index 100% rename from www/api/data/components/previews/transformers/simplyPreviewRoutes-render.js rename to components/previews/transformers/simplyPreviewRoutes-render.js diff --git a/www/api/data/components/previews/transformers/simplyPreviewSorters-extract.js b/components/previews/transformers/simplyPreviewSorters-extract.js similarity index 100% rename from www/api/data/components/previews/transformers/simplyPreviewSorters-extract.js rename to components/previews/transformers/simplyPreviewSorters-extract.js diff --git a/www/api/data/components/previews/transformers/simplyPreviewSorters-render.js b/components/previews/transformers/simplyPreviewSorters-render.js similarity index 100% rename from www/api/data/components/previews/transformers/simplyPreviewSorters-render.js rename to components/previews/transformers/simplyPreviewSorters-render.js diff --git a/www/api/data/components/previews/transformers/simplyPreviewTransformers-extract.js b/components/previews/transformers/simplyPreviewTransformers-extract.js similarity index 100% rename from www/api/data/components/previews/transformers/simplyPreviewTransformers-extract.js rename to components/previews/transformers/simplyPreviewTransformers-extract.js diff --git a/www/api/data/components/previews/transformers/simplyPreviewTransformers-render.js b/components/previews/transformers/simplyPreviewTransformers-render.js similarity index 100% rename from www/api/data/components/previews/transformers/simplyPreviewTransformers-render.js rename to components/previews/transformers/simplyPreviewTransformers-render.js diff --git a/www/api/data/components/simply-logo/componentCss/simply-logo.css b/components/simply-logo/componentCss/simply-logo.css similarity index 100% rename from www/api/data/components/simply-logo/componentCss/simply-logo.css rename to components/simply-logo/componentCss/simply-logo.css diff --git a/www/api/data/components/simply-logo/componentTemplates/logo.html b/components/simply-logo/componentTemplates/logo.html similarity index 100% rename from www/api/data/components/simply-logo/componentTemplates/logo.html rename to components/simply-logo/componentTemplates/logo.html diff --git a/www/api/data/components/simply-logo/meta.json b/components/simply-logo/meta.json similarity index 100% rename from www/api/data/components/simply-logo/meta.json rename to components/simply-logo/meta.json diff --git a/www/api/data/components/simply-toolbar/commands/preview.js b/components/simply-toolbar/commands/preview.js similarity index 100% rename from www/api/data/components/simply-toolbar/commands/preview.js rename to components/simply-toolbar/commands/preview.js diff --git a/www/api/data/components/simply-toolbar/componentCss/simply-toobar-button.css b/components/simply-toolbar/componentCss/simply-toobar-button.css similarity index 100% rename from www/api/data/components/simply-toolbar/componentCss/simply-toobar-button.css rename to components/simply-toolbar/componentCss/simply-toobar-button.css diff --git a/www/api/data/components/simply-toolbar/componentCss/simply-toolbar.css b/components/simply-toolbar/componentCss/simply-toolbar.css similarity index 100% rename from www/api/data/components/simply-toolbar/componentCss/simply-toolbar.css rename to components/simply-toolbar/componentCss/simply-toolbar.css diff --git a/www/api/data/components/simply-toolbar/componentTemplates/simply-toolbar-base-component.html b/components/simply-toolbar/componentTemplates/simply-toolbar-base-component.html similarity index 100% rename from www/api/data/components/simply-toolbar/componentTemplates/simply-toolbar-base-component.html rename to components/simply-toolbar/componentTemplates/simply-toolbar-base-component.html diff --git a/www/api/data/components/simply-toolbar/componentTemplates/simply-toolbar-component.html b/components/simply-toolbar/componentTemplates/simply-toolbar-component.html similarity index 100% rename from www/api/data/components/simply-toolbar/componentTemplates/simply-toolbar-component.html rename to components/simply-toolbar/componentTemplates/simply-toolbar-component.html diff --git a/www/api/data/components/simply-toolbar/componentTemplates/simply-toolbar-default.html b/components/simply-toolbar/componentTemplates/simply-toolbar-default.html similarity index 100% rename from www/api/data/components/simply-toolbar/componentTemplates/simply-toolbar-default.html rename to components/simply-toolbar/componentTemplates/simply-toolbar-default.html diff --git a/www/api/data/components/simply-toolbar/componentTemplates/simply-toolbar-page-frame.html b/components/simply-toolbar/componentTemplates/simply-toolbar-page-frame.html similarity index 100% rename from www/api/data/components/simply-toolbar/componentTemplates/simply-toolbar-page-frame.html rename to components/simply-toolbar/componentTemplates/simply-toolbar-page-frame.html diff --git a/www/api/data/components/simply-toolbar/componentTemplates/simply-toolbar-page.html b/components/simply-toolbar/componentTemplates/simply-toolbar-page.html similarity index 100% rename from www/api/data/components/simply-toolbar/componentTemplates/simply-toolbar-page.html rename to components/simply-toolbar/componentTemplates/simply-toolbar-page.html diff --git a/www/api/data/components/simply-toolbar/componentTemplates/simply-toolbar-publish.html b/components/simply-toolbar/componentTemplates/simply-toolbar-publish.html similarity index 100% rename from www/api/data/components/simply-toolbar/componentTemplates/simply-toolbar-publish.html rename to components/simply-toolbar/componentTemplates/simply-toolbar-publish.html diff --git a/www/api/data/components/simply-toolbar/componentTemplates/simply-toolbar.html b/components/simply-toolbar/componentTemplates/simply-toolbar.html similarity index 100% rename from www/api/data/components/simply-toolbar/componentTemplates/simply-toolbar.html rename to components/simply-toolbar/componentTemplates/simply-toolbar.html diff --git a/www/api/data/components/simply-toolbar/meta.json b/components/simply-toolbar/meta.json similarity index 100% rename from www/api/data/components/simply-toolbar/meta.json rename to components/simply-toolbar/meta.json diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index a741691..0000000 --- a/docker-compose.yml +++ /dev/null @@ -1,15 +0,0 @@ -version: '3' - -services: - simplycode: - build: - context: . - dockerfile: Dockerfile - ports: - - 80:80 - - 443:443 - expose: - - 80 - - 443 - hostname: simplycode.local - \ No newline at end of file diff --git a/www/api/data/generated.html b/generated.html similarity index 100% rename from www/api/data/generated.html rename to generated.html diff --git a/lib/config.php b/lib/config.php deleted file mode 100644 index db86a60..0000000 --- a/lib/config.php +++ /dev/null @@ -1,27 +0,0 @@ - $mimetypes ) { - if ( strpos($dirname, $path)===0 ) { - $allowed = true; - break; - } - } - if ( !$allowed ) { - throw new fsException('Access denied for '.$dirname.$filename, 106); - } - $finfo = new finfo(FILEINFO_MIME); - $mimetype = $finfo->file($tempfile); - $mimetypes[]= 'inode/x-empty'; - $mimetypeRe = '{'.implode('|', $mimetypes).'}i'; - if ( !preg_match($mimetypeRe, $mimetype) ) { - throw new fsException('Files with mimetype '.$mimetype.' are not allowed in '.$dirname, 108); - } - return true; - } - - private static function runChecks($method, $filename, $tempfile) - { - if ( !isset(self::$checks[$method]) ) { - return; - } - foreach ( self::$checks[$method] as $path => $checks ) { - foreach ( $checks as $callback ) { - if ( strpos($filename, $path)===0 ) { - $callback($filename, $tempfile); - } - } - } - } - - private static function dirNotWritable($dirname) - { - // FIXME: try to find out why it is not writable - // check if dir exists - // check if dir is writable - // check if dirname is a directory - // check permissions on dirname - // check owner and current user - - $error = error_get_last(); - var_dump($error); - throw new fsException("Directory $dirname is not writable: $error", 102); - } - - private static function fileNotWritable($file) - { - // FIXME: try to find out why it is not writable - $error = error_get_last(); - throw new fsException("File $file is not writeable: $error", 103); - } - - private static function renameFailed($file, $tempfile) - { - // FIXME: try to find out why the rename failed - unlink($tempfile); - throw new fsException('Could not move file contents to '.$file, 104); - } - - public static function exists($filename) { - $realfile = realpath(self::$basedir . $filename ); - return file_exists($realfile); - } - - public static function is_dir($filename) { - $realfile = realpath(self::$basedir . $filename ); - return is_dir($realfile); - } - - public static function scandir($filename) { - $realfile = realpath(self::$basedir . $filename ); - return scandir($realfile); - } - - private static function passthru($dirname, $filename, $hash=null) - { - clearstatcache(true); - list($realdir,$realfile)=self::realpaths($dirname,$filename); - $lock = self::lock($realfile); - - if ( !$lock ) { - throw new fsException('Could not lock '.$dirname.'/'.$filename.' for writing', 109); - } - /* PUT data comes in on the stdin stream */ - $in = fopen("php://input", "r"); - - /* Open a file for writing */ - $tempfile = tempnam($realdir, 'put-'); - chmod($tempfile, 0644); - $out = fopen($tempfile, "w"); - $res = stream_copy_to_stream($in,$out); - - /* Close the streams */ - fclose($out); - fclose($in); - - $exception = false; - try { - if ($res!==false) { - if ( !self::isAllowed($dirname, $filename, $tempfile) ) { - throw new fsException('Access denied for '.self::append($dirname,$filename), 106); - } - self::runChecks('put', self::append($dirname,$filename), $tempfile); - $res = rename($tempfile, $realfile); - if ($res == false) { - self::renameFailed(self::append($dirname,$filename), $tempfile); - } - } else { - } - } catch( \Exception $e ) { - $exception = $e; - } finally { - self::unlock($lock); - @unlink($tempfile); - } - if ( $exception ) { - throw $exception; - } - return true; - } - - private static function lock($filename) - { - clearstatcache(true); - $fp = fopen($filename.'.lock', 'w'); - if ( $fp && flock($fp, LOCK_EX ) ) { - return [ - 'resource' => $fp, - 'filename' => $filename - ]; - } - return false; - } - - private static function unlock($lock) - { - flock($lock['resource'], LOCK_UN); - fclose($lock['resource']); - unlink($lock['filename'].'.lock'); - } - - public static function cached($cacheName, $cacheTime) { - $cacheFile = self::$basedir . "/cache/" . $cacheName; - // Serve from the cache if it is younger than $cachetime - if (file_exists($cacheFile) && time() - $cacheTime < filemtime($cacheFile)) { - // echo "\n"; - readfile($cacheFile); - return true; - } else { - ob_start(); // Start the output buffer - return false; - } - } - - public static function saveCache($cacheName) { - $cacheDir = self::$basedir . "/cache/"; - if (file_exists($cacheDir)) { - // Cache the contents to a cache file - $cacheFile = self::$basedir . "/cache/" . $cacheName; - $tempFile = tempnam(self::$basedir . "/cache/", $cacheName); - - $cached = fopen($tempFile, 'w'); - fwrite($cached, ob_get_contents()); - fclose($cached); - if (file_exists($tempFile)) { - rename($tempFile, $cacheFile); - } - } - ob_end_flush(); // Send the output to the browser - } -} diff --git a/lib/http.php b/lib/http.php deleted file mode 100755 index 892bca8..0000000 --- a/lib/http.php +++ /dev/null @@ -1,138 +0,0 @@ - false ]; - } - foreach ( $list as $header => $extraInfo ) { - for ($i=$redirectLevel; $i>=0; $i--) { - $check = str_repeat($redirect, $i).$header; - if ( isset($_SERVER[$check]) ) { - return [$header, $_SERVER[$check]]; - } - } - } - return [false, '']; - } - - private static function parseAuthUser($auth) { - return explode(':',base64_decode(substr($auth, 6))); - } - - public static function getUser() - { - $checks = [ - 'PHP_AUTH_USER' => false, - 'REMOTE_USER' => false, - 'HTTP_AUTHORIZATION' => ['self','parseAuthUser'], - ]; - list($header, $headerValue) = self::getHeader($checks, 3); - if (isset($checks[$header]) && is_array($checks[$header])) { - $headerValue = call_user_func($checks[$header], $headerValue)[0]; - } - return $headerValue; - } - - public static function getPassword() - { - $checks = [ - 'PHP_AUTH_PW' => false, - 'HTTP_AUTHORIZATION' => ['self','parseAuthUser'], - ]; - list($header, $headerValue) = self::getHeader($checks, 3); - if (isset($checks[$header]) && is_array($checks[$header])) { - $headerValue = call_user_func($checks[$header], $headerValue)[1]; - } - return $headerValue; - } - - public static function getMethod() - { - list($header, $headerValue) = self::getHeader('REQUEST_METHOD',3); - if ($headerValue==='POST') { - if ($_GET['_method']=='PUT'||$_GET['_method']=='DELETE') { - $headerValue = $_GET['_method']; - } - } - return $headerValue; - } - - public static function request() - { - $target = preg_replace('@\?.*$@','',$_SERVER["REQUEST_URI"]); - $target = self::sanitizeTarget($target); - - preg_match('@(?.+/)?(?[^/]*)@',$target,$matches); - - $filename = isset($matches['filename']) ? $matches['filename'] : ''; - $dirname = ( isset($matches['dirname']) ? filesystem::path($matches['dirname']) : '/'); - $docroot = $_SERVER['DOCUMENT_ROOT']; - $subdir = filesystem::path( substr( dirname(dirname($_SERVER['SCRIPT_FILENAME'])), strlen($docroot) ) ); - $dirname = filesystem::path( substr($dirname, strlen($subdir) ) ); - $request = [ - 'protocol' => $_SERVER['SERVER_PROTOCOL']?:'HTTP/1.1', - 'method' => self::getMethod(), - 'target' => '/'.$target, - 'directory' => $dirname, - 'filename' => $filename, - 'user' => self::getUser(), - 'password' => self::getPassword(), - 'docroot' => $docroot - ]; - return $request; - } - - public static function response($status, $data='') - { - http_response_code($status); - header('Access-Control-Allow-Origin: *'); - switch(self::$format) { - case 'html': - echo $data; - break; - case 'text': - header('Content-Type: text/plain'); - echo $data; - break; - case 'rawjson': - header('Content-Type: application/json'); - echo $data; - break; - case 'json': - default: - header('Content-Type: application/json'); - echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR); - break; - } - } - -} diff --git a/lib/router.php b/lib/router.php deleted file mode 100644 index 5099041..0000000 --- a/lib/router.php +++ /dev/null @@ -1,73 +0,0 @@ -'; - } else if ( !filesystem::exists($templateDir) ) { - echo ''; - } else { - echo ''; - } - } - - http::response($status); - $contents = filesystem::get($templateDir, $template); - $contents = preg_replace('/ - - - - 404 Not Found - - -

Page not found (error: 404)

- - -'; - } diff --git a/npm_post_install.sh b/npm_post_install.sh deleted file mode 100755 index fee8923..0000000 --- a/npm_post_install.sh +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/env bash -current_pwd=`pwd` - -if [[ ${INIT_CWD} != ${current_pwd} ]]; then - exit 0; # Skip posinstall when we are installed as a dependancy -fi - -#if (process.cwd().includes('node_modules')) { -# return; # Skip postinstall when we are installed as a dependancy. -#} - -installCodeMirror() { - sSourceDir="${npm_config_local_prefix}/node_modules" - sTargetDir="${npm_config_local_prefix}/www/js" - - mkdir -p \ - "${sTargetDir}/codemirror/lib/" \ - "${sTargetDir}/codemirror/mode/css/" \ - "${sTargetDir}/codemirror/mode/htmlmixed/" \ - "${sTargetDir}/codemirror/mode/javascript/" \ - "${sTargetDir}/codemirror/mode/xml/" \ - "${sTargetDir}/codemirror/theme/" - - cp -f "${sSourceDir}/codemirror/lib/codemirror.css" "${sTargetDir}/codemirror/lib/codemirror.css" - cp -f "${sSourceDir}/codemirror/lib/codemirror.js" "${sTargetDir}/codemirror/lib/codemirror.js" - cp -f "${sSourceDir}/codemirror/mode/css/css.js" "${sTargetDir}/codemirror/mode/css/css.js" - cp -f "${sSourceDir}/codemirror/mode/htmlmixed/htmlmixed.js" "${sTargetDir}/codemirror/mode/htmlmixed/htmlmixed.js" - cp -f "${sSourceDir}/codemirror/mode/javascript/javascript.js" "${sTargetDir}/codemirror/mode/javascript/javascript.js" - cp -f "${sSourceDir}/codemirror/mode/xml/xml.js" "${sTargetDir}/codemirror/mode/xml/xml.js" - cp -f "${sSourceDir}/codemirror/theme/base16-dark.css" "${sTargetDir}/codemirror/theme/base16-dark.css" -} - -installSimplyEdit() { - local sSourceDir sTargetDir - - readonly sSourceDir="${npm_config_local_prefix}/node_modules/simplyedit" - readonly sTargetDir="${npm_config_local_prefix}/www" - - mkdir -p \ - "${sTargetDir}/js/" \ - "${sTargetDir}/hope/" \ - "${sTargetDir}/simply/" \ - - cp -a "${sSourceDir}/js/"* "${sTargetDir}/js" - cp -a "${sSourceDir}/hope/"* "${sTargetDir}/hope" - cp -a "${sSourceDir}/simply/"* "${sTargetDir}/simply" -} - -if [[ ${BASH_SOURCE[0]} != "${0}" ]]; then - export -f installSimplyEdit - export -f installCodeMirror -else - installSimplyEdit - installCodeMirror - exit $? -fi - - diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 1220aea..0000000 --- a/package-lock.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "simplycode", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "simplycode", - "hasInstallScript": true, - "license": "MIT", - "dependencies": { - "codemirror": "5.65.2", - "simplyedit": "github:simplyedit/simplyedit" - } - }, - "node_modules/codemirror": { - "version": "5.65.2", - "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.2.tgz", - "integrity": "sha512-SZM4Zq7XEC8Fhroqe3LxbEEX1zUPWH1wMr5zxiBuiUF64iYOUH/JI88v4tBag8MiBS8B8gRv8O1pPXGYXQ4ErA==", - "license": "MIT" - }, - "node_modules/simplyedit": { - "resolved": "git+ssh://git@github.com/simplyedit/simplyedit.git#004c14675574c1edb5a1fc3ccae32097f9154069" - } - } -} diff --git a/package.json b/package.json deleted file mode 100644 index d347deb..0000000 --- a/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "author": "SimplyEdit", - "description": "Code editor in the SimplyEdit family", - "dependencies": { - "codemirror": "5.65.2", - "simplyedit": "github:simplyedit/simplyedit" - }, - "keywords": [ - "code", - "ide", - "editor", - "lowcode", - "nocode", - "low-code", - "no-code" - ], - "license": "MIT", - "main": "index.html", - "name": "simplycode", - "repository": { - "type": "git", - "url": "git+https://github.com/SimplyEdit/simplycode.git" - }, - "scripts": { - "postinstall": "./npm_post_install.sh" - } -} diff --git a/www/api/data/page-frame/componentPreview.html b/page-frame/componentPreview.html similarity index 100% rename from www/api/data/page-frame/componentPreview.html rename to page-frame/componentPreview.html diff --git a/www/api/data/page-frame/fullApp.html b/page-frame/fullApp.html similarity index 100% rename from www/api/data/page-frame/fullApp.html rename to page-frame/fullApp.html diff --git a/www/api/data/page-frame/pagePreview.html b/page-frame/pagePreview.html similarity index 100% rename from www/api/data/page-frame/pagePreview.html rename to page-frame/pagePreview.html diff --git a/www/api/data/pages/base-component/actions/deleteBaseComponent.js b/pages/base-component/actions/deleteBaseComponent.js similarity index 100% rename from www/api/data/pages/base-component/actions/deleteBaseComponent.js rename to pages/base-component/actions/deleteBaseComponent.js diff --git a/www/api/data/pages/base-component/actions/getBaseComponent.js b/pages/base-component/actions/getBaseComponent.js similarity index 100% rename from www/api/data/pages/base-component/actions/getBaseComponent.js rename to pages/base-component/actions/getBaseComponent.js diff --git a/www/api/data/pages/base-component/actions/saveBaseComponent.js b/pages/base-component/actions/saveBaseComponent.js similarity index 100% rename from www/api/data/pages/base-component/actions/saveBaseComponent.js rename to pages/base-component/actions/saveBaseComponent.js diff --git a/www/api/data/pages/base-component/commands/deleteBaseComponent.js b/pages/base-component/commands/deleteBaseComponent.js similarity index 100% rename from www/api/data/pages/base-component/commands/deleteBaseComponent.js rename to pages/base-component/commands/deleteBaseComponent.js diff --git a/www/api/data/pages/base-component/commands/saveBaseComponent.js b/pages/base-component/commands/saveBaseComponent.js similarity index 100% rename from www/api/data/pages/base-component/commands/saveBaseComponent.js rename to pages/base-component/commands/saveBaseComponent.js diff --git a/www/api/data/pages/base-component/dataApi/deleteBaseComponent.js b/pages/base-component/dataApi/deleteBaseComponent.js similarity index 100% rename from www/api/data/pages/base-component/dataApi/deleteBaseComponent.js rename to pages/base-component/dataApi/deleteBaseComponent.js diff --git a/www/api/data/pages/base-component/dataApi/deleteBaseComponentPart.js b/pages/base-component/dataApi/deleteBaseComponentPart.js similarity index 100% rename from www/api/data/pages/base-component/dataApi/deleteBaseComponentPart.js rename to pages/base-component/dataApi/deleteBaseComponentPart.js diff --git a/www/api/data/pages/base-component/dataApi/getBaseComponent.js b/pages/base-component/dataApi/getBaseComponent.js similarity index 100% rename from www/api/data/pages/base-component/dataApi/getBaseComponent.js rename to pages/base-component/dataApi/getBaseComponent.js diff --git a/www/api/data/pages/base-component/dataApi/saveBaseComponentPart.js b/pages/base-component/dataApi/saveBaseComponentPart.js similarity index 100% rename from www/api/data/pages/base-component/dataApi/saveBaseComponentPart.js rename to pages/base-component/dataApi/saveBaseComponentPart.js diff --git a/www/api/data/pages/base-component/meta.json b/pages/base-component/meta.json similarity index 100% rename from www/api/data/pages/base-component/meta.json rename to pages/base-component/meta.json diff --git a/www/api/data/pages/base-component/pageTemplates/Edit base component.html b/pages/base-component/pageTemplates/Edit base component.html similarity index 100% rename from www/api/data/pages/base-component/pageTemplates/Edit base component.html rename to pages/base-component/pageTemplates/Edit base component.html diff --git a/www/api/data/pages/base-component/routes/base-component.js b/pages/base-component/routes/base-component.js similarity index 100% rename from www/api/data/pages/base-component/routes/base-component.js rename to pages/base-component/routes/base-component.js diff --git a/www/api/data/pages/base-component/routes/base-component.json b/pages/base-component/routes/base-component.json similarity index 100% rename from www/api/data/pages/base-component/routes/base-component.json rename to pages/base-component/routes/base-component.json diff --git a/www/api/data/pages/base-components/actions/listBaseComponents.js b/pages/base-components/actions/listBaseComponents.js similarity index 100% rename from www/api/data/pages/base-components/actions/listBaseComponents.js rename to pages/base-components/actions/listBaseComponents.js diff --git a/www/api/data/pages/base-components/commands/createBaseComponent.js b/pages/base-components/commands/createBaseComponent.js similarity index 100% rename from www/api/data/pages/base-components/commands/createBaseComponent.js rename to pages/base-components/commands/createBaseComponent.js diff --git a/www/api/data/pages/base-components/dataApi/listBaseComponents.js b/pages/base-components/dataApi/listBaseComponents.js similarity index 100% rename from www/api/data/pages/base-components/dataApi/listBaseComponents.js rename to pages/base-components/dataApi/listBaseComponents.js diff --git a/www/api/data/pages/base-components/meta.json b/pages/base-components/meta.json similarity index 100% rename from www/api/data/pages/base-components/meta.json rename to pages/base-components/meta.json diff --git a/www/api/data/pages/base-components/pageTemplates/Base components.html b/pages/base-components/pageTemplates/Base components.html similarity index 100% rename from www/api/data/pages/base-components/pageTemplates/Base components.html rename to pages/base-components/pageTemplates/Base components.html diff --git a/www/api/data/pages/base-components/routes/base-components.js b/pages/base-components/routes/base-components.js similarity index 100% rename from www/api/data/pages/base-components/routes/base-components.js rename to pages/base-components/routes/base-components.js diff --git a/www/api/data/pages/base-components/routes/base-components.json b/pages/base-components/routes/base-components.json similarity index 100% rename from www/api/data/pages/base-components/routes/base-components.json rename to pages/base-components/routes/base-components.json diff --git a/www/api/data/pages/base-components/transformers/baseComponentLink-extract.js b/pages/base-components/transformers/baseComponentLink-extract.js similarity index 100% rename from www/api/data/pages/base-components/transformers/baseComponentLink-extract.js rename to pages/base-components/transformers/baseComponentLink-extract.js diff --git a/www/api/data/pages/base-components/transformers/baseComponentLink-render.js b/pages/base-components/transformers/baseComponentLink-render.js similarity index 100% rename from www/api/data/pages/base-components/transformers/baseComponentLink-render.js rename to pages/base-components/transformers/baseComponentLink-render.js diff --git a/www/api/data/pages/component-list/actions/listComponents.js b/pages/component-list/actions/listComponents.js similarity index 100% rename from www/api/data/pages/component-list/actions/listComponents.js rename to pages/component-list/actions/listComponents.js diff --git a/www/api/data/pages/component-list/commands/createComponent.js b/pages/component-list/commands/createComponent.js similarity index 100% rename from www/api/data/pages/component-list/commands/createComponent.js rename to pages/component-list/commands/createComponent.js diff --git a/www/api/data/pages/component-list/dataApi/listComponents.js b/pages/component-list/dataApi/listComponents.js similarity index 100% rename from www/api/data/pages/component-list/dataApi/listComponents.js rename to pages/component-list/dataApi/listComponents.js diff --git a/www/api/data/pages/component-list/meta.json b/pages/component-list/meta.json similarity index 100% rename from www/api/data/pages/component-list/meta.json rename to pages/component-list/meta.json diff --git a/www/api/data/pages/component-list/pageTemplates/List components.html b/pages/component-list/pageTemplates/List components.html similarity index 100% rename from www/api/data/pages/component-list/pageTemplates/List components.html rename to pages/component-list/pageTemplates/List components.html diff --git a/www/api/data/pages/component-list/pageTemplates/List components.json b/pages/component-list/pageTemplates/List components.json similarity index 100% rename from www/api/data/pages/component-list/pageTemplates/List components.json rename to pages/component-list/pageTemplates/List components.json diff --git a/www/api/data/pages/component-list/routes/component-list.js b/pages/component-list/routes/component-list.js similarity index 100% rename from www/api/data/pages/component-list/routes/component-list.js rename to pages/component-list/routes/component-list.js diff --git a/www/api/data/pages/component-list/routes/component-list.json b/pages/component-list/routes/component-list.json similarity index 100% rename from www/api/data/pages/component-list/routes/component-list.json rename to pages/component-list/routes/component-list.json diff --git a/www/api/data/pages/component-list/transformers/componentLink-extract.js b/pages/component-list/transformers/componentLink-extract.js similarity index 100% rename from www/api/data/pages/component-list/transformers/componentLink-extract.js rename to pages/component-list/transformers/componentLink-extract.js diff --git a/www/api/data/pages/component-list/transformers/componentLink-render.js b/pages/component-list/transformers/componentLink-render.js similarity index 100% rename from www/api/data/pages/component-list/transformers/componentLink-render.js rename to pages/component-list/transformers/componentLink-render.js diff --git a/www/api/data/pages/component/actions/deleteComponent.js b/pages/component/actions/deleteComponent.js similarity index 100% rename from www/api/data/pages/component/actions/deleteComponent.js rename to pages/component/actions/deleteComponent.js diff --git a/www/api/data/pages/component/actions/getComponent.js b/pages/component/actions/getComponent.js similarity index 100% rename from www/api/data/pages/component/actions/getComponent.js rename to pages/component/actions/getComponent.js diff --git a/www/api/data/pages/component/actions/saveComponent.js b/pages/component/actions/saveComponent.js similarity index 100% rename from www/api/data/pages/component/actions/saveComponent.js rename to pages/component/actions/saveComponent.js diff --git a/www/api/data/pages/component/commands/deleteComponent.js b/pages/component/commands/deleteComponent.js similarity index 100% rename from www/api/data/pages/component/commands/deleteComponent.js rename to pages/component/commands/deleteComponent.js diff --git a/www/api/data/pages/component/commands/saveComponent.js b/pages/component/commands/saveComponent.js similarity index 100% rename from www/api/data/pages/component/commands/saveComponent.js rename to pages/component/commands/saveComponent.js diff --git a/www/api/data/pages/component/dataApi/deleteComponent.js b/pages/component/dataApi/deleteComponent.js similarity index 100% rename from www/api/data/pages/component/dataApi/deleteComponent.js rename to pages/component/dataApi/deleteComponent.js diff --git a/www/api/data/pages/component/dataApi/deleteComponentPart.js b/pages/component/dataApi/deleteComponentPart.js similarity index 100% rename from www/api/data/pages/component/dataApi/deleteComponentPart.js rename to pages/component/dataApi/deleteComponentPart.js diff --git a/www/api/data/pages/component/dataApi/getComponent.js b/pages/component/dataApi/getComponent.js similarity index 100% rename from www/api/data/pages/component/dataApi/getComponent.js rename to pages/component/dataApi/getComponent.js diff --git a/www/api/data/pages/component/dataApi/saveComponentPart.js b/pages/component/dataApi/saveComponentPart.js similarity index 100% rename from www/api/data/pages/component/dataApi/saveComponentPart.js rename to pages/component/dataApi/saveComponentPart.js diff --git a/www/api/data/pages/component/meta.json b/pages/component/meta.json similarity index 100% rename from www/api/data/pages/component/meta.json rename to pages/component/meta.json diff --git a/www/api/data/pages/component/pageTemplates/Edit component.html b/pages/component/pageTemplates/Edit component.html similarity index 100% rename from www/api/data/pages/component/pageTemplates/Edit component.html rename to pages/component/pageTemplates/Edit component.html diff --git a/www/api/data/pages/component/routes/component.js b/pages/component/routes/component.js similarity index 100% rename from www/api/data/pages/component/routes/component.js rename to pages/component/routes/component.js diff --git a/www/api/data/pages/component/routes/component.json b/pages/component/routes/component.json similarity index 100% rename from www/api/data/pages/component/routes/component.json rename to pages/component/routes/component.json diff --git a/www/api/data/pages/page-frame/actions/getPageFrame.js b/pages/page-frame/actions/getPageFrame.js similarity index 100% rename from www/api/data/pages/page-frame/actions/getPageFrame.js rename to pages/page-frame/actions/getPageFrame.js diff --git a/www/api/data/pages/page-frame/actions/savePageFrame.js b/pages/page-frame/actions/savePageFrame.js similarity index 100% rename from www/api/data/pages/page-frame/actions/savePageFrame.js rename to pages/page-frame/actions/savePageFrame.js diff --git a/www/api/data/pages/page-frame/commands/savePageFrame.js b/pages/page-frame/commands/savePageFrame.js similarity index 100% rename from www/api/data/pages/page-frame/commands/savePageFrame.js rename to pages/page-frame/commands/savePageFrame.js diff --git a/www/api/data/pages/page-frame/dataApi/deletePageFramePart.js b/pages/page-frame/dataApi/deletePageFramePart.js similarity index 100% rename from www/api/data/pages/page-frame/dataApi/deletePageFramePart.js rename to pages/page-frame/dataApi/deletePageFramePart.js diff --git a/www/api/data/pages/page-frame/dataApi/getPageFrame.js b/pages/page-frame/dataApi/getPageFrame.js similarity index 100% rename from www/api/data/pages/page-frame/dataApi/getPageFrame.js rename to pages/page-frame/dataApi/getPageFrame.js diff --git a/www/api/data/pages/page-frame/dataApi/savePageFramePart.js b/pages/page-frame/dataApi/savePageFramePart.js similarity index 100% rename from www/api/data/pages/page-frame/dataApi/savePageFramePart.js rename to pages/page-frame/dataApi/savePageFramePart.js diff --git a/www/api/data/pages/page-frame/meta.json b/pages/page-frame/meta.json similarity index 100% rename from www/api/data/pages/page-frame/meta.json rename to pages/page-frame/meta.json diff --git a/www/api/data/pages/page-frame/pageTemplates/Edit page frame.html b/pages/page-frame/pageTemplates/Edit page frame.html similarity index 100% rename from www/api/data/pages/page-frame/pageTemplates/Edit page frame.html rename to pages/page-frame/pageTemplates/Edit page frame.html diff --git a/www/api/data/pages/page-frame/routes/page-frame.js b/pages/page-frame/routes/page-frame.js similarity index 100% rename from www/api/data/pages/page-frame/routes/page-frame.js rename to pages/page-frame/routes/page-frame.js diff --git a/www/api/data/pages/page-frame/routes/page-frame.json b/pages/page-frame/routes/page-frame.json similarity index 100% rename from www/api/data/pages/page-frame/routes/page-frame.json rename to pages/page-frame/routes/page-frame.json diff --git a/www/api/data/pages/page/actions/deletePage.js b/pages/page/actions/deletePage.js similarity index 100% rename from www/api/data/pages/page/actions/deletePage.js rename to pages/page/actions/deletePage.js diff --git a/www/api/data/pages/page/actions/getPage.js b/pages/page/actions/getPage.js similarity index 100% rename from www/api/data/pages/page/actions/getPage.js rename to pages/page/actions/getPage.js diff --git a/www/api/data/pages/page/actions/savePage.js b/pages/page/actions/savePage.js similarity index 100% rename from www/api/data/pages/page/actions/savePage.js rename to pages/page/actions/savePage.js diff --git a/www/api/data/pages/page/commands/deletePage.js b/pages/page/commands/deletePage.js similarity index 100% rename from www/api/data/pages/page/commands/deletePage.js rename to pages/page/commands/deletePage.js diff --git a/www/api/data/pages/page/commands/savePage.js b/pages/page/commands/savePage.js similarity index 100% rename from www/api/data/pages/page/commands/savePage.js rename to pages/page/commands/savePage.js diff --git a/www/api/data/pages/page/dataApi/deletePage.js b/pages/page/dataApi/deletePage.js similarity index 100% rename from www/api/data/pages/page/dataApi/deletePage.js rename to pages/page/dataApi/deletePage.js diff --git a/www/api/data/pages/page/dataApi/deletePagePart.js b/pages/page/dataApi/deletePagePart.js similarity index 100% rename from www/api/data/pages/page/dataApi/deletePagePart.js rename to pages/page/dataApi/deletePagePart.js diff --git a/www/api/data/pages/page/dataApi/getPage.js b/pages/page/dataApi/getPage.js similarity index 100% rename from www/api/data/pages/page/dataApi/getPage.js rename to pages/page/dataApi/getPage.js diff --git a/www/api/data/pages/page/dataApi/savePagePart.js b/pages/page/dataApi/savePagePart.js similarity index 100% rename from www/api/data/pages/page/dataApi/savePagePart.js rename to pages/page/dataApi/savePagePart.js diff --git a/www/api/data/pages/page/meta.json b/pages/page/meta.json similarity index 100% rename from www/api/data/pages/page/meta.json rename to pages/page/meta.json diff --git a/www/api/data/pages/page/pageTemplates/Edit page.html b/pages/page/pageTemplates/Edit page.html similarity index 100% rename from www/api/data/pages/page/pageTemplates/Edit page.html rename to pages/page/pageTemplates/Edit page.html diff --git a/www/api/data/pages/page/routes/page.js b/pages/page/routes/page.js similarity index 100% rename from www/api/data/pages/page/routes/page.js rename to pages/page/routes/page.js diff --git a/www/api/data/pages/page/routes/page.json b/pages/page/routes/page.json similarity index 100% rename from www/api/data/pages/page/routes/page.json rename to pages/page/routes/page.json diff --git a/www/api/data/pages/pages/actions/listPages.js b/pages/pages/actions/listPages.js similarity index 100% rename from www/api/data/pages/pages/actions/listPages.js rename to pages/pages/actions/listPages.js diff --git a/www/api/data/pages/pages/commands/createPage.js b/pages/pages/commands/createPage.js similarity index 100% rename from www/api/data/pages/pages/commands/createPage.js rename to pages/pages/commands/createPage.js diff --git a/www/api/data/pages/pages/dataApi/listPages.js b/pages/pages/dataApi/listPages.js similarity index 100% rename from www/api/data/pages/pages/dataApi/listPages.js rename to pages/pages/dataApi/listPages.js diff --git a/www/api/data/pages/pages/meta.json b/pages/pages/meta.json similarity index 100% rename from www/api/data/pages/pages/meta.json rename to pages/pages/meta.json diff --git a/www/api/data/pages/pages/pageTemplates/Pages.html b/pages/pages/pageTemplates/Pages.html similarity index 100% rename from www/api/data/pages/pages/pageTemplates/Pages.html rename to pages/pages/pageTemplates/Pages.html diff --git a/www/api/data/pages/pages/routes/pages.js b/pages/pages/routes/pages.js similarity index 100% rename from www/api/data/pages/pages/routes/pages.js rename to pages/pages/routes/pages.js diff --git a/www/api/data/pages/pages/routes/pages.json b/pages/pages/routes/pages.json similarity index 100% rename from www/api/data/pages/pages/routes/pages.json rename to pages/pages/routes/pages.json diff --git a/www/api/data/pages/pages/transformers/pageLink-extract.js b/pages/pages/transformers/pageLink-extract.js similarity index 100% rename from www/api/data/pages/pages/transformers/pageLink-extract.js rename to pages/pages/transformers/pageLink-extract.js diff --git a/www/api/data/pages/pages/transformers/pageLink-render.js b/pages/pages/transformers/pageLink-render.js similarity index 100% rename from www/api/data/pages/pages/transformers/pageLink-render.js rename to pages/pages/transformers/pageLink-render.js diff --git a/www/api/data/pages/preview/meta.json b/pages/preview/meta.json similarity index 100% rename from www/api/data/pages/preview/meta.json rename to pages/preview/meta.json diff --git a/www/api/data/pages/preview/pageCss/simplycode-fullscreen-preview.css b/pages/preview/pageCss/simplycode-fullscreen-preview.css similarity index 100% rename from www/api/data/pages/preview/pageCss/simplycode-fullscreen-preview.css rename to pages/preview/pageCss/simplycode-fullscreen-preview.css diff --git a/www/api/data/pages/preview/pageTemplates/preview-app.html b/pages/preview/pageTemplates/preview-app.html similarity index 100% rename from www/api/data/pages/preview/pageTemplates/preview-app.html rename to pages/preview/pageTemplates/preview-app.html diff --git a/www/api/data/pages/preview/pageTemplates/preview-component.html b/pages/preview/pageTemplates/preview-component.html similarity index 100% rename from www/api/data/pages/preview/pageTemplates/preview-component.html rename to pages/preview/pageTemplates/preview-component.html diff --git a/www/api/data/pages/preview/routes/preview-app.js b/pages/preview/routes/preview-app.js similarity index 100% rename from www/api/data/pages/preview/routes/preview-app.js rename to pages/preview/routes/preview-app.js diff --git a/www/api/data/pages/preview/routes/preview-app.json b/pages/preview/routes/preview-app.json similarity index 100% rename from www/api/data/pages/preview/routes/preview-app.json rename to pages/preview/routes/preview-app.json diff --git a/www/api/data/pages/preview/routes/preview-component.js b/pages/preview/routes/preview-component.js similarity index 100% rename from www/api/data/pages/preview/routes/preview-component.js rename to pages/preview/routes/preview-component.js diff --git a/www/api/data/pages/preview/routes/preview-component.json b/pages/preview/routes/preview-component.json similarity index 100% rename from www/api/data/pages/preview/routes/preview-component.json rename to pages/preview/routes/preview-component.json diff --git a/www/api/data/pages/preview/routes/preview-page.js b/pages/preview/routes/preview-page.js similarity index 100% rename from www/api/data/pages/preview/routes/preview-page.js rename to pages/preview/routes/preview-page.js diff --git a/www/api/data/pages/preview/routes/preview-page.json b/pages/preview/routes/preview-page.json similarity index 100% rename from www/api/data/pages/preview/routes/preview-page.json rename to pages/preview/routes/preview-page.json diff --git a/www/api/data/pages/publish/actions/getAppData.js b/pages/publish/actions/getAppData.js similarity index 100% rename from www/api/data/pages/publish/actions/getAppData.js rename to pages/publish/actions/getAppData.js diff --git a/www/api/data/pages/publish/actions/getBaseComponents.js b/pages/publish/actions/getBaseComponents.js similarity index 100% rename from www/api/data/pages/publish/actions/getBaseComponents.js rename to pages/publish/actions/getBaseComponents.js diff --git a/www/api/data/pages/publish/actions/getComponents.js b/pages/publish/actions/getComponents.js similarity index 100% rename from www/api/data/pages/publish/actions/getComponents.js rename to pages/publish/actions/getComponents.js diff --git a/www/api/data/pages/publish/actions/getPages.js b/pages/publish/actions/getPages.js similarity index 100% rename from www/api/data/pages/publish/actions/getPages.js rename to pages/publish/actions/getPages.js diff --git a/www/api/data/pages/publish/actions/getRouteWeight.js b/pages/publish/actions/getRouteWeight.js similarity index 100% rename from www/api/data/pages/publish/actions/getRouteWeight.js rename to pages/publish/actions/getRouteWeight.js diff --git a/www/api/data/pages/publish/actions/saveAppHtml.js b/pages/publish/actions/saveAppHtml.js similarity index 100% rename from www/api/data/pages/publish/actions/saveAppHtml.js rename to pages/publish/actions/saveAppHtml.js diff --git a/www/api/data/pages/publish/actions/tests/getRouteWeight/Fixed path 3 items.js b/pages/publish/actions/tests/getRouteWeight/Fixed path 3 items.js similarity index 100% rename from www/api/data/pages/publish/actions/tests/getRouteWeight/Fixed path 3 items.js rename to pages/publish/actions/tests/getRouteWeight/Fixed path 3 items.js diff --git a/www/api/data/pages/publish/commands/saveAppHtml.js b/pages/publish/commands/saveAppHtml.js similarity index 100% rename from www/api/data/pages/publish/commands/saveAppHtml.js rename to pages/publish/commands/saveAppHtml.js diff --git a/www/api/data/pages/publish/dataApi/saveAppHtml.js b/pages/publish/dataApi/saveAppHtml.js similarity index 100% rename from www/api/data/pages/publish/dataApi/saveAppHtml.js rename to pages/publish/dataApi/saveAppHtml.js diff --git a/www/api/data/pages/publish/meta.json b/pages/publish/meta.json similarity index 100% rename from www/api/data/pages/publish/meta.json rename to pages/publish/meta.json diff --git a/www/api/data/pages/publish/pageTemplates/Publish App.html b/pages/publish/pageTemplates/Publish App.html similarity index 100% rename from www/api/data/pages/publish/pageTemplates/Publish App.html rename to pages/publish/pageTemplates/Publish App.html diff --git a/www/api/data/pages/publish/routes/publish.js b/pages/publish/routes/publish.js similarity index 100% rename from www/api/data/pages/publish/routes/publish.js rename to pages/publish/routes/publish.js diff --git a/www/api/data/pages/publish/routes/publish.json b/pages/publish/routes/publish.json similarity index 100% rename from www/api/data/pages/publish/routes/publish.json rename to pages/publish/routes/publish.json diff --git a/www/api/data/pages/publish/transformers/htmlEscape-extract.js b/pages/publish/transformers/htmlEscape-extract.js similarity index 100% rename from www/api/data/pages/publish/transformers/htmlEscape-extract.js rename to pages/publish/transformers/htmlEscape-extract.js diff --git a/www/api/data/pages/publish/transformers/htmlEscape-render.js b/pages/publish/transformers/htmlEscape-render.js similarity index 100% rename from www/api/data/pages/publish/transformers/htmlEscape-render.js rename to pages/publish/transformers/htmlEscape-render.js diff --git a/www/api/data/pages/publish/transformers/indentCode-extract.js b/pages/publish/transformers/indentCode-extract.js similarity index 100% rename from www/api/data/pages/publish/transformers/indentCode-extract.js rename to pages/publish/transformers/indentCode-extract.js diff --git a/www/api/data/pages/publish/transformers/indentCode-render.js b/pages/publish/transformers/indentCode-render.js similarity index 100% rename from www/api/data/pages/publish/transformers/indentCode-render.js rename to pages/publish/transformers/indentCode-render.js diff --git a/www/.gitignore b/www/.gitignore deleted file mode 100644 index e4e5f6c..0000000 --- a/www/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*~ \ No newline at end of file diff --git a/www/.htaccess b/www/.htaccess deleted file mode 100644 index 6296c0b..0000000 --- a/www/.htaccess +++ /dev/null @@ -1,39 +0,0 @@ - - - Order Allow,Deny - Deny from all - - - - Header set Cache-Control "max-age=0, public, must-revalidate" - -RewriteEngine on -# -# RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] -# -# RewriteCond %{REQUEST_METHOD} PUT -# RewriteRule ^(.*)$ simply-edit/store.php [L] -# -# RewriteCond %{REQUEST_METHOD} DELETE -# RewriteRule ^(.*)$ simply-edit/store.php [L] -# -# RewriteCond %{QUERY_STRING} _method=(PUT|DELETE) -# RewriteRule ^(.*)$ simply-edit/store.php [L] -# - - RewriteRule ^logout$ simply-edit/logout.php [L] - #RewriteRule ^login$ simply-edit/login.php [L] - - - RewriteCond %{HTTP_USER_AGENT} Lynx|w3m|googlebot|baiduspider|facebookexternalhit|twitterbot|rogerbot|linkedinbot|embedly|quora\ link\ preview|showyoubot|outbrain|pinterest|slackbot|vkShare|Validator [NC,OR] - RewriteCond %{QUERY_STRING} _escaped_fragment_ - - # Only proxy the request to Prerender if it's a request for HTML - RewriteRule ^(?!.*?(\.js|\.css|\.xml|\.less|\.png|\.jpg|\.jpeg|\.gif|\.pdf|\.doc|\.txt|\.ico|\.rss|\.zip|\.mp3|\.rar|\.exe|\.wmv|\.doc|\.avi|\.ppt|\.mpg|\.mpeg|\.tif|\.wav|\.mov|\.psd|\.ai|\.xls|\.mp4|\.m4a|\.swf|\.dat|\.dmg|\.iso|\.flv|\.m4v|\.torrent|\.ttf|\.woff))(.*) simply-edit/prerender.php [L] - - -Options +Indexes - -RewriteCond %{REQUEST_FILENAME} !-f -RewriteCond %{REQUEST_FILENAME} !-d -RewriteRule .* simply-edit/router.php [L] \ No newline at end of file diff --git a/www/api/.htaccess b/www/api/.htaccess deleted file mode 100644 index f509db6..0000000 --- a/www/api/.htaccess +++ /dev/null @@ -1,9 +0,0 @@ -RewriteEngine on - - RewriteCond %{QUERY_STRING} _method=(GET|PUT|DELETE) - RewriteRule ^(.*)$ index.php [L] - - -RewriteCond %{REQUEST_FILENAME} !-f -RewriteCond %{REQUEST_FILENAME} !-d -RewriteRule .* index.php [L] \ No newline at end of file diff --git a/www/api/data/simplycode.sh b/www/api/data/simplycode.sh deleted file mode 100755 index 5ad887c..0000000 --- a/www/api/data/simplycode.sh +++ /dev/null @@ -1,10 +0,0 @@ -docker run \ - --env "USER_GID=$(id -g)" \ - --env "USER_ID=$(id -u)" \ - --interactive \ - --publish-all \ - --rm \ - --tty \ - --volume "${PWD}:/var/www/www/api/data" \ - --volume "${PWD}/assets:/var/www/html/assets" \ - ghcr.io/simplyedit/simplycode-docker:main diff --git a/www/api/index.php b/www/api/index.php deleted file mode 100755 index 29db492..0000000 --- a/www/api/index.php +++ /dev/null @@ -1,132 +0,0 @@ - $e->getCode(), "message" => $e->getMessage()], 501); - } - - function filenotfound($path) { - output(["error" => 404, "message" => "File not found"], 404); - } diff --git a/www/camil_192x192.png b/www/camil_192x192.png deleted file mode 100644 index e157c14c612220c90528c0f3b6fc550b027c3a1a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26043 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
x{HVgcH(9RG9V_@_4b` z^%BFt6(LHJWgh|Z(Kh}Kol&BE3D|;f!xt(eV3G&H`ODkrtkB7aWL5-P32I3Rcw5A) z0Ug#OI2dC!z)Aq40iUbrKUfhsK>xxwRB2XA#3Ur2L}|;6+V#G_t=Z)pr=4^DI!)Yc zf$MQ)$I*u$6#2rKcYYbpr5b$`BM`yBb^bK%ejxm0^}8J2@~nmBCnad(J-=MvNBKji z*QuShsO9VO0{Fi31drp^y-!TR^9k) ztcj_uhF9f-98j#9AuSsX|+=_cH*i@I$~wx5xG z{gm(g&o{y^ew3ZPaM2=~k{nd9o8w@FAh(EN(sCNq?1Fssg8xc zZ$OFJi(1r*wP{sDD?l}Eg~XT3rMRJ{A~DKH_K9zxX~iN01-@8ciz!5KjJ*SuiB!I` zV5iIe-?V*?eoPZLEBKr(BWCQl>jA{Ns4yK2M>7!0ELl2Sz{g_^a)k$1da(b8)yLHy z^K8!q+Vc3qFAi2xthh|5)KAV1b2~Z{m$UtRcy(Z_LC%Xas0`?UPWLT8eC_%Js$=^2 zdbQ_PwW^c0c`bDIX~7my8vxK$k|Jy@;Lt}Y8dTEmgxw#DD2>NIbI7N3j+<-+pt_SC z(q$I zyG2l6Tj^G3R@VwwHD`^ak~Pbc0$_g+p@+5OYyG4Qc(N0ge{7AbJ~fSw4!R_Y%GDaw zp(lkwlg^(K7I>xdCefQr52h6PBmwf(%x+kri`(_t_4fo+FES|Yiu8d?aojL7J{=WLH$9B`nn>_MITLw%SQxl(k!I<~lTyhIAj~PnBk1Ia7 z=HHb_@g%Pyi`U#Cdw*(9nJ;h;|h@q(?NmH19HCr z%IlBUt{7o6PSYRs-SCvGj0I6l$&pu009=-QRwF0e+_L58&;93$$$$OonP=r!7{Ene zJt90U@oCg9c9}t9r^BcyzpFt(1&pwAb_UYn3d;v! z*Fh14sFY9hg)P4(pB!w*ABTa|hfx8+R06lH)S7keYQf45RbS!q0U4J|;}P63rU)LS z!{gOZ8m{g$t{9d+2ws$Nq5LjlbWZF9RTMmKWz8Sbu0!dhzizRN*up zL&l>HWc~3JC$8_yHGc`?DNj7lbJR|a{LH;AHh$Qr1!0sxKw+}-m?KzMznq`PRvZu5 zFO$b#geM=LzE2^P;Xl(qI1vPi3EeJ(u*t(z-KL~SSbW+Zs=iWvysCq`hAF}i zCF4d&5pOf zp1wDcHHZ)X*CNQ^zZNy733kP4Z^zD4rhXg<6sxE%KA*&AGzD~uWWYs+Q z<&EXFecKx6aHlPBa4isU4I})fj)J-E}crz`As=%TU(F3 z@z}b5P$tIDzJ2oP-)wmFwknm_hRQN?3=e%4NH~u;4ffZ0X z3%Qw?{QQ7j#wda*Z`$C)B!^%@Nys@>;-*gIkdUDvmrx2}r`dTBE>)&9ObPU%v8IxZ z#M;g@-z0+z)83N%%GLXQ?oV5N1s))AG6~h5%&0ZAlCNsdI&0dxCQX|(V%M5sV_&~= z=HlPdN;T5(Q~+KIM-5jIXXJA3@WlMxjz0GI%ID^{KecT6^8BKM3~;Y(IQ{g~tD}kK zyU?IS=;(lluQaA;0&$fG&+fQmin>psZx-Rxn zheg9yhn)u;5-}xE1e+CRqU^?qV(M8>K(Bxi4b`ftCdOMvte|*A1ZOI&1nkxmcuuH2 zd?x~{c^mHDwgfP`Gr~RR?TSPZ@)OmHtn z?y8g1S9W@=Z-D9O5i0=AAK%BJEg8O|+MJB5X=AFKx>&Z!W1U9+SqwlJPBO}r@<^lO z7T^>Cl}!eF7J_pwZP-dxXER&05q4Xwlc~>TflhcN@3T6 z`CyUZaQP651U6#5KrV5bg5><78ZsG$X`l}bc3%-LCS1iLr zPn@#ww(Gxt{(1g$?t_f7D!^$c9SSEPjIn z3GEh*5q_r*z!O!(+5?91@QtG6PY%lYak*1Uargz+3~{l5COi=2_d{UQilQi`pRSp}qwfwU<+F=5-;bd%q}(AcN? z`Ta{|#9+|i<50dQDL~mkmaA^XOXqy&^rQCCltD#V6+k81iBaGa4r#PkBriowGB2=_ zE5(l5W2*+rN1Q8|c!4)DRF`p>Q!ngwn4V#8BAm|IQ9hbhCu*oAu zO+OKlx=_}S`_5~NKTW+PC8Pwy>TB5o4-^0Y5uQx6fWa>(Ab+SKplQP14XcHV;O_6X>!Pe<%N&(-St1%-%|0Q zD-L{@xPcDGohgTu0N=655Zmc+%qxLi&V+leQ-E|cCOC?NH@pJir39EujMGt5$JCH7 ztBBzreCClA?;9K^-a7yI|2*-J&uhYqTwVh?NEfVbs>2~ zgVVWp#6yacW1i_cgs-|o0f1hZM*UYRGX4Eue?=1p4gH<1qHt1OJ7DAx3cR4o>=)$= z?MjVrh^u%wLW85>VUnnfFo2_^H1q+-RuryKpv=VfA5wwMbQ8v;p-;#oG{l4==qa9$ z!ig0?h=X4f6$lYyGt?%@ld>`}$}bbE4O zrO=)!fw0i1Z{*8XM-Ws(*ic(w;jjt@X~r28rb#{BjkH)AXwg_qg(4A^fu$k-;~a*% z75gAw$G_MJNGlr@ts1z%ez$k@G zg54JK*m0n+JyXg|sEHdlXvpJB_dr&EoQRX*As<|fR@Bo`Kn}#gFTnH{5NhH!w*%K$ zi^uyx5uR`_&>whk!DX@}L?#3%BXQX-v2$yeJ&&K(8Wfn8%L6c*wm{hO;BGHlfASlv zTonoV46%jPz)WO!Fw8f3QIDxhXu?3T_81y`yDgJP${PVU@C2T+*z;#qn| z4}0_9{t zcr84YLqC|JYoG*E6MVzZVmuZXT%oLt4C*^7TKekepSbO3V}w>-2=~ea+z^2RWclT_ za>W2{LR0>o!u(0?8QvsV5SkGX45K$gv8RXXAP=>g2|?J7cL!--M+hcvXtt8ueKdU* z8Uz3W>eKu*GagiE=+X{T*_Sr_avYT+cpW<~N%AUS`UW3y<4hdBsYCKIXbirQA%`&i zjjj#z7j$|9R0S90F*QZLTZGqn5eBtcJ#(zPw~m$-y^)$;Ba0t`AnxIy1nZACy1_M7 zK>>PZm@waGfP~F{5Y|g3Lnb8HbqG^_8(6jtgFR>ELAqT6VLMLAo)5?SUk;l-P?!i% zc>ZbylXM;rhLfwkw@Y_3J8UOgoP{kYLHZ5%AlQMP9R%R#PgL^ zUe_q&XsDs>4^@X;+{eNWddRQcj|X{=xgjo4Nb`fM^yWCE-hb?*ZMWH`tnv!jeHbu4 z`o-RlG`7F@8NAw~xih0ywPpG7-A_*+PE6{1Q{XG)0uvwtUVQwf=HN6GYmsTej3q#N ztOb)4Iz*G+w3W&=Oj4?DqDl;#s-g{JRJ@{+jBQlmTT-cHm+EX;soduGRk(SMa$7!B znU(WZEV+uRK;L`WaM?iZ5fgLx?tmN7V=2ZJAIO7M0r?~>1}K~EQmL*EwX!{<8ft4* zRRyl-$qHg1`QdYnT+ibTiUkDUD@AD%rapvXOLx5bk8d1rRIYGb~tpZ(B3%@I-^zpt&*C zQMHAN%{)bg#_pnGBe&vo10xuvS|`yU3hbp)U2B#pwfrsB{>ojddihIAkuV_zX=3$E z9fJe@?FCqN?r(lSdy8BqsWQoSR)CQW^~%K$0qPMLpnBnpCNLzzib4q}VN5|TT&Y$y z?yN$iwo~rBM^t_1N1P(L1YXF=b*!Fw;ity#fBGw$QWo@&8zu1a&yPA`%DQL&L@PjO z6)C_DG7oIx;d zL)w#ltpSV@$7y@As(KrxzW#4jea;gk{KrzN*k*qs2LP`MjKER#VAHDUmYL? zGMaBYl(1cCm{iFr3P?fvz!HUESG-AOj=xpao^q?ItZkrdP>`N$9t?zNKizov#mYJB zY1J`&M^OTAi?MNlc|!_nzR1)UF#pM4O{;9fo}}pAj>}Q8c%^cVx`Dz$@pS4hKIKz8 z>PT5oRs~38+?Gtv$z@1&)3kY;I9wioVBX<_7{NEUJs@1z1(ww!E(mXhFun&c7|xVL z8{8A7CMJJYRetTCs&dOc&@rNH9EjBpQ+22QNpM&{j+6yuRe-f@IW z*5R_CtO}5bG_;ZMufwCy*lNgr5dvwpIsy?~@+qG!^pIheV-1rp2oZ2`CMsR6 zV!=Q5-4BHJ{T3S1v7Y;lK1CbH(pGf@$Hl-A(p^&}P#%<30o-^^wk20X@=l8-57wLk z&3m?H#wi1+1KHC+`54r+@w$m;2B=`n+L7DKqZ@?Y&#;tefVf6)2g68R` z>lpe;HKe*Gyz;^`TWZpPQC0=G>+kosCc<@Z!ur?63#;aNBWDhx#`Of59|${qnOF(i zD8gRKl#b9==k$kE)tEv3V$tA$hU7-0s`l#-s>JXev~e)JlRt#Suu9lZ;mjUb$a%RH z-xGR^kv*;`l-^rqv9Wae**esBY;oXMsK=Hp<#KL#kl2Wlc6*}#HRZ%~hf_o<}BB`4gT% zFeSf9WjV+6YKw2eoX?802KiPb2&yr<8&7KycwpeIV*61Kz_05Y^D3aoz@+k?U8nU-Ha+*I8eFr8i1%*A4%metqKJ`hnwh#g1 zVCUtr&_Co>6a)cEVV%YSd|`ou;07=9#jLr90sJw$)$x8_6TSq|!Y~^`uxIK>^*XGpHoSr#!})xB*f5 z4@GnF20FV$NdBQ2f=3^HR85>XQJs74xoX9V6{@SNi!DD^fMv^;sbh{gh81J>?Af}6 zAUkR&`qcf&rkxz#&{YPMT>(;AC$}~-y3_P7$RycQ`V0dC(Y}M~gtbbBYE{jQLp5<= zXlZFtC!c&W3;p-L_dWIIn{Vor;=t-~>#et{PkriBs-Cmh`HgaI<;=v zadg@ev9P7V#BCZ-j9x5mdTsh|((Qc3!0Fr{3Xz|y9wjTh7PBXwctRa|=%H%Onl&6R z1t`LfJMO3!ELfl^G`AB!MfI4TsS&DkO<5j^D7ykIS-LD!Id1yHq^6|yGz)9s_UTW5nk`v#bF-$FA5EXT zRApk)AMPhPjNbGa_gfIRIf68}AiWq&y5RtPn;$`VDLPNv=-t@|UV7;zb@0Ild+qmx zEQt?RTC5U4e8WsVQ>_H4k-S?-yig# zfzBJDPhU&{drJBSOwNG^9;lvs?m2IwDk>`YP8qMBBG13@f^yxk%2*HLrI*jqp@Csg z6ktSp@ig*u-TfEJ0$?ju#3kw`shWv9=uG{?SHAKU_3X3H>X=fswY7Yp{ru;PzoC1? z2zf}WH^9oV>#n=U@=zqEy0$$AF(GQO5;K2j3#w_zgEAa~CFigxih)ramSDuS z6Nqvc*lGFs07r!@Wt)D&2`8`*U<-Nw{r9sG0ni>>`EKyP|NFnBO=0E6s?i0E%ZW74 zl}BXQL{HNF>zZhab*++j663uTzQJ@@+B^UYb@omP)=h$^YzW!G`b4Ir1~nOK0e~p_!G0 zKQ)chkOyIM+$0j{BUjPD=OJ71alV=`VSq%p24DX!H=>Q>R9F3E%@Z@F)OW)(9Tmyc(ERhj`Roif%yx>hS!I|; zKCdQ1z$c?i#Z)93Q!l^#vUi?}$K&dZGtS_!0r-wQ-2v^uNTq5g`1cx8o%mJ00b?)} zfHr6e`Y6TB-ovW_0dmZ4viLF?mq3!pH>Fb>lUUx!T`V45yxr{_6ImVn=e5qzEt zfXbU3DYu&T?T&i=_18HGXlQ6qkx0I6yycc#bf|kg^2j49RxjV#=JxOg>@t8xS6)D7 zob&)s=!T2hd3PB(Vi>QPJ^g4im3;>G=2u>MrH%=(N5$p0Qo!~8efHU>;BIAafkW|k zzVjU&D-Xbr&^8AXKl(bIhI8<3E`qaQxLy^J#EKw!__8*|eZi-HWF<1^0C^Z5*?0Jk zxq*vslv!A`XpuVe%riYhGkWxBUJXz$uDaQH>ZzwyJXXdZ#!2>uj9C3jBycL0fIP&2=G7~&yrL#go~#xwT&OAi$EsDU@+{*(0bcN$ zID9K1lm&*@M)-MBBxry+GhoFKhdGSs*GJ$|va#^Et`DJyupe^BA>PApNXJ39t}cHr zciU|@9U_U+idAk5iUL?{=@GExupUwd(vF`d;sg)DVS{0yB`QZKC)B@X5r?nmpMPG* zd|+FI>(q}u_84Eg$Kh-L{r6WhXU=57?G13)3+{D;c=E|7b*OwujfV9smyiT!vDmB@ zpJ~i#7o7nR+G?w<@(dUFjw@pJMTdh9I!H~MHqBEM1LQNn4}{~3K?cQJ?mNn^07f{A zPK37do+I#}DXZ`Z-O<||t30fm4KNgx)VMtevHwp6Dz*LHXSD7yjx@*2J(6Jhp=u=Li|9K&}L4+15EwINs4*r`PC z#e@_A4zt0lKm7p|7`OHDSoA&j+@to}Z$GAo!(nyB6<4Sq{pd#=4+4)=mm9H~M$IQV zpxO>#<7DyI4g*08Tol@H1re-^YU9tn_UitT9Xv%lW=!F?_Ha(P@x~ij*wUUkH1&O?5-w*Oyugzy(mTHk?v z>XIc()Y!4b51`-r*0*#hA2?8#8&1Uk5kldl@BE=k*yNF?bKwdV2A&B6b~uQj@|f4A zW6y8y`WD0X+i$N!`ItL*ZeDwM$`(()YGhTc_CGp2Ae3DJm=FBWk}$*@1Vv%_;lM1z zFpt?<#QiZAhiApemzP`RGrqTo#rpSxC&2W5@4fd{vu4dIdDRFgHTm5MMSp=`j+ZBI z!A1DC1FzZBFm%jEajs*S_B@$zPrzJ8GPHl!4cdp%`2n=LFNHc5&@G7kUBgd7&5P3>^pEN4tFN|16+}~>#n=l z?+JM7u^57uuRO5%Wl)S(3PD~lU)D=_^lSiCHaKo>|s}1KNJZxAD_5}v`xC?*j zrI&CV0FTc)>nuuiRM*;Os#EetV-@TV6lGU{_vbIjI^pHa-4q)GK zk^HU;Kd3SSIE-wsM1%60i;)bJzC{+SL zxLCUXy>3}0P`{%xtxF_}25xHMOGZIp1pqJbj1<0$ap8p*dUx3|M|eD)x0qCasF{pO zj+9S1$>}@KEWC!@50qU2fLuk>9AX6X*=TGrASLK*t8ZHdcF2KbC>6OZme~Q|#1rxS zOz(jS27d5^A9&&JfIj0}WkKKz;P{Slx#94Si-=M1UNH%ld0`SAJ6?dE$5afMCf+LP zgDnZ*PIgf$-w~ zKum6`cxYW%p8*jh; zwz~ZC%XQ2L_O!qM{qJ?GyvSy-BH~rFv|S))j1PQp((o349L7IofsA5BTwqf2>2jLt|s< z_p+LC;Ol>QbRsw|0N-vZwig~K&{mEtWR`h_Y1LCpT>uwD%th~-9ESyBqQG$vl;rhY z`=zbFz)okAmZcf&EPby7H@0vy5RW_H*(=|wF0k$;w-fwTw z-Rn`H%y^#--WP<&A%eiebeCM>U*RYx(01#*mq_&3_Ub=jkC>A}=P{4?D|01r@Y`5l z`RqGTJhRGwtw|~15fWUD!?q{S;^)Cp9jlj+l4a1tT&}9=5uGq#42lBe>c>GlTQqwG z%w)YN8-X^0&S9h&*E>Ypm-6q|4irZnb(A{bfCF@_d*JJPbLJF&Av>K;^S%|9zu42H z*fwF=$0fnCgV~u=u|+SCkPx4Vm*y-0x7Dc^``!QL1dNoUi0|0I}q2+JrdYnvb^6vTHmKgvBMFE`p@x&8Y8sUh)v|$3s zBZ0@eBY8yZX(q8X>OHU|b}Y(&g3%Q)&LuyXMOHe^ zVWVhZX&zT?)(576!AupAur0dxv$Yh?xk%8f2K}Law1X`YcIe2*?NVKC=Ngqw%e@JE z?)r+ZbuB8^M%!J~8?Gqp3zh~&0RU(0P7i@O#_Y)T2MLL}=nFF>FD6zdSJz48@cgG$ z7T+xDA8!kQ?FzOxxM_ozxb_A?%MPo5&N=7ss<6{ec&Y2)0z*%}{-DPKBWR^q>nQ+fk`?+Tx*lra5;G99Y@tw)gy#IgWw zVJn1}v*N&u7dsVRn)8ADPy%d+uD||zJ_O^|eox;DD;Lu3YgBCEbNy#Qpj>w|Bl94@ zlbI;X2Wf0;!3Ssn5}2-3?4A2~zRWkk?DBTF6fn!JugFz8%ALCWrhCi!Rl43wVIQ&f zA3yqB}D?zx{4@(cB|IBAT)2)IG zHdZ}#v#NUTD$lYHHZYZTTL}8IlOOAHW2)l+UR2?bT>UbuWza7PI-GZ0KAqPZ6^bnQ z_QE}Oz2U~+cmI0nKA?xz`;T=WzP@GjPhWhGHYbt(G$I0r1qzk}KhFu8xj7butDLhR zQ}L$Fm zZ`Q)^Ukxf0_(I^dDRmz`!(k^BS+%Hk=Vv)mMhuz)FzUu7c-K+{K?Vp@yz3BzUNRi@ zkaKex)$+IVHSv>ywX>g8(Plhu0IvB0tXbj#LnXZ0Ie||%c_qoL8bRLxTNH?iE|Zsr zcz_TD%|GrSteHEDw`)fD;czfEK47Pz*0u$&s&G2V;dI@&zwi6`FZu6SFB1k;0o>_F zK1~x+z#$CK_~H;VlOnziv%DJU;ubJzSylV-bEEMRHZ zZNajGzH&xh3yxkg<2M??84VP;YS|h+YW%zt@!uN zDyF)qSyws3wtjKS*RJ=!BwR)essgCW#?>U~)F zmB-$aX<1$=;)#`N`6IuUjGG&Hph~qbeoxiC{wJYn{`KWrLn)ZK2+j#uZG;m*vT^iD zz8JAmW62Uj{wY~_;SfI_s!ow4a>?k)JG=iDLIS{5ca;~a<=|s_>nst4!M}tpsKplvQmXzo)uxIziQR$=kQdxTW8pa`M?6 z86*^{cbW0Z-M>C$yZ5epfJPI;ey$`#iB2LdLHc9M!%WlQI65r84Mg(?!ZoNw!(>(c zwZE!xe8b(PEf;cREn6S_iHg1c7m9!p`6Ct%(5NAJ#U!~GkQxSp!kGXtmzZ}wrIIBS zSIKFID|gENsxuc>**70hl^;IMFTXN1%m6}v`6!vxy(0Rr5`MFGL z%kG+E!>$=2(cfJp@t@w6eQQMTT69L!FRnyzZTdb@JN{eKhO#(*`C-=Jd8T}OPt zIw)YCF>fS}Ut|~V!I@kJMDr9UkVbVBHUEPE(^r6vArmmmvKg_Gfn0i@Z+^Sx)93t3 z$IFgE-vTijCKSCkX)bT_MCv)<2djt;5cMpD;e&)}H)nzXle$H8`CDq;bw{gAa^Nq* z-4K9~tor9QB>eboG2%v+rYuWhZl21NT;jklzGQ|ih2|ylfro5K$Z=lKr6fPZ=5028 zlw7F^-KF&e6qVv=UppQP5<&Mt?Ktjp*Pb)1u|apX{8%pvkePb;Lo`)+T!t`Xt}rsT z{P=hAI4!0F6tVU$aSO-X-Wn*L9PBG;%Ru%6B~`3tp=$fpA>N^DQ-EB5S8CPGXRC@? zzvJ;US4{u2#2*mBNRXfmmQdp|fp8FU$^iBo1>u=MISMmf1Q6Lw^~Daq{XwaEym1&` z1|cC$Ls=T)DH_o-0Cdl|n>rucAttrwF;bKza-F_TI3o`e?Z z>~Kkxgg=u_s~jB|*&$4S(azPX?I*jd&ei#EEZbOtAva%poT^&*jEFJCnJ1bp2=YM_ z0&RF@*o6Bd_}6?9<-qyNE6!y(KUNba_`WzO1yjh^bPZ3aLGJ9l!a^U8-f_aTN60G|Z8MnlX87ar3gZ?MqaYm!phifXptZ{Fb<% zV4iAc-c{rM1!r2rn=lLDi`-W*O!6#-4(kx-Gxg#ekyBOwxli;qz|LgX;52f!A|Q-xCJoNO&I<(d;Ech-&v8-#tPn(F zhaM3B_{;WKQ78>OXI|SYMgYZxzbA!|bZU`&3RUbdJp5HjDK7^8#n)cqz9(lbJ#+Vl z&*w6!(Zng9AbfZOMZ8x)N#urAVFH0`vzXdLZInISu|j2EzEicex2y2D>9j*z|5u4b z(CDzAO{uookE_(5&Qg)Z`i?&hp}SEajpa?}%Zr1r6f6nkA z{{gHR$b^s%mk*B9zM|@$_nn(px2}`BW@W;9TLIqvU`bbY+-|p1gBdxZk@X-8jth4p zzP$rm8wMC`m`pzQyVKwhQ|VFH$X6_Zo9x*7>3e=ZO-IXy^`-#8^XYBw%DIsh7%vZ+8R)Ss4?(5?pux&Z z8kSy@N8;H;Cx?0io*Uh8B-5^<5B)&3|NK*G*<-&`>8>`eTdz}Pgw&WxcBs}lFQ|^I z4^!^#r>Xdgcc?3rLjUNJjLV)H-4E>nMp$hW$Q$@okWYl!rhDb^#s>|SU-HcrITM$> zVzk7`AI=5LGs+;fV4gsx7;lv*%;PGAzj6zTX3J(PlmEVcrjC^j`7N&ptiAf6Dg71|3g*0_b8R5gCrG)AQskyK42SB42J4;p1Mwbql#qX0Xl|5J_%N^ zUMW|I!afuSSXHQ0N+qcD%PUb1_Au3@I#Ov>Syitb%c2=@{T#xT z4qOAz&%@S;w^K+Gfyy``m2TQfb!>l}YMQ#Iax3aoC>o=4UxeB)OFsmW>dvP5cMGz# zinM+-SE-loP_e}?t8g}{+m&$yMo_dn(z-laK~_;()Nl8x+x|J> z53X2u(C%0K{Fh~WG@^J*gNUYvdS~I)M?4f-`0AnEwT=lh07Jl-p1?Q1GHJf+yDphk zHC5Fr9JPM36;+@fFc?=YFaelBqIs4LZCNwyiK zE_Kzj%T%MX0#_) zo%ph#MsQ4k9#ZOuv$FeK^~ju;G47;jjU7Koer)DrSU?BOpuZ%q@*MKT88M-aWM$9KVD+9_v7`QC0Fr0w6 ztPBn*oI`Z>X$7J^7|})e0nW}f;Kj2bn7SyeeHpF@G7|#;UGfMdE;Pd{Lo+Z!Z1VU? zpcT@E*C>UHf`}kZ>R6L-)TK`>QENLAsw0t7552ie&A9GE)td0zn^coiXY4VWLQ)q0 zcf7V#y|BbQ=1gr$b%>CU0J7n67r!1E15t}izAo?n@a&U%{&kW*V7)5u0=Wu)ejjoxn`4%@>(uKMg<~u8UWwg!!dZRZ&;9btcrR)^(ci{2_ww7xM(3TeavQ zm^kV-`Ft3GlD_bL3D6{FrGX-O;B#H}U^Jvpc@5;DSQ!JP`Mfaw@qItcpO%9N7%}kM z*4b5kOsO5lRCC>?{zYp#)$w;P4)E$F9UP?{YjV*a=^ zeQ>R0l+4{~FQeqJK-O*L+=FzaEZ86l0L&VD!VhS$DPoljnt^~!q+zy=A|!8OeNdc~ zK!qYI77nW#TC3B^l=^5z3yuk1B`g%WK6o4q)SoZxRz5v32#ZqjDCkemres1QJEIh6 z+9VenA5eG>@PQV%&LSwzFQFNJier+8{4{y~2x1|^%@?cHJ;#kuH8KCS?x6i=L5ups z+etAd)F-?q@$bitQOC@jtaIhmJImVDypAfe@;Y8#az&Hib=pAdke!<&jRz-2CD$}p`rxwXh_x2N)Vxu z&Rf!~y3FtP%1kq)RB0e9a_8rRa7db1Girb$Mj?f+^P38E*sr4y!h;e(Qg`VZb{$4v zY(r6KGyu><9JoB!0q3ZOn4?}kduvr2msdSX?KySnzZR(kb~(sSf3WnoekQJda4_Bu zPRB74;Gg_^akt|&3V{m`{6bx+TfwbLE0kKsinZhX z-K*6NM{UV%Jn~+P${1!BSad2$NgkB~xbMIOCK7+mLgqMoAbB+MD2!#5_qMo1 znog*WWJaw^I4RU>hd8*XO_b*fT zzSYd){?>WhtBF!hC%beweI^LURTZrQwJ}-^DqPhVcU2;lRZq@ct(seKrAUMyg1_+!e{V2I(@Lyl zgF=6|eQuOGb=Q&1`|D?|(7c228=m8egQJd`997RRrj?c^C@B1Z7&MtLI~7@Z9;wdP z7d4Z;%eF0@aB$y#(z6$^+uWdNz2OT#iY%Xf5p@YtZZXpbkvzzrkOCGB3s_W z5Um86G@Z^;B={NCmXwvCwTo7RWLAZ#y`9I`soIJtPoGyIp*%`}^7&&b4eqq(qiMqq z37d4l&xb&vU!E3q)iwUvt5KU{WCrH zeE_UaljVPL{%TcA=eJPP_=xsOi3dcJPM}By#fvrFdg}60<$6^FVR@Qbh=koX!&fj(k!hwn4n*n$_jkZ#0l}e@f zptd$ehvQE2>0E%-po83$VR1EWbd8Gek2@6B*%Kh3qR70S=sx&1M})$z7hxZgF4ms{ zoXr;|-{%a7OCfw}U^NK&`6!2Em9mKY#nCUJNt}Yc0cA|##a3jkqr@j~&U%3K$H24; z#d6e=mJapmqBd1msnqa_kgA-t<3G0h!J~unz2M#sbG;xMi8zaHKKIJHc@KXFSCt{r zJbAE;`VyKyc@{8<@c4rq&w`!D-p|VfLpX4_!m~qoc&(Gp0&7X=+i1JmLR+GBv^|3B zq;-B`Lrm?yMT2sSJX{w9_t%?TX;v&lnRuxrY%77XQAyk=M zOg2aTI7jf&6Z}lYLcOe{2xQErUqRSuqJR`(#WRq0c{m0-+>`Jd2rn$aAQ5R*Jwp{D8Bsney4w?$Ei*j^6cp1EBq~offH7Vm!iP{Lobj==orh z1oOfInmiA%YGjEK^k>%(bDdZTXiJnys#H2nRzIiO^=g2pN_jP)!*U1hK(QjkNCEbp zRHMe$S88F9_PjQ9SNjYj9HwvZ@&{HFMn=ub(ktZgK*OV%hRG*Ifa=QD5oZx73Brd|*sst($Q;*NbC99jN)I#*ORG`%tQr*G}3vknSuN!h6I{?xC0S~;PQVTokt zK$Bt3m(BZ9^MK`54vr{mFaJ`J#K~bh5u&|vIHn@en5rS>H^f6~7+fWstA>-qWm6oQ zApnofZBe(pv{XI(&PsmPi0j8T0TtVAX&523si3j5`-QR+V*v}+!_ajxP=vC;A*X4_ zM$x_$=_9w#5V~0fKsH-00ag;N^hMe;<%>cmVNPCIv_}2)^<^rN&8SA=Ie6W~7bL=} zwj$j6_LMIlBDn_--Sl+Be74-CYhIsqnE;qXc}#sge$X^bItT2808Eww=yIkg8y+1q3S;w;Df9uF zq!+E#2j!cyqFw!$wv@$+rcv1rXh8anBf)oMUq7Enm6o9rx?Iipi zM1vyW0G-I>XgQ~1)NWH%MC~xTQcY;AR5ASGJd9tfJ8eD8thu~tk^_e-(o_WMx6_NH8 zdk{zY^eOXWi$AlP1%P8D1qI7{FJP>g=TI*#^*9JeoGd?48VymHxQ258d>ooXZjKJn zl#jDJtRVAOcd7p_X;bsa+EvHGs={^Ya7`5;5A_qh^Mo2c_dtNIOPWx17NIdkV21%O zuJdvKP25xhSaBv%pA9&qqdwI~F&e;IRn$p2gm;1zt&j_wJJbX3tWt|x5_}~M4<^>p zmIqe9ft{=ZRWUc49lq85r#;gCwYdvEOz0{G6{W_rQK7N6%6<3pBQC62Is0OY#>7O) z{+_`S!`$x!q>g;pN<<$N;gv*hiSRrTzTBRmZ4s;(EI(EOY>#l?0INhNWlfTg6#@6s z(&Xc}v4})VyQ{|4#ne_!F*UxSif{6`+>izZA(*CDR!SavN-qXe#w$bw1i?aY`(kKF zH~D&i$;L-yT^F5eRdZXHdTnvL`mi;jqEt6+>-o7Ww*2Iaz$>=;)nQ5}Ym#jk_vklg z#gDuF!6)0K*1<y|b6Yd!(jJ((<_(EWp$Mp|D zUaCt=I<`hQCuCAY6D45Bia<($GXW_Flp;Z{lY}3BGV78h#5+r~S|PASAVHzJwy2A$ zy(iYwDiOurmsSw!j~*L(BE6J;7*H?eleC2`xd)Rkk4O-DVSeN!0yV~pm)}ewP_|ee zqGyOlc%@_6pRkQ+Bdo0_vashT^IJkAISd^jY2jP`?U^=Y3E;iqE}DLMH>r+q#NzT)p`;LRGT zil&cqXWV&UCxFea8D`3gAT1H!$MQc+uHmpZ5963H4VJ(YLn-LQHC@emTiTpA+i zGUsCHZQ&0pLS7nqp75hQ`G#qd2MHvxPzX{4C`6hhI7L#OghG(OKq=t!D#3K|v0~8C zfmZ_@7V*s~l!XGYB2e8>3@8CB1e&A9O;@Q!?hDd|L_$e@Cw*rhgVxJSG4iHXStd4Pj9Lj^Lj@bX)@=^i%Ruj06~$ zC&3G(NIE{Ud53a@5fe*~I5}MLg78yXgajT+0IQC#3qt`aNcgd@hXP;)fN~%l3WrrL z6s9_`?FqG|w%GmQlkQq@`om8=z1|MI#o&*26U9rvI(xrqEwldUq?7t}1ZFzn7h3yb zu&uid!yKKHyC<4wfF{0xD%v&A4)I}B_TQdjR6Iq#>_Ss7sPQ3C4 zZg>L&W8LKO;Psd7ykGMpw}-o0wxuY30)Sx-wmm5TU(xLG%UB8IM*<<^9Ot^> zlR%>_`oNaR3{!qzO^ZGM<4^jJEIbb6p#b`dA!FQlvjc=5TPYTPqRUo_wp27W2)(iX zbf#qsk9|K5y>NIDUl?C6#nmi)_X1kQ=MpFDRMfpTYuJHbJn$PoUV!E|1~4Bs2kg7^ zcG0^|+y1vTE8aNK$+>YY2PMG*t4HrC2>o}@5J|P`hLHHBBy6XHhExbW+GH{1ws0j$ zwoLqcxg^mf^DOv$-vDv)u}XL=0Eb2RjS@ikskpxqfQB%q(FXxx^n#Tk01e7xhH;@j5f(N`M8lsK7}I`mYaYGlS7yagdpf7^t8pHl2RGh?Ko+*)m}I5_R}XX zcxTT0gYzTD{RH)H^TKWCpLESV4Vd0aDqwAi zAlTFw{v#qgN?{sg968yd}2sdFK8%9KCKuz`fyyQIk(**x7VC_)p^|1Mhfcw z=818`8=NP5MPTB9oztc>bfsQ7BZ&Y6 z2p%~ju)(@;n1QI1OcAguAb~$PGk>E^18V{=B3vOTw3ni`y}Q5UWLTWYkQ--Ky9nsV zo+03z6M_v5Ff<4|!pMv}b`+oh$&!6gK(<5kei`k}>zOX@-dz3&) zPawFSo?*)M4OS_<91LOJUdh(P+v9Wtr1oZ%Mgeq$3K|>F1acTJZORbgO(K6^CB!4I%4$nA2}oj>~52e)5!{Y~?A zmQ5DD;mKx=SwH{!`BPh8{YEI898KrQ2(Ds?kZH)oa}b{p1ooLiKpJS>2|EN;|44)f zTTqQ4_XHMt=?mAFSI)GJdUabR>!rNhHu{eG5QfX|C-3ZWF)0*Tmu(pL+T0z#e)(>n zKH>?TyjehV^OKE<GwAZx)k7grdigxo+YL;-9i@D!{# z`&r4f(g{!>#ciRtt-P(Uy#kd*5w9HTf-`+2ORt;-nJN1``p37sZoTQ@7v{hH&bzJ1 zxw)aQoZGCi{kBs=H(hZ0w9zf^o>bTT-WT0u=h&Q+i?ZRR^nNibPdIIXD^^?YS}_V@ zD~f~>>Y)u!i74I6kB63=)?8I%b7spu{+XVz%N>_p`OE)a^T6}#5=A&P1mLDC z&TrVYx^1UXogaO0&m-6(L9t8+EO5)H_hj- z7{$TIcfS4XCUTCO$;E5trfNpbb4N|N@0GQcFCBc=#hd(|zOU#5w?CN}J92~*4`nO< z{)5v#HG1vb11s8B9O9%pMw0LiBj$zj<)324y5_N#WR6IMLYiNCpwnS$GtH2$@xu}% z_RT63>B`iMSlt<^c__KXZja|iPkrw*r<~m~=Yx;R`z7IPAsG0a9>Rd|z_mZxyRl{7 zkyERaO>W1U;gPP^-Bq%a_zS7bHBc4`8%2<HX$|OSL#*7~O>&w4CBbLRzqMT||l_ccyARJqJmsEkIK7^NO;klb|D0kHHC%xb} z?ixIR#?RA3`0=BEj+31`ckTxJ3gHljFoYotVF;T8l=}a@qv2E66#*0g0000hmG$@@*cSx z@6Y$Icz)Q|Ip>%A+%xygbzL)OHvFBY65$i-CjbC|P(@k(Jph3IaElJW#eTS)yH8y| zT+p1}E6D=NM_=qcJYZVOXvhEnRk8RtW>^o;c;A)vodAHR-H$)Ceo(O`0B~QRA}{m7 z-T3ep$B(<;g$`HuGCIN9I0iuXTACOTuFk|4s6xQNp_Mqo5b?A+zm8k~SDl?l>&1ex zhpsVd_Ieeu@Z;-naOd!)mlA6*xBN=xn+sLcZ?LomGOabFZcacBN_1d-UdJ7IT9JuJPk#CF&|j~(Bn%h4NPVa` z=s{0Sb;kGmwAhXjG0q!R{Z_np>6f)*kRvEfefA|A@&8Vh?fJv%@{C!_J|`oP>j}5s zRaBi_GwN81(^#~2v^TS6Q`3#Q`L-}J57&zJ2V^z27dUs94InxQh`EAJf75RAeLXn)Bl5q{aj1UB15mX*y&-CEv@p8q`UA7b_EZ3!Ec2e! z#T-UJGF4JxpF|?kwHhKde7J5yntcvrZ7-?>{o*gq563!S+dA=RfyriVtB)r$Tjx8pv# z@|j4dyxwja(}I3tBebfD;%_@PQWJrlly2Wee$Ze*-YTP6jnq0+Oz%z8i!F%mT+nO! zY{eR<+W8`vrLONBN!~rK&xRIgeN1YNNkM5qiJ-fM4s(v(O>-`HhVq=y`R*^d!#Wh@ zHB7UOdwnx6ku{aZa^0hUTCa3xlFVO)SGMdbo@F-Pov!p1G)TSk`I~+C=2PqDE&VOd zHdD@HqG|Fq)^Iw6n8T3thAXJfb}yszsiTvyi&Zae=dD5fjhREM)PGe2h*I&oOPuRo zzD-`eL3BX%9we8#X;ePX=lg5hG2u(4#hA8#E)B=XnlYcYKmSYL4fz~HK!*QrtrhR} zReG6-4&4oJMfB69d&t#Vw=N_&aIun>UddU*ev?hulcRf7G;dwTMiQIB_wVnI;R~CH zQs5TT1*kMPD`bEr_}aE?+c` zEe<)pLh~**E7Ua#gh$v=rM?iDbe43PDw{R5t6jIsW8as&ElfAALS2H|Q%o5CZ`p@{ zUnA&Tk>EYNDljNZ5xiJN*6+@X8Pm{vZVi2bow^?O_IvS^dh!d6TV;5dm{4&9nMjAo ztcQVcNwFoHCQZYx_a=w026XHuWIseMEH5jG9Qw@K@h)EWgIz#Kap^}?%K$uNssLc@ z@a`@-4T-ZN0lAMMQXKO|B!96VQ)spK!r%hQaXa$&ND_7A6pLq@FLv0Mqmi5gS!8W$om@UUj&f6d7V4;{`m%zVms8BgGpYxeY1e2FA&iMVo z?yt2K8&S&!WLENWTC8neXYhZCCH|0DGwc_~K4x(1)oPc`!oCTj565?_D-^Uohoy~+ z+vVB)w}Zw@IoMZoRrz!^SAuuGjKno8jyFVfEt20_NnKvDy;3StwAHczfzED*E1LGw z#Eu*D3^5-8zsEuL-mOI~V`dJubiA;#ldUJU>~$=0!1;h8yJGhna;-Cmb@2z~C-C7* zzWUnk+I;6;+(6t-ZX7kTA0kV5RLQ72hIoIMSR{@dsG7iuQQFxjw~=dY9$?;=KCz)- zEt2H}6(YNAb=z!g{)DOazjw-bpjU>RjtGoR{aVh>`XnL*A02IN_b@n$2evFAK8aPf z(rt2jntd>{sCt6?yN=2hF~qY(442#O_ADV8>z*vpzkJUG@{ObNaer5cTZVxLiwUBf zsKveb<;i^<75jlgk&RR7!q@{*c5-*9+iv13@L%S|U^Kqrta9ah?XmI~bi9mczg523 zWvg%~uOX?gPd==+2@&8u(XvR-D1$b3!(1DQ>y=HZ)s$|l`Aj8q%7cWYc*I%2Tf^I- z*HyUd9#T-(Cccu!)UWK8F!xWUu%u$K*G6w@T?}r6?fMm|Meu9>qtzDzLu7tJ0csfo`LQ*J_4T;}`cB86KL zT2kgf4H_uaFhV2k(`pc=9upCsCKBRlyi>B4I@5KNJhu3sOJ8X{LR6vNd%ool=(O3H49#DLX4ZN zeDvCFSUFlys)&J1gzy~NvF<~j9=<+-S-MV1OTOr`r%WY?Zls1Y5X#GL+E*Ke`wpktIjy2Ke>{L+bqIzig|LefGDTRnx)w zZ7Zi&EcoKj@%n1}jKu9WzE@`Nktq;<;Ixj#EqD%~UrDIgWgHdWTOVD0@7$4KfED(` z;+~N>VmnJ@>c(3VnGiyr6Z}I;VD+2#b_{dMednL{E4J*5|9cI3A{(IS`NGjm+0wC; zM<{Cj9%Xg8l&O0T`NM4*+m#c!E$pOZ1 zEO~c8oATmQjW*wvX0c+e{ zA}jl6>8Qw9^PP{<9b9ddef59zFZUSV*m{jSZuVjHS4RyBN?G2)cJ!H@qYbaHiDzO9 z--QWl$6QXow~DqN8m3vCmYt!HY)<+@5R0U9-Jj6dD9c^U~P{x zVv6xq)RwB3cq6v_J%x8%Ebn>}!kSpV3(k({iz)X=V3+*0ylnBCXd*^@^b?%Y zx<)a668f}-cVZtFcZ6vhH-6GwdLs_Dfw+$%xQF3^54EXKbj_$=SL?u*8p!2hMeN%% z%8s?@epe?c3l^Mif(w}6m$%qH^?_`khm$Tt1z+S;e2o0GNjBXCbFCo#t3-yXXuR&D zY^!u^lTnI0E?)_l@xu`{pADG*dR_2o^F z*e!v0Y$%c0*N<7{BqSl)uaVAL-w*wgJz4jofFG^;k%-WKYir}Hq1hAfPNn}T_eZVp ztmnAj6_hrAsoOA3clFn8Ml7_#FU=5V^P|Q$IE+6v@SWw&S^qt@z*?7@q%7Xhm(;x^ zK_e~6e(e3o^t_3#sq2N#!3j^pMPx)n>s3+(xaNNxDF5_v@ouMPaHFr|1x~~CG4k@n z-u0rLRM9b0oOx%ncYx4LMAyO)=lBK<&TUNSscJ^8?4Hd?lfA#Ldvl|OO+56QF4=48 zckiE)!J)$~J&DrHvj~y)t8F;Tf5h{eof1$)Z0x=sJUAE}3W_|wrfitr$%at7f_;dR zwc0nvjD$^wn18Wh=90|NdfMhg**(8>>@{?`KTqVf8-OnRQsj>8cX;O;sV7nB4Rf{> z&qq-fS=olNu^lWgAS>K&BS9^Dr5Gkx3vNT!=#Qlwy68n(V~<1kMixqP?)sXywf$~m zdA6^0#q(36v98cjEQ^ z?sxmu-5mlvxvz74+x(#V>%1-h(^XaMK!7HRxKBSQdYbp(IQ1P=ZH@#A~ zaH8P^zlVItm&zl==;&Lwe)W-onmm`Y+<;M2<*=&9 zQrDsHmm#3#oGR^kv~Q2krAcdV)98FFd%5nFfk<^T?N`e)Y!9kbaY{@N)z0sxdQKj{ z1;>*7rvJu$J3;%GzPt>jClzz*ZQ{AfqEh_EK2n>2aEJY%MeKlDT@UXrZ+a_QQ93`0 z9|geZyTk^7v8?$0oW#Mb4$<+zT1~}&--?VGefs~lNH>*W=nM`<-|756S0UV<|)9d zoP$o|uaLl4Sui;X-8yH$O_{@(#?%3+SKw2(z3{!u|-s)$XDs}KOf1PCj z);bH{t0_lGp9q*h&Ll~=9>t1K%ma@9fQ?8rocx>z?<_8Ff{}fyZpU4sjuuDR5T7N1Wc~)#6i)?`NWx8JIoAO~t

suN^xsYzn~F~d%9Q?5-e%XnG26`ig|$RKaGdDM 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ÐK77Pa#O+GofY6|aYvT|}N|!P3ey+DIhq>YppF^68ah z8H|-1K;wgm6)w5a7#MUi z`XMFovo{nXpT`yFnQ0Mr>~nThwd6W5SdtGfrbCjo7$O;CgWAx~%AoVCHk~KXR_qhC zdo56u^>aF+s5_|s)-DPnQ+;nj-YZOJa{zy7nj0Ez93zxwy$j{0pbeFl$oTok3L<-Y zC{X2b+*zryCitV2$@9qaTHQ`q#%_3Sxf#B5WGNgt-3)V>5Ui)hBqVi}9@BEt6k_lh?obudcr3)#Yvf zRj|tNC~>Ld>+k;6T{}BR?wC4!&zmbtv$tUy?&Mt19EKCnZEc&Mn8TQ`eX9;negEmV z1qZyi2snH}?Q;$n99}<`iJGD8ydJER$f00+311+MR%Etlm;W(O4-ATAo;?pB*NJ=v zJs*I4E^>1Eh~?OoHpj0A|K!~Hk|1;Z`glNc*Z_dxj-PU1TN=7%+cp=r8DL=DtxU@D zP6X53ny{{Xhk-Q%2ap?ZX|!{)7Pe1~hRx&kFopE^NIi^V)#T5gYQblJaA}8auI*~G z_YrI`O_rekk^qU=Kj1KF;_Jj<$+O)6NT|TN7*M;{K-M0}I;rti7_e!(Qw%CYtYjP$ z>9{^yXgnb9D^n&pqI^@qF~hk*I@W~%!Qwe@`2GDw4D#8fRyaD}3I}GE!@;?Z^7*De z|E7#NegACVz9B;g?ho+Ua{v{6rH}dC5RlK95B}Bo_CE|-(XKJD8~_2S0>z8PShv_;{<+_S|N|KQo8u7wc`qwXyn?N5R4|-J$5Wd#927*6OB=D{PjnEjZsSlIxb*Gi`iWuhD27z```C)d? z#HK^%Ok+i<7_R}8eL2^`q_7eqL|aFP85%l^>g`NPIeUMP@0}XCUav(MRkjDr4b;1kxtM z{-ZpD95lqtVbgJghPS4(H|Nd`fL+z|nE`&y-<&-bSZ*Q`IolM_PSion#Z(_Xpa$gI ztBiRiW^I5vs!1I#%yzC-b?|xina>qlzdL|5zfG`nq7t@@kA^K%jj&?^n}UfN7UQ}W zTFS7s>>2M9_76FP904FF!+iB;3ThX5t3f@RfvGf|;!LdO$Z8(rwJ}gKX}5zUYwKgp z;WEr4>G`QH;e9Ejc?G_mlLRtqq|SrOJ3q-^3t3%LdGNRi=wXajD%ejMx^5-UkW!UHaw8hPd=w7ovd8B*8>;LXlW9zS9{rCU%H&p2oYhs;4rNpI< zue|Hmw(bfi-m>Mur{CJ?bZ)D3dOP&vE?B6G8vssHJN4=5=cJEhM7p?{L%5jm`mtOu zyT8t?Q|`bA*Eh{~n3a`!a{T5t^E{@VMyx+>4j{`#kB-^y2+)Ds1A^wPd3!%Pa0I*3 z2M?P7eooryR<$Xh^VUZP(x(pXk;jbyXvWAhn~agiT0x(6?C{4_P%de14ERqO`?vsd zIQL+I4`b>Jv>bFB3n??kFf^{+HWr?U=4yoX(7*y7Jl?T_;U$nITInW zk+ZqF?ay2MD4UMlZu{5lc7Js0b~SIG-`ht5`5gfJNWf(I&>tc>eqH%1fCo8#WYDcN zLc7{H*1PE~UmktwkN?Ts#O^=av2*7kYfXu@kevDwPj`IzfBx!*?e)bww?FnbKU{4t zycEmkPFnzMVrnX%FFftE$r-48i!spYz) z%&8@|LF&rKNb|g)XqT|Ekk1ViZ6f&QKv&=~)@A@~`;7s_;OXjKF*gXtA^@G<&*>w7*OIMH5rEhh!j{;buSRdrGzLG&;578FSuaXGr7wa4nI`vbH zYS@Tf0bfY8O)n&>g>91~*cddB&#OX7;s68LxG;SZbSiQp&j#6g-VhFR%{H-qiA&IS?tjb}9y z0DB7Hl#cyGNJe@H>X$ecWP?<{4a;*m7{gURhxP2@VtD9eI~<%{3MUrY;nb3iC2k35 zOAZ(oczS8t95P}AI(U8F4}wqo)1m8OJ*HzmHvs-LKOMVY?Wf=W=iLB0em&I6I|)ql zc0bGH?Es{EmFki9^X~l8=*xfl!?TUef4Xz;<>fp6&j2_bC7wz6>bw5s#Fo+U<{c0H z)sObt%~xO{-ibK{V1i>ou2wK5xu^`mnpX{L?tk?5BEM zMAHS>_*fjlBh5vUFupvm@gwbNI$Anrx-&X>I%j?zko*>}rX<6S05=3&Sn24EXCE7w z)3(im1#T?(Fd>Vfqi=Tkxqo!}lHuJ1&yR7eD@gDxmX0Xe%xM9nNuf`0qz?OmcLXL! zDq%M^1D8$L!;b0EFgAis0Ty+dTpWje{ zP%$~ymre=Se3qwUJV_4NKVKVw6gk(aBF?1DVK(}q=B^O+a$?JQE;VjJLs$_9sbyJD zWmN;g{sl#y)HY?iy>?i{KvP(1h6j%=h6hh|!b}qmTO-IeeRfOV#sbqgMT+@oDQOG= zT1fH}AXuf4{xbTz&tg%%uJm^jxBw$S+k=g@6|EYBQB5tL*8+C$wp1AU7m z)I6OzCgfPA~UhqHzS#azT7;|~*RQvjYl1Hiigr6r37M!HvlEuIV5CajOy0cs_U zsU7S|UX4xg$5*gQkJKAs`(!ojnXZIAlOthzavbY4#u>{+XQ*$A-LE<$kLQjt%Y`iK zOqTi-1UIi8WtjohBOX;ZMbP(rKUr%btx(hvCsB8iVJ1@(YvD|)mCCM2$D?hSlrTWZ z`ZD$_`ix_bJnCx`j6Q9*n&J3dGdwwmt9yi#OWm-Ho#i41AMaRU+xCb4?CoJ` z4x51LPCkXJE2;s|WCyr-TnJ=~eF7GhU-^+%lp)tyS!Z)j1Q(<;uRAqd8Wt48O(`b0 z021mh)&qaJeT(H5!DC%4k8;#SnvPcejTj3tYpc5gbn+0TBc-#mt9^@^rbE`90P+#c z$&+sz2=cX&fITkQw#hIX=KO85VYWQ5F6Q*PnNXb~&uRNcfwfHSQESw^3?d~@$8J5y zKA=7wIQxp_(MfC`uZFE-eBiJeHjFmH_~=L&!>T_4&oF^?d<2(;wK_Hlu)~_L9Gdhr z|6xYunQd^2X+Lpmft7Vc9dQ!%OeB>}vEH(Pbyq6}_&}=)igsO#*wUBv*gi^LnlR2eSmlXR-_oJe+4D1e zj0#l5c>F9rZUP`j2hGpp>9BD+Ee2l>9Sr+gADy}1_P4kB+2{Mb!p9~8w46V6kO#KP zGaZzQz&eqsHtY63>R%Z>+(ese%q{<;HzG=jbwh=e^ufB>4$6i^5M(GCJqM$_3-hjoe0R;{qR4um#W zXd4|pIj*lf9jVKk^7b(V+d>DyyAfQfx!vjY_+m;w&!)$IVbZ>S$X|1-YNN1wvJ!TT z*TR;`M%Xky8b+{L;N1@CNH_K~4JDi$`34~6t{-N(sO{WgIJ>e^tSmvNfc+#owkj56 zDV`hai|*25IEt(ILyMhoaG|3o@|T)jjSD~TI8iz`c4q`M`c=ad!5$LE`9L{z_{`vp zWpPl&rpMQV7G5W_)FL4e)50`i*Qi zowx0H^sXPTEgbtk%=leewFyjqQkrO7AI>{sF^O%Jg~D=YZ89n1WCs-&dg;)P>E!ti z$cYz|Dacz{gdvq@F)^(u>Nt;3nXHT3V_NwxWNCAttP@$zqnm{D#ez(RoIXf%%;v=X z_Pu>AkdEIr0JfOJ$#X9OdAmDcd~Oz8j?SMv(&;9Gy=b;k4(di-LQY?s3RTgn8fogW zp=`6Ijn4zsEt~Z=W8OD*UaW&yu43_WSSsd1hp|Ehjs^=p9~PT{w;1O~4DckpV=y|> z0KXPS;63>J?-L02t8n~@SX^|AKt!WS9#@sjzBM$c&6iv@BX(Nw$@uevg7ejyrs5y`ZioOZpTFD=3EZW zmWvAkA71$|b7zoU8OFVcFQj>Xe|ivHW)OVgb$SqD6@*xg6+AA6FdzY6G@#2{Zj*~F z#Uu+}YMn)L1K{5jaA*S{S=b<-S8-7$b=>B(>C741roj2`)WzdwfV>z|S>`E5ntThk z$zaSp!oFF6s(|LzJH(LBs##mfk2O}Hot$sbHw$!rDFeP_m}54$$*_kf!H<1xFdc*0 zWS`jeq}^tQPk@NUOpSIf9bnB2UIbf9#aazYkxK!~l44Nz_2aQ)>_Y$bm?qKl68mp<{13?JI$8z1>&I7@Kc z%Q#WESO;xy&s#v6za&Y!x~7M{u3REW{1MjYD#ZGeVoZw9HnUDqAi~Ezt8IP8zOp_< zH!0S`d`u!{pHUy(0h%Io;B?SjBH~p((scTC=9IAq{p_JV-W6~spKSzUY?}ja(73?> z9qs9=A8Bm@tWX5rsbJ|$BM`L;dain;J39T<#an;oQ;V(6|DJr=kDuPYV`urm-+2JL zy~MKspMCFt-nzSU@GTpU-S?K!*#oy?@!A1)oeKaL7#j$2AwI9jhZq+v6qiBe`b3YQ z4B?BI>XcN<>PtHo7cq#R>sXl%E;THLd0g8wxkRSVX^~Gkrv+Is63EMD3|l;khrl=n zIt|9YDX|nC4qJ5Cip+2a;wBrD#9Iv6{zid**`hhh0rpL5C(~o)PxUK&f#8WzV z@FrvViwX1VSaw6WHS=o+bF(-~Y{hySqp4*m~rvcaF{-x*3-&`T-$j#*tvo>cT*a zrY51Pujxpt!hnNZKtNwsC3uIeT5Qk2XG)ZFvM&&%73;e4K%??4^>Q{9) z%Mu$PK^?}BkNKoUN)~xy!MS7>O@?reo!h+3)sV`loP?p%ACcQeU_$kTTc)4$J08gM zQoWrNPt0Wc;^UB(A$jRp5%8x%dX>+Ze9ADeClo8h4FG~1HU=v<1N_`Rb@JJUfO+64 zKj!&o{Fz+#y?x&1Cy#k_{wxdiL2Q-D@3h#w!THif0j~UOjl*Gb>pi`j?)d2OEjRt? z6)$^Z`GTMG4EA`5XA$mt-*4^P*Ex8{*5mj7(8$cAw^Z8gEm$^2khRXS;9|C5t&M)O zTK^K*q<3H$jQL!$hAqWZDcT`u%bidPl@Qr<5S}(?(Vs3l|GqQ=WnIsa$$)Rg)A^WC zUwtwfvFI4+2#{8L$!CCfRxS>9<(_W|5QE_p!xWpbjYWmWD(R2>3Olb^Dq8OPTi%na&o|c z$>JCtgxFwNG4ALA=|e(tZl!-rIBj>H5`K*Rya`~6uM?ch5<0_boadQdVK|#sfycD! zh`R7IZ#|$VK}Pz}L^MSrg@2P_+8n6Vfp|BAG&0@kiw`Hu-lHM5Rsjc>p%1nY9ebp8 zyB`_c3^YLN&H#d*+@~Cjn6syhUD2DfH#^!q=;HyqBfuvUvWEu|>pUW;4|E<7Jk8Tu zsWdzFiQ}DZ*W5jJ)r&rMV&BXD{IVCkvixD63jpabbX!QY{=jkGtZ!%nb<0Lnld?ju5$`)rGBR9$u=|VmT6dfd@ z#nF+Q%WDimY#y9RTZ~fO2yNO=}E#UUMp*z2NHA4fE9 z`Jk1BR4h+NXG_W;dFuLj#GmIzR>XjDMVLWL(n)jtA*S;qPveBxv1d-3{3vIR-T5(3JkU{IdYQbXtsKxuAc?YY)Ne~5 zEt(rhmW)5p1o~j96KYR}iB0#1ZC8Eq==K+UZv3_%{oZB!_Lt880>XN~#IqLP{=k2@ zdegCQ+%a|P;Wt#93pc~zU=vVjXk=)i#BA0w?#PFXuZ3E2M90a@gy%&*7fz4Q2Xv7` zdn_m-Uijot8;mT%7u_^pyn;M=#0uMeh(dj^g*`RuHjK}Z8)ZwBMkZaOfVAAC#F%G% ze&vhHC+`mAx9uT|Sk78`=9J0TRXS8jo3rNvZ1UPbD9<+r#>+Mb49uq-YY}<&Jb}yF zhJxpoE|Evuq_7;T3wh)i&DdlK>XK9*D*{l)c&^7I$6}PrPDr$`{2WS|`9Ac?Q7@AH z!m&(CM8Kg%MmLJmlwWO=MT#+dz^ELS!qMg9ToGVMdI?Xi6aVs;;^gI+TSbftk!G(@ zm*vv=lA;71Gflb-({j+{A;_tVZw{S&IdTwk{LI6FcLMlcf4|!Am(OVhRDhccmX|%) zr`!GohYwnU6}_0G*{hEnY)@>yr!}_a(<3i>%cnQq{xjt-`dtLr*(mX>#=Rf-k5_Fv z`Q0~6pML1|)y0#ygl>B`Kf>c$oDUFNfQ;kZxLO0Y6d7O3r;7tC96uLGBp;Ge9 zAjo5{(;4#^9l5d-9+=`g4I6rhkm-~sUC)m?(#!L-slcCq1R#Bu!}6qOeEcJ(Yw|qC zs6GCfPne7a+YFcsrI5Ev`BLJ)<=W9==G(z+r%0tGlEgV&DV5G+=J!iD`cp1bs6qs| zIH}Bweh_pdV8(dJr4uj-AdwOm9DX)RJj?O9KYq{t&2taFZs)PP?`WKU;w9B~YZrFyRV*?C z#t2yqT3MKdB$ER2 z9EVX{D&^F&3?q2OnK?VPlPR>FUKqxd2b%8NKORs&@Q+!@Gv`lz-W@3Nd zezrw^7Ih!SrVkgZIzspbBojh#wd;3h=HvvqJ@~oq- z`jLky+K6*M3$zeo-q6_wRjS&z{}oE&q!M zI~yfR0Dt-3-`;guZT1JYp8WQm)5q_-wc1|ThS@ug>B@_N1o@(sFSIt{`xf4ae9~Lq zFuAh@7r-LCe!~FYlfm`LE84PU7JMCtAysloEaoH=qiH!=1rnw^9Og(Q>02Z$4S8+= zB#oqWBuwuPzI2$u9K>Qrr<}!f&UWQbHQOZcoKPGx%D0&OJk2ug-0_Y^6_-%wJ zOFm`zaRe*ZXP+#j7#SVy;6SeYG-B0_JnIO_Fk#yq!tyOoLgL$zX(eLcC?%VokZzQA zF%p(bM2cfIrqYi9C@&pHrfBlaBxN$`5xKCbKc0KasWRqdT}n<>l-Xd~Xavyq`8st> z!}yd#z`-1OOjBOLoVaf7JHN0w(69QzmY&+D91hvWfli-gNsl~Ah=IVZ3~C`-Qj$~c zm3F9+ol327AdF9czPbOlzdkyB)yJ>O^S&=spZn@RIW@KKQ+ric0K3i~Y%@&mcwC+YwCQYvdjhuNsYXY?X%=12XzUQt9stpllmODfPT8X5bF;dFGfis9S&6qf^ z)Oj0U3FMg`9lGg8eeyujnbWzGrmQ(?+92OI0H&X94j`vn`B|E`_1!)<0(Rxk=K{o| z5OS2kn1MX!6Iq%x>jPOn;s?7JOT9|9b{NCv!QQpEf3xwbU%2a3Z{n|ZU2$#sO5djt z@obeSu@Zmz-rpYIGG6E|1&fQXFVN=?SU-GC9tbNp zS$X9|?8`+C>eJ3}Pso)qKvI%jasZ{=YtQ^7Q=s z_q_2J!7K4p!_HQT5^Lb$_x{VD+y3xhzqzv9d^uL6om_ylf^fM2$%S(LOXYBAS)pw} z4qSwi8MLUx#ZP5Z1*<$+q#ev#9Td)mQr!##nC2P=!xqPwKhR)=SNv=MUAEU91VKuU z3?VMr-i?C#ECb7i%Z^p`JYC0=Pvd~{^hX&FRtDRdIeKd9Aw=6CIP}n=>mkkZ?Cycp zozEetzaq>AU7Xn^sH05;@|Y{GDh{4(SzRbD+RZ5)6BX79y#ijxEcC$~7YVDI1S3y2 z)u_aIYwAXcQ!aK`tTeNHf)IdRhDi628I6Ju2|o@=CiW1z1FGRDc_i+H@M zoE!dGzVf99eGnN>eEfl-=N#nl>ykA?ERFJLGlNpHBr1y}%Kk=Odf`~8_8zY6zvWw% zpZu>M8JpVjVUsFxDIlJ*5+&BgH{Smr-*)-qfAjY0+>}o$n}RKF}QBH%`?|sQ5!ZQZBzmDE8cw> zWW+2fKd~xDM1|<&>AW(?AtOzm*mA9kjje;yc8pHk*#J+WN(95K8SVMf1_x$P8I1|664*+xbtFCgN_91c1>>4CN*?MPFxpw2Z3huM>>j>2N+ zC=5KBAj_O=WCFVSb~?s%%KSNF(I`i{Q3X9%I`G=;1v5w6eI&l%8!8 z5W_wqv%zd0C<(sToX+2_;E|v*+lz?jQ^X3e{H!b3+GW)DRM@cdbG6%l{v%^A`-$JP ztP+j*&SBSjI<4a!j zTk?SC(;?_C0D~{~O5>c!9^56a$mx)j1-^9QF#L0TUd<~;eaNv>1xg*^H0!Rm&`HL6NQj6OBX2h#n<9|G zGGd*1yS#`Z$8B5vIHvjVY%WD7?Pc+t@E7vbx8QL@D}Ky3haTGsIL&jYbbJudfDJ%& z^eodh3P|x^`b@`jp)_c=2SqYPn$4_MYVmFW(|LW&Mh^Co&BxHfChTanG5$zp*EJ7x ze&QV;nclduyz0M1(SH_8lvpRe_j~{9=XMcf89Ol6KQ zLD4RA>6BeATf}wD?TC&s;XDvLSc@U7j|g!7WR7)0-Qp?60UL>e4T(j42h{Vtn8DcO z%vp=4@|Zza7iqwpk)`9FK%i7!q9QUCOE+H8stwGdohanC`(Rmq=mX{HV4Zg4lCci4 z-%|^uSvE_zel#XIOv8^GKW36o7%QfuK0Dv9^p!^%Y~P#c)w?EXIU zh8r(qSj_X{_Xpx>&+-f!6^o(PI9T0z_2+u8`p17hdDHiQFlLsxM3J7s5+%+EpZm}| zf9UEbKJfz+Cm()6rL}M+9LP>A4x?IRY^}gTfyG3Nma&va53mk!VYLNoC9*|m4fr}% z#30Ac&5GHK3#6z)P)m#yR+k=xbyPir)u!Ke%5ew8zAD=7t7Ys@#?l9!=KEDUVYi== zD}!cLdgLqR_LxV<$}a%YagZlYpS;S8wybmnrE^f$?;xZgj}C~C&8X=$EP&Umc0;urH&HB8c|E=iaxqjJ$10n5J=DAL z2kvRy{)-*5L&} zSO}CyntXm%-={%7@>N`vagdfIP4Q2+=-FyAtUU&I_>rW9=c#DY7D&^kpAkZJ$ZT1x zT-6)3MV(d05Zch5$Jsd&rnWv>z2+6)sNVR-Pae7Zqkl8<+Fxn!+OxMM?^hNdN?3GwBwj*mo0$gagfJ6-QpIRdUM)}e+c!*Np z<NSh`<3x}JN zvSsR<1tiiz7hxuOh=z&-&9j`Hm6z&xdk)NisVx)(9M=>i6f8ggE z0K^brk{szK_B3x2+F`auNr!!<=Mw;K5Nh1dgQvS>AF5!%jrH7^Nt#y@c#=Q7hyPvN8BG{K23(mv+;Gv>ZZK>Hv5h1QIciW$WVreuWPP^SYZnkE~m!V`_@n0?Ip2kgk19k+Kc0Y<-s^?~OHJ zm6Clzdg{M^WOW00Z-bBUr9ytHRZsF+yyq*;9P~73dzT~9yvS?sjDoiL{%Lr zq`o1SEXxtVQ$NRKnx+)&wQ!iL)T;MY_rK^fCtB4%Z&e%Ltv&a(%llsaV<)9k;%SBC z?3XBU?)dWW{T;PiGoDOX8l$02)kk)Vf$Va{789@-vRJBSF5|Clwje zA;GO&{OE;m0I$IDhwegUY{Qe?%WitKy61+!o0*;eSaoX41H10{$K@6O(-?7Blqhlj z@TqtG#)gT-!#gME4?cf;b?LR^^9Ns2X)j-mg>C}Zb#>jY#QMU;r&qxO!K1;!}QNYcKsM+)j{j4m73ksF_F^bJ7lEwIyb<499k4P*lPkd2@3lfgr~ z(yJ_V>W#zo&6hpayZ%*QJ$CB!Co8+If4qL>El=#e>N(|We4pm%9~~u1oJV}_9shcA zWck!fclS=bX>8%>OUD+E?+M-3HY_b;^!!?~bo-K5|F*2H8-qj(S5kss;j9OP^v@8h zmF8{CWpauor>@G<3FL)H*i!GT$OOk0d+8ONPoFIlk8(~RijHDUCmr?OkU1Gk_vuEv zj@-T?>9~9<%Ge}xC>;gdX~`b+mC6r>)L;U!lRDDIn(al9h$>M4GhoAu%S2+`VgkYB z2;<@?g-jzyw3k9UWXdiR38IZurzn!5-*&bI0641bMM9A2AZIC5>&H5~Zg{M=Y3Dt2 z^X22Kg=wR*J1L8K*6#4(Zj39#l8-sMN>Jj9WygzsYxA zu^grQnS(^h>mOc7By}RC?4pcdXEr^*l8;Gu`KgUUa}BOA0G?A+BR}P(7L0F4$@MB7 z?8lcwZRA9l-u8HR$8}#nG`8;((>K2Q;a$(W?W+*#3* zb#rY{F+mBF(su`N#2>SHvx;mQbUTB}R~{9TBy2Dlwff+7(s?e_PbiiZ?WOQkl#s4J z#qT^K)k5o$r8g(=%^XeaaAtd(_Z+Hi+;MMZYWv@|e&Anxd&7=he;dV1JOj}`ib|BY z2>9mj|N8589{c*8BePGwy3v~79lGreSbXZeN_>-GT(NxN@++jZkuG(P!Mf|0JTnZl ztM9LqP8awXJ3J?K1ep_XkPlwU%`FZBdM^=3?Xe7|(sBnQKLdqpZZO~#^7ffU%traS%5emN|d;`_{4{P|Mn|Se)Z*>PkiSkjm2Zn zsWun4^?KbYIFJSwY+JvuOu3I>qy;fs)GiKuf%XO1*3SMKm_&|jkxpWQS7b$do@Tp{ z=+h&z`~;~@ce*P<{XzVQp?U)_$War0Cy2HNl&K8@dBw6I3*El95XlB018o#B(B}Dr zTOQK#p^$t$cSWS_Bt@y>c~%9rWD)fqVc17T$R zU}b9Cq29Hxc%=1`pSgR}rp=|}e-ZrXis?KQu2Z~Zy1K2RH-_&QZeJiBl)#&?MlYvS%d{I74?a`OIL zHlBLu){(^%*M`pW&PuO0iIr;v8vy>wITpLP&~@FZTzL56%7r$Cm%i!*f-dE>NHb0r zYA))w$ScvGPi9INk=k)^mn6{vc^3jIuTYkpeZhgRwgI?=;k6ym`xgv-4&UQJKpth) z)2TdQF9|}9hF(QZzgMj^EA`R2&=`NTyK(n@l`C)kT4V2XzdZKBAG%vgC7!jonB%)d zi8b-1Kl-iL?mzOCmye!$uFPCF z@*P<|;QW;5=(Dv7RAHwGwj@hs1vC3kvRzDeP z)yH}x6US>?_CMBr(GTBuZ0CzUcEuH!KWyS9p6$38Fqkhfsf{yW`q>E6;n~m#Wvk?2%Kg%2)SZ^_=4-U801cI37!sxTJ9R2maeFo8}&S z{pOSRzqm1X=-L`K0^Lew8f$tZ`o9ovj$w81_9o{nr4#V^*BaRTJq3LQ5o!B93yf^Y z>q~nm$A*lR51A&0`b@W4d%UuF$I0ftmp;~g@sED?)O_;~uYG>`<2)sXW0hG`qQs?x zPrvgwuH4aRzIF4=1K+pd*aO#h+sk|5^e1s$U8_{OjSg18Dt~1iai=Pm6aC2GA#Uqu zzJSYlIgOCzM2F^%Epu>)b8SOkK9K5w=(BasC^`_OX?KWicc{`KJwWapoMPJUwZZ;i zG(_IpweI@RUTn`GowT1E=g?L|Qf3CUXJDJ6Ec4QO4yu>Vi`n20DW&6Armdejf?A;4 z5S?vTMjq>4e%rm_l|T3CjeD+nthRC6U8Yf@#OfF{T1%9;WbxO(_nSMmk9K}!=ZSm2 zZ^Ma)_lD(@n|ht@J}jpjdzI=4e^Y?Nnr{@qF|L{`QFK_t9GLS{r=82?x9y#m$~lyS z{7kDTBVE?jlIwz;Nu&wtu5d^R)DP704Zuq9hRKRPkj(*h-Co47{v-PHqAe!Pqv=mC zp-tsj&ogn-Ue7)qq{SapuUL;hKu+v}{IEV)VRw*B0-ducGjsz0K28Ls^pTM$JE^K#qa&@*v84R zSL|GRc<=55&W1P#V zE>Yr=!2|F4)t{X@_28>Fp7`$bdacF%xZa-b*}DW9$X+?lqa$|EA^YvtK4Cf(@)O5$ zR?a)Iu>vX=d1q=ib!@9`08$5bo;Co!kr{;kJZ}`z;Iog>gGho#z5Kq2bXYCl6v$Ds zPv|HIbd1ZbhO^j2tRHMcBvTBmm$g@U-j=}|fEM^2*quio9cop_j)$##pRDY?>Fd>f zFZgb4`xW<3Tyx8}qHKv0=ZtmCq7o%8eSGP6{_l~=nMZ01SKaUVZCVMxXnN zhfX~C_}%S$KYlb^`I1g!-%Z`iZh1|cC6y>~K5!N@phSsF7ax1?Z%tlt?5m@l9oM{c zY~lF64GRZunV5O}hDvjGKOFuhEW{%at6|{R_#?!e06i?&{0y3lb-JX>Ng#HILC9%< zE-w8S7A!N8gjIS7m|27i56W{;Wvu=CDdAm&$QmYFgf>oW&nhy* zpuS+)zEO&WJ6JC3;C+U`V>VhyRQVhG(&S!Xu2rcXY)x*T8QXW`6JgKwU#w1TfBfj( zfBnT)uR1&WqC1)+dv9p%y!@Kd>6f@5IEz_OqQs?-Prm2BjEyaw8r^dGq4Cbn>t45I z?vYoHo<4YWW9h`!YHMjz=ytY1Yzz~i)~#Se5Z7oSbtXC{K%Vnl=At0II?t{`*N3#8 zt2)PlF!zkc+9yZ#H6&3m6X`L)0KY`FF%^VP|%?aJ8n;-2T-S~~p_7aVJh z_!1?a{`kxH{`bjkbB}J>I9h#PrPI82tTlhd_`=~EMrRN1thAOk_9~UFa0}yD-?_5a zP3x%ursIk$Q#ce|GM>Q(K=LA#TrUPYRvC)u&r9W3bINOhx&-yz&LDe($1HwvQVPLMZ|fWK_yCD+W4#A|L;>Ho#jnaOUI_i=MV4OFjl{5 zeCfpAN^9Z9(dC&P)#m(Ex7*!Tt%Pwb@Kr4EHFr8|BTl9DiVwuF=?J4~mdaRV>dH|8 zzL_Yd*97HVHtG&2FLi>$Xe6MzQumAi8(xbP103)=khUjn=Wwue-2q89006(5=f)T> zLF#0;J~|)9CR@F+jiF@R`wI_}|@#sS%SHF0!dfm&9RX6UOz3jRh%eV5C zc*=2(GqXgArzbx0{&$TvI?LO4%|5uHG5h3Y8z(1T(Cf5zPAwm~xiNQaXJ{=?;$m(a z7WGlA@0=$LSo!I7eBCGP<~RfI^&03TNK?*v1*~w&NGIeuT zCANm_AjiIfml<0J&O~+hdSmMabDnw+sJolx!e zD!p#6SE($pSY>+417UpQ6DN)xdAQf<9PMtt>~!t28;;ht zUwLxh&95jOeu+yC=V8W`DDm{h$KUskIy}VQN~bk_`H3&>8?RPx9&OI->UBHMA6q`X zquQFUg?5V@0e+ic9KJ=DfS5dtHHWgty)5zr01+ostaum=LJ65CR)L&dK|f2c2Cqx{IPIfAjn~(JBBj4y%M~+k*jqZUb9($y=>-y96J=dS8U;W~vVdIV?`>wd= z6tzo~xRjwGUZO;a93TC|_guYm{^5=F`J-2Eo_TcR#N_z?dTVhA+ed_icURO`~hCMus*3S2=nmr%}~YZs*iL-y)h5^2`C<{)Ee`>`dF`BsV*M;9C(+YhT!v!y91+q1JIXVds>>qB(=6IVe+|bF`Ys_ zGr=Ia)$|F^x0syaWx1WTY!=X8$p~z`di<=u+6z1b3-J1_3cH?mu>t5*8{JT=&tUKL z@N%VotTi&-uGQ+N>Rb1n?rq)wNN?-qkMuU|I8~Y2)UA$fXm8nb#W$nr5+$B-Sodrz zQKH03eEg5zvvuR-_zhDFhpyam`oZT`=1=adE}fhhT|SL{K(o^8wl~+h-K+T$qR{Q| znw=Yg@lff~E5T#=6y&8TeHy(c(+U4PPE$JB40MVEobF&p%!}z*lNEV6TsMt}A(bPd z>}%Lu&f9+e=&&-knLUawkjgPy@Q;9<}w!^mi_GBO^*$W&Mu*)Ut#y!U8j z%bstA9ale5*?RfXsrlw3*I#$_5!xwH;@O1ZGr2^G5@(E$|IzQ&H%?F9JkdG@_tdUV zFCE#n?b!XdgxSNpTFY}AYu&J^SFK!u4Z&vY4(hy1Ko?f!Yl#CdTzeyMW(~SC?g#Xk z0J8Mk@F3+2K{Bmhi{nQPVnyg30dZQBNd^AXR?#_2CezFvEqJb~WIXEW`Jznx7=jFC zgBcxpgvq-ak=sKQGoZs%7d95Fq1w?$9DIVGfw$=;Rt?>1ogFq;>2)3l;~2s+WP0t| zXlRaY3e~CY?J&J_zPk0YgU#*Ne62gNX5E&W+D6Kd&!Q0!XH1 zi4r9)B)Y>6g97#$CtkxgN_F}2to-*BQjHg#WRYSVYa_{RCl)V5x4YFp@yPO-S9 zz5Djx!}3d%D6u+xu9hfK;v(bocYXY(vF_r=dangovaS&Ea%tZ zn5PTwe)QjJrwyt@E{f8wF8PtBWTn!9FqaWV5VS4&ze$3tIG{eT_pZKVa%dr!9X^ z8qS{Iov&1Cx((l})kCO{A~Zmcgl+>@=8cKYiSeC}S8MgZt<~y}SL*dnuhs|wPM&hr z#)x!!^|4Sv+-;266+L6faif4Rf9$2@&D&)A%Eo*$t!{;SxX z-1Phxd?vC>lqgZ6M2Qk5N|Y#3qC|-jB}$YiQKCeN5+zEMC{dzBi4rABlqgZ6M2Qk5 pN|Y#3qC|-jB}$YiaRCs*{}1kUTy%) \ No newline at end of file diff --git a/www/generated.html b/www/generated.html deleted file mode 120000 index f4de73d..0000000 --- a/www/generated.html +++ /dev/null @@ -1 +0,0 @@ -api/data/generated.html \ No newline at end of file diff --git a/www/hope/hope.annotation.js b/www/hope/hope.annotation.js deleted file mode 100644 index bf0e99a..0000000 --- a/www/hope/hope.annotation.js +++ /dev/null @@ -1,46 +0,0 @@ -hope.register( 'hope.annotation', function() { - - function hopeAnnotation(range, tag) { - this.range = hope.range.create(range); - this.tag = tag; - Object.freeze(this); - } - - hopeAnnotation.prototype.delete = function( range ) { - return new hopeAnnotation( this.range.delete( range ), this.tag ); - }; - - hopeAnnotation.prototype.copy = function( range ) { - return new hopeAnnotation( this.range.copy( range ), this.tag ); - }; - - hopeAnnotation.prototype.compare = function( annotation ) { - return this.range.compare( annotation.range ); - }; - - hopeAnnotation.prototype.has = function( tag ) { - //FIXME: should be able to specify attributes and attribute values as well - return this.stripTag() == hope.annotation.stripTag(tag); - }; - - hopeAnnotation.prototype.toString = function() { - return this.range + ':' + this.tag; - }; - - hopeAnnotation.prototype.stripTag = function() { - return hope.annotation.stripTag(this.tag); - }; - - hopeAnnotation.prototype.isBlock = function() { - return (hope.render.html.rules.nestingSets.block.indexOf(hope.annotation.stripTag(this.tag)) != -1 ); // FIXME: this should not know about hope.render.html; - }; - - this.create = function( range, tag ) { - return new hopeAnnotation( range, tag ); - }; - - this.stripTag = function(tag) { - return tag.split(' ')[0]; - }; -}); - diff --git a/www/hope/hope.editor.events.js b/www/hope/hope.editor.events.js deleted file mode 100644 index c2ab6ff..0000000 --- a/www/hope/hope.editor.events.js +++ /dev/null @@ -1,35 +0,0 @@ -hope.register('hope.editor.events', function() { - - if ( typeof hope.global.addEventListener != 'undefined' ) { - this.listen = function( el, event, callback, capture ) { - return el.addEventListener( event, callback, capture ); - }; - } else if ( typeof hope.global.attachEvent != 'undefined' ) { - this.listen = function( el, event, callback, capture ) { - return el.attachEvent( 'on' + event, function() { - var evt = hope.global.event; - var self = evt.srcElement; - if ( !self ) { - self = hope.global; - } - return callback.call( self, evt ); - } ); - }; - } else { - throw new hope.Exception( 'Browser is not supported', 'hope.editor.events.1' ); - } - - this.cancel = function( evt ) { - if ( typeof evt.stopPropagation != 'undefined' ) { - evt.stopPropagation(); - } - if ( typeof evt.preventDefault != 'undefined' ) { - evt.preventDefault(); - } - if ( typeof evt.cancelBubble != 'undefined' ) { - evt.cancelBubble = true; - } - return false; - }; - -} ); \ No newline at end of file diff --git a/www/hope/hope.editor.js b/www/hope/hope.editor.js deleted file mode 100644 index 97e1c0d..0000000 --- a/www/hope/hope.editor.js +++ /dev/null @@ -1,483 +0,0 @@ -hope.register( 'hope.editor', function() { - var hopeTokenCounter = 0; - var browserCountsWhitespace = (function() { - var div = document.createElement("DIV"); - div.innerHTML = "

abc
"; - document.body.appendChild(div); - var range = document.createRange(); - range.setStart(div.querySelector("div"), 1); - var offset1 = range.startOffset; - var sel = window.getSelection(); - sel.removeAllRanges(); - sel.addRange(range); - var newRange = sel.getRangeAt(0); - var offset2 = newRange.startOffset; - var result = (offset1 == offset2); - document.body.removeChild(div); - return result; - }()); - - function unrender(target) { - var textValue = ''; - var tags = []; - - var node; - - var tagStart, tagEnd; - - for (var i in target.childNodes) { - if (target.childNodes[i].nodeType == document.ELEMENT_NODE) { - if ( - !target.childNodes[i].hasChildNodes() - ) { - tagStart = hopeTokenCounter; - hopeTokenCounter += 1; - - switch (target.childNodes[i].tagName.toLowerCase()) { - case 'br': - case 'hr': - textValue += "\n"; - break; - case 'img': - textValue += "\u00AD"; // ­ - break; - default: - textValue += "\u00AD"; // ­ - } - - tagEnd = hopeTokenCounter; - - tags.push({ - start : tagStart, - end : tagEnd, - tag : target.childNodes[i].tagName.toLowerCase(), - attrs : target.childNodes[i].attributes - }); - } else { - - tagStart = hopeTokenCounter; - - node = this.unrender(target.childNodes[i]); - // hopeTokenCounter += node.length; - textValue += node.text; - tagEnd = hopeTokenCounter; - - tags.push({ - start : tagStart, - end : tagEnd, - tag : target.childNodes[i].tagName.toLowerCase(), - attrs : target.childNodes[i].attributes, - caret : this.getCaretOffset(target.childNodes[i]) - }); - - for (var j=0; j= caret) { - try { - selection.setStart(node.childNodes[i], caret - nodeOffset); - } catch (e) { - console.log("Warning: could not set caret position"); - } - node.removeAttribute("data-hope-caret"); - return selection; - } - } - - } - - function tagsToText(tags) { - var result = ''; - var i,j; - - for (i=0; i -1) { - result += " data-hope-caret=\"" + tags[i].caret + "\""; - } - result += "\n"; - } - return result; - } - - function hopeEditor( textEl, annotationsEl, outputEl, renderEl ) { - this.refs = { - text: textEl, - annotations: annotationsEl, - output: outputEl, - render: renderEl - }; - this.selection = hope.editor.selection.create(0,0,this); - this.commandsKeyUp = {}; - - if (this.refs.output.innerHTML !== '') { - this.refs.output.innerHTML = this.refs.output.innerHTML.replace(/\/p>/g, "/p>"); - this.parseHTML(); - } - - this.browserCountsWhitespace = browserCountsWhitespace; - - var text = this.refs.text.value; - var annotations = this.refs.annotations.value; - this.fragment = hope.fragment.create( text, annotations ); - this.refs.output.contentEditable = true; - this.update(); - this.initDone = true; -// initEvents(this); - } - - function initEvents(editor) { - hope.events.listen(editor.refs.output, 'keypress', function( evt ) { - if ( !evt.ctrlKey && !evt.altKey ) { - // check selection length - // remove text in selection - // add character - var range = editor.selection.getRange(); - var charCode = evt.which; - - if (evt.which) { - var charTyped = String.fromCharCode(charCode); - if ( charTyped ) { // ignore non printable characters - if ( range.length ) { - editor.fragment = editor.fragment.delete(range); - } - editor.fragment = editor.fragment.insert(range.start, charTyped ); - editor.selection.collapse().move(1); - setTimeout( function() { - editor.update(); - }, 0 ); - } - return hope.events.cancel(evt); - } - } - }); - - hope.events.listen(editor.refs.output, 'keydown', function( evt ) { - var key = hope.keyboard.getKey( evt ); - if ( editor.commands[key] ) { - var range = editor.selection.getRange(); - editor.commands[key].call(editor, range); - setTimeout( function() { - editor.update(); - }, 0); - return hope.events.cancel(evt); - } else if ( evt.ctrlKey || evt.altKey ) { - return hope.events.cancel(evt); - } - }); - - hope.events.listen(editor.refs.output, 'keyup', function( evt ) { - var key = hope.keyboard.getKey( evt ); - if ( editor.selection.cursorCommands.indexOf(key)<0 ) { - if ( editor.commandsKeyUp[key] ) { - var range = editor.selection.getRange(); - editor.commandsKeyUp[key].call(editor, range); - setTimeout( function() { - editor.update(); - }, 0); - } - return hope.events.cancel(evt); - } - }); - - } - - hopeEditor.prototype.setCaretOffset = setCaretOffset; - hopeEditor.prototype.getCaretOffset = getCaretOffset; - hopeEditor.prototype.unrender = unrender; - - hopeEditor.prototype.parseHTML = function() { - hopeTokenCounter = 0; - - var data = this.unrender(this.refs.output); - this.refs.annotations.value = tagsToText(data.tags); - this.refs.text.value = data.text; - this.fragment = hope.fragment.create( this.refs.text.value, this.refs.annotations.value ); - }; - - hopeEditor.prototype.getEditorRange = function(start, end ) { - var treeWalker = document.createTreeWalker( - this.refs.output, - NodeFilter.SHOW_TEXT | NodeFilter.SHOW_ELEMENT, - function(node) { - if ( - node.nodeType == document.TEXT_NODE || - !node.hasChildNodes() - ) { - return NodeFilter.FILTER_ACCEPT; - } else { - return NodeFilter.FILTER_SKIP; - } - }, - false - ); - var offset = 0; - var node = null; - var range = document.createRange(); - var lastNode = null; - do { - lastNode = node; - node = treeWalker.nextNode(); - if ( node ) { - if (node.nodeType == document.ELEMENT_NODE) { - offset += 1; - } else { - offset += node.textContent.length; - } - } - } while ( offset < start && node ); - if ( !node ) { - if (lastNode) { - if (lastNode.nodeType == document.ELEMENT_NODE) { - range.setStart(lastNode, 0); - range.setEndAfter(lastNode); - } else { - range.setStart(lastNode, lastNode.textContent ? lastNode.textContent.length : 1 ); - range.setEnd(lastNode, lastNode.textContent ? lastNode.textContent.length : 1 ); - } - return range; - } - return false; - } - - var preOffset = offset - (node.nodeType == document.TEXT_NODE ? node.textContent.length : 1); - var nextNode; - if (node.nodeType == document.ELEMENT_NODE) { - nextNode = treeWalker.nextNode(); - treeWalker.previousNode(); - if (nextNode) { - range.setStartBefore(nextNode); - } else { - range.setStartAfter(node); - } - } else { - if (start-preOffset == node.textContent.length) { - nextNode = treeWalker.nextNode(); - treeWalker.previousNode(); - if (nextNode) { - range.setStartBefore(nextNode); - } else { - range.setStartAfter(node); - } - } else { - range.setStart(node, start - preOffset ); - } - } - while ( offset < end && node ) { - node = treeWalker.nextNode(); - if ( node ) { - if (node.nodeType == document.ELEMENT_NODE) { - offset += 1; - } else { - offset += node.textContent.length; - } - } - } - if ( !node ) { - if (lastNode) { - range.setEnd(lastNode, lastNode.textContent ? lastNode.textContent.length : 1 ); - return range; - } - return false; - } - - preOffset = offset - (node.nodeType == document.TEXT_NODE ? node.textContent.length : 1); - - if (node.nodeType == document.ELEMENT_NODE) { - range.setEndAfter(node); - } else { - range.setEnd(node, end - preOffset ); - } - return range; - }; - - hopeEditor.prototype.showCursor = function() { - var range = this.selection.getRange(); - var selection = this.getEditorRange(range.start, range.end); - var caretElm = document.querySelector('[data-hope-caret]'); - if (caretElm) { - selection = this.setCaretOffset(caretElm); - } - // remove all other caret attributes from the other elements; - var otherCarets = document.querySelectorAll('[data-hope-caret]'); - for (var i=0; i', '>'); - } - if ( this.refs.annotations ) { - this.refs.annotations.value = this.fragment.annotations+''; - } - }; - - hopeEditor.prototype.command = function( key, callback, keyup ) { - if ( keyup ) { - this.commandsKeyUp[key] = callback; - } else { - this.commands[key] = callback; - } - }; - - this.create = function( textEl, annotationsEl, outputEl, previewEl ) { - return new hopeEditor( textEl, annotationsEl, outputEl, previewEl); - }; - -}); \ No newline at end of file diff --git a/www/hope/hope.editor.selection.js b/www/hope/hope.editor.selection.js deleted file mode 100644 index 4f650ab..0000000 --- a/www/hope/hope.editor.selection.js +++ /dev/null @@ -1,347 +0,0 @@ -hope.register( 'hope.editor.selection', function() { - function hopeEditorSelection(start, end, editor) { - this.start = start; - this.end = end; - this.editor = editor; - - var self = this; - - var updateRange = function() { - var sel = window.getSelection(); - var rangeStart, rangeEnd; - var bestStart, bestEnd; - - if (sel.rangeCount) { - for (var i=0; i not a text node - var nodeRect = null; - var range = null; - var rangeRect = null; - var yBias = null; - // find textnode to place cursor in - do { - node = this.getNextTextNode(node); - if ( node ) { - range = document.createRange(); - range.setStart(node, 0); - range.setEnd(node, node.textContent.length); - nodeRect = range.getBoundingClientRect(); - if ( !yBias ) { - if ( nodeRect.top > cursorRect.top ) { - yBias = nodeRect.top; - } else { - yBias = cursorRect.top; - } - } - } - } while ( node && nodeRect.height!==0 && nodeRect.top <= yBias ); //< cursorRect.bottom ); //left >= this.xBias ); - - if ( node && nodeRect.right >= this.xBias ) { - // find range in textnode to set cursor to - var nodeLength = node.textContent.length; - range.setEnd( node, 0 ); - var offset = 0; - do { - offset++; - range.setStart( node, offset); - range.setEnd( node, offset); - rangeRect = range.getBoundingClientRect(); - } while ( - offset < nodeLength && - ( - (rangeRect.top <= yBias ) || - ( rangeRect.right < this.xBias) - ) - ); - - return range.endOffset + this.getTotalOffset(node); // should check distance for end-1 as well - } else if ( node && range ) { - range.setStart( range.endContainer, range.endOffset ); - rangeRect = range.getBoundingClientRect(); - if ( rangeRect.top > yBias ) { - // cannot set cursor to x pos > xBias, so get rightmost position in current node - range.setEnd(node, node.textContent.length); - return range.endOffset + this.getTotalOffset(node); - } else { - // cursor cannot advance further - return this.getCursor(); - } - } else { - return this.getCursor(); - } - }; - - - this.create = function(start, end, editor) { - return new hopeEditorSelection(start, end, editor); - }; - -}); \ No newline at end of file diff --git a/www/hope/hope.events.js b/www/hope/hope.events.js deleted file mode 100644 index da14d3f..0000000 --- a/www/hope/hope.events.js +++ /dev/null @@ -1,35 +0,0 @@ -hope.register('hope.events', function() { - - if ( typeof hope.global.addEventListener != 'undefined' ) { - this.listen = function( el, event, callback, capture ) { - return el.addEventListener( event, callback, capture ); - }; - } else if ( typeof hope.global.attachEvent != 'undefined' ) { - this.listen = function( el, event, callback, capture ) { - return el.attachEvent( 'on' + event, function() { - var evt = hope.global.event; - var self = evt.srcElement; - if ( !self ) { - self = hope.global; - } - return callback.call( self, evt ); - } ); - }; - } else { - throw new hope.Exception( 'Browser is not supported', 'hope.editor.events.1' ); - } - - this.cancel = function( evt ) { - if ( typeof evt.stopPropagation != 'undefined' ) { - evt.stopPropagation(); - } - if ( typeof evt.preventDefault != 'undefined' ) { - evt.preventDefault(); - } - if ( typeof evt.cancelBubble != 'undefined' ) { - evt.cancelBubble = true; - } - return false; - }; - -} ); \ No newline at end of file diff --git a/www/hope/hope.fragment.annotations.js b/www/hope/hope.fragment.annotations.js deleted file mode 100644 index 3009768..0000000 --- a/www/hope/hope.fragment.annotations.js +++ /dev/null @@ -1,380 +0,0 @@ -hope.register( 'hope.fragment.annotations', function() { - - function parseMarkup( annotations ) { - var reMarkupLine = /^(?:([0-9]+)(?:-([0-9]+))?:)?(.*)$/m; - var matches = []; - var list = []; - var annotation = null; - while ( annotations && ( matches = annotations.match(reMarkupLine) ) ) { - if ( matches[2] ) { - annotation = hope.annotation.create( - [ parseInt(matches[1]), parseInt(matches[2]) ], - matches[3] - ); - } else { - annotation = hope.annotation.create( - matches[1], matches[3] - ); - } - list.push(annotation); - annotations = annotations.substr( matches[0].length + 1 ); - } - return list; - } - - function hopeAnnotationList( annotations ) { - this.list = []; - if ( annotations instanceof hopeAnnotationList ) { - this.list = annotations.list; - } else if ( Array.isArray( annotations) ) { - this.list = annotations; - } else { - this.list = parseMarkup( annotations + '' ); - } - this.list.sort( function( a, b ) { - return a.compare( b ); - }); - } - - hopeAnnotationList.prototype.toString = function() { - var result = ''; - for ( var i=0, l=this.list.length; i0); - //}); - list.sort( function( a, b ) { - return a.compare( b ); - }); - return new hopeAnnotationList(list); - }; - - hopeAnnotationList.prototype.apply = function( range, tag ) { - var list = this.list.slice(); - list.push( hope.annotation.create( range, tag ) ); - return new hopeAnnotationList(list).clean(); - }; - - hopeAnnotationList.prototype.grow = function( position, size ) { - var i; - - function getBlockIndexes(list, index, position) { - var blockIndexes = []; - for ( var i=index-1; i>=0; i-- ) { - if ( list[i].range.contains([position-1, position]) && list[i].isBlock() ) { - blockIndexes.push(i); - } - } - return blockIndexes; - } - - var list = this.list.slice(); - var removeRange = false; - var growRange = false; - var removeList = []; - var foundCaret = false; - if ( size < 0 ) { - removeRange = hope.range.create( position + size, position ); - } else { - growRange = hope.range.create( position, position + size ); - } - for ( i=0, l=list.length; i= list[i].range.start && removeRange.start <= list[i].range.start ) { - // range to remove overlaps start of this range, but is not equal - if ( list[i].isBlock() ) { - // block annotation must be merged with previous annotation, if available - // get block annotation at start of removeRange - var prevBlockIndexes = getBlockIndexes(list, i, removeRange.start); - if ( prevBlockIndexes.length === 0 ) { - // no block element in removeRange.start, so just move this block element - list[i] = hope.annotation.create( list[i].range.delete( removeRange ), list[i].tag ); - } else { - // prevBlocks must now contain this block - for ( var ii=0, ll=prevBlockIndexes.length; ii= list[i].range.end ) { - // range to remove overlaps end of this range, but is not equal - // if this range needs to be extended, that will done when we find the next block range - // so just shrink this range - list[i] = hope.annotation.create( list[i].range.delete( removeRange ), list[i].tag ); - } - } else if (growRange) { - var range; - if ( list[i].range.start == position ) { - if (list[i].tag.indexOf("data-hope-caret") > -1) { - foundCaret = true; - range = list[i].range.grow( size ); - list[i] = hope.annotation.create( range, list[i].tag ); - } else { - if (foundCaret) { - range = list[i].range.move( size, position ); - list[i] = hope.annotation.create( range, list[i].tag ); - } - } - } else if (list[i].range.end == position ) { - if (list[i].tag.indexOf("data-hope-caret") > -1) { - foundCaret = true; - range = list[i].range.grow( size ); - list[i] = hope.annotation.create( range, list[i].tag ); - } else { - if (foundCaret) { - range = list[i].range.grow( size ); - list[i] = hope.annotation.create( range, list[i].tag ); - } - } - } else if ( list[i].range.start > position ) { - range = list[i].range.move( size, position ); - list[i] = hope.annotation.create( range, list[i].tag ); - } else if ( list[i].range.end > position ) { - range = list[i].range.grow( size ); - list[i] = hope.annotation.create( range, list[i].tag ); - } - } - } - // now remove indexes in removeList from list - for ( i=removeList.length-1; i>=0; i--) { - list.splice( removeList[i], 1); - } - return new hopeAnnotationList(list).clean(); - }; - - hopeAnnotationList.prototype.clear = function( range ) { - var i; - range = hope.range.create(range); - var list = this.list.slice(); - var remove = []; - for ( i=0, l=list.length; i range.start ) { - list[i] = hope.annotation.create( [range.end, listRange.end], list[i].tag ); - } else if ( listRange.end <= range.end ) { - list[i] = hope.annotation.create( [listRange.start, range.start], list[i].tag ); - } - } - } - for ( i=remove.length-1; i>=0; i-- ) { - list.splice( remove[i], 1); - } - return new hopeAnnotationList(list).clean(); - }; - - hopeAnnotationList.prototype.remove = function( range, tag ) { - var i; - range = hope.range.create(range); - var list = this.list.slice(); - var remove = []; - var add = []; - for ( i=0, l=list.length; irange.end) { - // range is enclosed entirely in annotation range - list[i] = hope.annotation.create( - [ listRange.start, range.start ], - list[i].tag - ); - add.push( hope.annotation.create( - [ range.end, listRange.end ], - list[i].tag - )); - } else if ( listRange.start < range.start ) { - // range overlaps annotation to the right - list[i] = hope.annotation.create( - [ listRange.start, range.start ], - list[i].tag - ); - } else if ( listRange.end > range.end ) { - // range overlaps annotation to the left - list[i] = hope.annotation.create( - [ range.end, listRange.end ], - list[i].tag - ); - } - - } - for ( i=remove.length-1;i>=0; i-- ) { - list.splice( remove[i], 1); - } - list = list.concat(add); - return new hopeAnnotationList(list).clean(); - }; - - hopeAnnotationList.prototype.delete = function( range ) { - range = hope.range.create(range); - return this.grow( range.end, -range.length ); - }; - - hopeAnnotationList.prototype.copy = function( range ) { - range = hope.range.create(range); - var copy = []; - for ( var i=0, l=this.list.length; i 0 ) { - current++; - } - if ( current < 0 ) { - current = 0; - } - if ( !groupedList[current] ) { - groupedList[current] = { offset: eventList[i].offset, markup: [] }; - } - groupedList[current].markup.push( { type: eventList[i].type, index: eventList[i].index } ); - } - return groupedList; - } - - var relativeList = getUnsortedEventList.call(this); - relativeList.sort(function(a,b) { - if ( a.offset < b.offset ) { - return -1; - } else if ( a.offset > b.offset ) { - return 1; - } - return 0; - }); - relativeList = calculateRelativeOffsets.call( this, relativeList ); - relativeList = groupByOffset.call( this, relativeList ); - return relativeList; - }; - - this.create = function( annotations ) { - return new hopeAnnotationList( annotations ); - }; - -}); \ No newline at end of file diff --git a/www/hope/hope.fragment.js b/www/hope/hope.fragment.js deleted file mode 100644 index 140c521..0000000 --- a/www/hope/hope.fragment.js +++ /dev/null @@ -1,105 +0,0 @@ -hope.register( 'hope.fragment', function() { - - var self = this; - - function hopeFragment( text, annotations ) { - this.text = hope.fragment.text.create( text ); - this.annotations = hope.fragment.annotations.create( annotations ); - Object.freeze(this); - } - - hopeFragment.prototype.delete = function( range ) { - return new hopeFragment( - this.text.delete( range ), - this.annotations.delete( range ) - ); - }; - - hopeFragment.prototype.copy = function( range ) { - // return copy fragment at range with the content and annotations at that range - return new hopeFragment( - this.text.copy( range ), - this.annotations.copy( range ).delete( hope.range.create( 0, range.start ) ) - ); - }; - - hopeFragment.prototype.insert = function( position, fragment ) { - if ( ! ( fragment instanceof hopeFragment ) ) { - fragment = new hopeFragment( fragment ); - } - var result = new hopeFragment( - this.text.insert(position, fragment.text), - this.annotations.grow(position, fragment.text.length ) - ); - for ( var i=0, l=fragment.annotations.length; i= range.end ) { - return this; - } else { - return new hopeTextFragment( this.content.slice( 0, range.start ) + this.content.slice( range.end ) ); - } - }; - - hopeTextFragment.prototype.copy = function( range ) { - range = hope.range.create(range); - // return copy of content at range - return new hopeTextFragment( this.content.slice( range.start, range.end ) ); - }; - - hopeTextFragment.prototype.insert = function( position, content ) { - // insert fragment at range, return cut fragment - return new hopeTextFragment( this.content.slice( 0, position ) + content + this.content.slice( position ) ); - }; - - hopeTextFragment.prototype.toString = function() { - return this.content; - }; - - hopeTextFragment.prototype.search = function( re, matchIndex ) { - function escapeRegExp(s) { - return s.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&'); - } - if ( ! ( re instanceof RegExp ) ) { - re = new RegExp( escapeRegExp( re ) , 'g' ); - } - var result = []; - var match = null; - if ( !matchIndex ) { - matchIndex = 0; - } - while ( ( match = re.exec( this.content ) ) !== null ) { - result.push( hope.range.create( match.index, match.index + match[matchIndex].length ) ); - if ( !re.global ) { - break; - } - } - return result; - }; - - this.create = function( content ) { - return new hopeTextFragment( content ); - }; - -}); \ No newline at end of file diff --git a/www/hope/hope.js b/www/hope/hope.js deleted file mode 100644 index be66cb7..0000000 --- a/www/hope/hope.js +++ /dev/null @@ -1,58 +0,0 @@ -var hope = this.hope = ( function( global ) { - - var registered = {}; - var hope = {}; - - function _namespaceWalk( module, handler ) { - var rest = module.replace(/^\s+|\s+$/g, ''); //trim - var name = ''; - var temp = hope.global; - var i = rest.indexOf( '.' ); - while ( i != -1 ) { - name = rest.substring( 0, i ); - if ( !temp[name]) { - temp = handler(temp, name); - if (!temp) { - return temp; - } - } - temp = temp[name]; - rest = rest.substring( i + 1 ); - i = rest.indexOf( '.' ); - } - if ( rest ) { - if ( !temp[rest] ) { - temp = handler(temp, rest); - if (!temp) { - return temp; - } - } - temp = temp[rest]; - } - return temp; - } - - hope.global = global; - - hope.register = function( module, implementation ) { - var moduleInstance = _namespaceWalk( module, function(ob, name) { - ob[name] = {}; - return ob; - }); - registered[module]=true; - if (typeof implementation == 'function') { - implementation.call(moduleInstance); - } - return moduleInstance; - }; - - hope.Exception = function(message, code) { - this.message = message; - this.code = code; - this.name = 'hope.Exception'; - }; - - return hope; - -} )(this); - diff --git a/www/hope/hope.keyboard.js b/www/hope/hope.keyboard.js deleted file mode 100644 index 1a96f44..0000000 --- a/www/hope/hope.keyboard.js +++ /dev/null @@ -1,214 +0,0 @@ -hope.register( 'hope.keyboard', function() { - var i; - - var self = this; - - var keyCodes = []; - keyCodes[3] = 'Cancel'; - keyCodes[6] = 'Help'; - keyCodes[8] = 'Backspace'; - keyCodes[9] = 'Tab'; - keyCodes[12] = 'Numlock-5'; - keyCodes[13] = 'Enter'; - - keyCodes[16] = 'Shift'; - keyCodes[17] = 'Control'; - keyCodes[18] = 'Alt'; - keyCodes[19] = 'Pause'; - keyCodes[20] = 'CapsLock'; - keyCodes[21] = 'KanaMode'; //HANGUL - - keyCodes[23] = 'JunjaMode'; - keyCodes[24] = 'FinalMode'; - keyCodes[25] = 'HanjaMode'; //KANJI - - keyCodes[27] = 'Escape'; - keyCodes[28] = 'Convert'; - keyCodes[29] = 'NonConvert'; - keyCodes[30] = 'Accept'; - keyCodes[31] = 'ModeChange'; - keyCodes[32] = 'Spacebar'; - keyCodes[33] = 'PageUp'; - keyCodes[34] = 'PageDown'; - keyCodes[35] = 'End'; - keyCodes[36] = 'Home'; - keyCodes[37] = 'ArrowLeft'; - keyCodes[38] = 'ArrowUp'; - keyCodes[39] = 'ArrowRight'; // opera has this as a "'" as well... - keyCodes[40] = 'ArrowDown'; - keyCodes[41] = 'Select'; - keyCodes[42] = 'Print'; - keyCodes[43] = 'Execute'; - keyCodes[44] = 'PrintScreen'; // opera ';'; - keyCodes[45] = 'Insert'; // opera has this as a '-' as well... - keyCodes[46] = 'Delete'; // opera - ','; - keyCodes[47] = '/'; // opera - - keyCodes[59] = ';'; - keyCodes[60] = '<'; - keyCodes[61] = '='; - keyCodes[62] = '>'; - keyCodes[63] = '?'; - keyCodes[64] = '@'; - - keyCodes[91] = 'OS'; // opera '['; - keyCodes[92] = 'OS'; // opera '\\'; - keyCodes[93] = 'ContextMenu'; // opera ']'; - keyCodes[95] = 'Sleep'; - keyCodes[96] = '`'; - - keyCodes[106] = '*'; // keypad - keyCodes[107] = '+'; // keypad - keyCodes[109] = '-'; // keypad - keyCodes[110] = 'Separator'; - keyCodes[111] = '/'; // keypad - - keyCodes[144] = 'NumLock'; - keyCodes[145] = 'ScrollLock'; - - keyCodes[160] = '^'; - keyCodes[161] = '!'; - keyCodes[162] = '"'; - keyCodes[163] = '#'; - keyCodes[164] = '$'; - keyCodes[165] = '%'; - keyCodes[166] = '&'; - keyCodes[167] = '_'; - keyCodes[168] = '('; - keyCodes[169] = ')'; - keyCodes[170] = '*'; - keyCodes[171] = '+'; - keyCodes[172] = '|'; - keyCodes[173] = '-'; - keyCodes[174] = '{'; - keyCodes[175] = '}'; - keyCodes[176] = '~'; - - keyCodes[181] = 'VolumeMute'; - keyCodes[182] = 'VolumeDown'; - keyCodes[183] = 'VolumeUp'; - - keyCodes[186] = ';'; - keyCodes[187] = '='; - keyCodes[188] = ','; - keyCodes[189] = '-'; - keyCodes[190] = '.'; - keyCodes[191] = '/'; - keyCodes[192] = '`'; - - keyCodes[219] = '['; - keyCodes[220] = '\\'; - keyCodes[221] = ']'; - keyCodes[222] = "'"; - keyCodes[224] = 'Meta'; - keyCodes[225] = 'AltGraph'; - - keyCodes[246] = 'Attn'; - keyCodes[247] = 'CrSel'; - keyCodes[248] = 'ExSel'; - keyCodes[249] = 'EREOF'; - keyCodes[250] = 'Play'; - keyCodes[251] = 'Zoom'; - keyCodes[254] = 'Clear'; - - // a-z - for ( i=65; i<=90; i++ ) { - keyCodes[i] = String.fromCharCode( i ).toLowerCase(); - } - - // 0-9 - for ( i=48; i<=57; i++ ) { - keyCodes[i] = String.fromCharCode( i ); - } - // 0-9 keypad - for ( i=96; i<=105; i++ ) { - keyCodes[i] = ''+(i-95); - } - - // F1 - F24 - for ( i=112; i<=135; i++ ) { - keyCodes[i] = 'F'+(i-111); - } - - function convertKeyNames( key ) { - switch ( key ) { - case ' ': - return 'Spacebar'; - case 'Esc' : - return 'Escape'; - case 'Left' : - case 'Up' : - case 'Right' : - case 'Down' : - return 'Arrow'+key; - case 'Del' : - return 'Delete'; - case 'Scroll' : - return 'ScrollLock'; - case 'MediaNextTrack' : - return 'MediaTrackNext'; - case 'MediaPreviousTrack' : - return 'MediaTrackPrevious'; - case 'Crsel' : - return 'CrSel'; - case 'Exsel' : - return 'ExSel'; - case 'Zoom' : - return 'ZoomToggle'; - case 'Multiply' : - return '*'; - case 'Add' : - return '+'; - case 'Subtract' : - return '-'; - case 'Decimal' : - return '.'; - case 'Divide' : - return '/'; - case 'Apps' : - return 'Menu'; - default: - return key; - } - } - - this.getKey = function( evt ) { - var keyInfo = ''; - if ( evt.ctrlKey && evt.keyCode != 17 ) { - keyInfo += 'Control+'; - } - if ( evt.metaKey && evt.keyCode != 224 ) { - keyInfo += 'Meta+'; - } - if ( evt.altKey && evt.keyCode != 18 ) { - keyInfo += 'Alt+'; - } - if ( evt.shiftKey && evt.keyCode != 16 ) { - keyInfo += 'Shift+'; - } - // evt.key turns shift+a into A, while keeping shiftKey, so it becomes Shift+A, instead of Shift+a. - // so while it may be the future, i'm not using it here. - if ( evt.charCode ) { - keyInfo += String.fromCharCode( evt.charCode ).toLowerCase(); - } else if ( evt.keyCode ) { - if ( typeof keyCodes[evt.keyCode] == 'undefined' ) { - keyInfo += '('+evt.keyCode+')'; - } else { - keyInfo += keyCodes[evt.keyCode]; - } - } else { - keyInfo += 'Unknown'; - } - return keyInfo; - }; - - this.listen = function( el, key, callback, capture ) { - return hope.editor.events.listen( el, 'keydown', function(evt) { - var pressedKey = self.getKey( evt ); - if ( key == pressedKey ) { - callback.call( this, evt ); - } - }, capture); - }; - -} ); \ No newline at end of file diff --git a/www/hope/hope.mime.js b/www/hope/hope.mime.js deleted file mode 100644 index 4d41993..0000000 --- a/www/hope/hope.mime.js +++ /dev/null @@ -1,85 +0,0 @@ -hope.register( 'hope.mime', function() { - // minimal mime encoding/decoding, stolen from https://github.com/andris9/mimelib/blob/master/lib/mimelib.js - var self = this; - - self.getHeaders = function( message ) { - var parseHeader = function( line ) { - if (!line) { - return {}; - } - - var result = {}, parts = line.split(";"), - pos; - - for (var i = 0, len = parts.length; i < len; i++) { - pos = parts[i].indexOf("="); - if (pos < 0) { - pos = parts[i].indexOf(':'); - } - if ( pos < 0 ) { - result[!i ? "defaultValue" : "i-" + i] = parts[i].trim(); - } else { - result[parts[i].substr(0, pos).trim().toLowerCase()] = parts[i].substr(pos + 1).trim(); - } - } - return result; - }; - var line = null; - var headers = {}; - var temp = {}; - line = message.match(/^.*$/m)[0]; - while ( line ) { - message = message.substring( line.length ); - temp = parseHeader( line ); - for ( var i in temp ) { - headers[i] = temp[i]; - } - var returns = message.match(/^\r?\n|\r/); - if ( returns[0] ) { - message = message.substring( returns[0].length ); - } - line = message.match(/^.*$/m)[0]; - } - return { - headers: headers, - message: message.substring(1) - }; - }; - - self.encode = function( parts, message, headers ) { - var boundary = 'hopeBoundary'+Date.now(); - var result = 'MIME-Version: 1.0\n'; - if ( headers ) { - result += headers.join("\n"); - } - result += 'Content-Type: multipart/related; boundary='+boundary+'\n\n'; - if ( message ) { - result += message; - } - for ( var i=0, l=parts.length; i= 0) { - k = n; - } else { - k = len + n; - if (k < 0) {k = 0;} - } - var currentElement; - while (k < len) { - currentElement = O[k]; - if (searchElement === currentElement || - (searchElement !== searchElement && currentElement !== currentElement)) { - return true; - } - k++; - } - return false; - }; -}/** - * hope.range - * - * This implements an immutable range object. - * Once created using hope.range.create() a range cannot change its start and end properties. - * Any method that needs to change start or end, will instead create a new range with the new start/end - * values and return that. - * If you need to change a range value in place, you can assign the return value back to the original variable, e.g.: - * range = range.collapse(); - */ - -hope.register( 'hope.range', function() { - - - function hopeRange( start, end ) { - if ( typeof end == 'undefined' || end < start ) { - end = start; - } - this.start = start; - this.end = end; - Object.freeze(this); - } - - hopeRange.prototype = { - constructor: hopeRange, - get length () { - return this.end - this.start; - } - }; - - hopeRange.prototype.collapse = function( toEnd ) { - var start = this.start; - var end = this.end; - if ( toEnd ) { - start = end; - } else { - end = start; - } - return new hopeRange(start, end ); - }; - - hopeRange.prototype.compare = function( range ) { - range = hope.range.create(range); - if ( range.start < this.start ) { - return 1; - } else if ( range.start > this.start ) { - return -1; - } else if ( range.end < this.end ) { - return 1; - } else if ( range.end > this.end ) { - return -1; - } - return 0; - }; - - hopeRange.prototype.equals = function( range ) { - return this.compare(range)===0; - }; - - hopeRange.prototype.smallerThan = function( range ) { - return ( this.compare( range ) == -1 ); - }; - - hopeRange.prototype.largerThan = function( range ) { - return ( this.compare( range ) == 1 ); - }; - - hopeRange.prototype.contains = function( range ) { - range = hope.range.create(range); - return this.start <= range.start && this.end >= range.end; - }; - - hopeRange.prototype.overlaps = function( range ) { - range = hope.range.create(range); - if (range.equals(this)) { - return true; - } - - // not overlapping if only the edges touch... - if ((range.start == this.end) && (range.start < range.end)) { - return false; - } - if ((range.end == this.start) && (range.start < range.end)) { - return false; - } - - // but overlapping if the range to check is collapsed - if ((range.start == this.end) && (range.start == range.end)) { - return true; - } - if ((range.end == this.start) && (range.start == range.end)) { - return true; - } - - return ( range.start <= this.end && range.end >= this.start ); - }; - - hopeRange.prototype.isEmpty = function() { - return this.start >= this.end; - }; - - hopeRange.prototype.overlap = function( range ) { - range = hope.range.create(range); - var start = 0; - var end = 0; - if ( this.overlaps( range ) ) { - if ( range.start < this.start ) { - start = this.start; - } else { - start = range.start; - } - if ( range.end < this.end ) { - end = range.end; - } else { - end = this.end; - } - } - return new hopeRange(start, end); // FIXME: is this range( 0, 0 ) a useful return value when there is no overlap? - }; - - hopeRange.prototype.exclude = function( range ) { - // return parts of this that do not overlap with range - var left = null; - var right = null; - if ( this.equals(range) ) { - // nop - } else if ( this.overlaps( range ) ) { - left = new hopeRange( this.start, range.start ); - right = new hopeRange( range.end, this.end ); - if ( left.isEmpty() ) { - left = null; - } - if ( right.isEmpty() ) { - right = null; - } - } else if ( this.largerThan(range) ) { - left = null; - right = right; - } else { - left = this; - right = left; - } - return [ left, right ]; - }; - - hopeRange.prototype.excludeLeft = function( range ) { - return this.exclude(range)[0]; - }; - - hopeRange.prototype.excludeRight = function( range ) { - return this.exclude(range)[1]; - }; - - /** - * remove overlapping part of range from this range - * [ 5 .. 20 ].delete( 10, 25 ) => [ 5 .. 10 ] - * [ 5 .. 20 ].delete( 10, 15) => [ 5 .. 15 ] - * [ 5 .. 20 ].delete( 5, 20 ) => [ 5 .. 5 ] - * [ 5 .. 20 ].delete( 0, 10 ) => [ 0 .. 10 ] ? - */ - hopeRange.prototype.delete = function( range ) { - range = hope.range.create(range); - var moveLeft = 0; - var end = this.end; - if ( this.overlaps(range) ) { - var cutRange = this.overlap( range ); - var cutLength = cutRange.length; - end -= cutLength; - } - var result = new hopeRange( this.start, end ); - var exclude = range.excludeLeft( this ); - if ( exclude ) { - result = result.move( -exclude.length ); - } - return result; - }; - - hopeRange.prototype.copy = function( range ) { - range = hope.range.create(range); - return new hopeRange( 0, this.overlap( range ).length ); - }; - - hopeRange.prototype.extend = function( length, direction ) { - var start = this.start; - var end = this.end; - if ( !direction ) { - direction = 1; - } - if ( direction == 1 ) { - end += length; - } else { - start = Math.max( 0, start - length ); - } - return new hopeRange(start, end); - }; - - hopeRange.prototype.toString = function() { - if ( this.start != this.end ) { - return this.start + '-' + this.end; - } else { - return this.start + ''; - } - }; - - hopeRange.prototype.grow = function( size ) { - var end = this.end + size; - if ( end < this.start ) { - end = this.start; - } - return new hopeRange(this.start, end); - }; - - hopeRange.prototype.shrink = function( size ) { - return this.grow( -size ); - }; - - hopeRange.prototype.move = function( length, min, max ) { - var start = this.start; - var end = this.end; - start += length; - end += length; - if ( !min ) { - min = 0; - } - start = Math.max( min, start ); - end = Math.max( start, end ); - if ( max ) { - start = Math.min( max, start ); - end = Math.min( max, start ); - } - return new hopeRange(start, end); - }; - - this.create = function( start, end ) { - if ( start instanceof hopeRange ) { - return start; - } - if ( typeof end =='undefined' && parseInt(start,10)==start ) { - end = start; - } else if ( Array.isArray(start) && typeof start[1] != 'undefined' ) { - end = start[1]; - start = start[0]; - } - return new hopeRange( parseInt(start), parseInt(end) ); - }; - -});hope.register( 'hope.annotation', function() { - - function hopeAnnotation(range, tag) { - this.range = hope.range.create(range); - this.tag = tag; - Object.freeze(this); - } - - hopeAnnotation.prototype.delete = function( range ) { - return new hopeAnnotation( this.range.delete( range ), this.tag ); - }; - - hopeAnnotation.prototype.copy = function( range ) { - return new hopeAnnotation( this.range.copy( range ), this.tag ); - }; - - hopeAnnotation.prototype.compare = function( annotation ) { - return this.range.compare( annotation.range ); - }; - - hopeAnnotation.prototype.has = function( tag ) { - //FIXME: should be able to specify attributes and attribute values as well - return this.stripTag() == hope.annotation.stripTag(tag); - }; - - hopeAnnotation.prototype.toString = function() { - return this.range + ':' + this.tag; - }; - - hopeAnnotation.prototype.stripTag = function() { - return hope.annotation.stripTag(this.tag); - }; - - hopeAnnotation.prototype.isBlock = function() { - return (hope.render.html.rules.nestingSets.block.indexOf(hope.annotation.stripTag(this.tag)) != -1 ); // FIXME: this should not know about hope.render.html; - }; - - this.create = function( range, tag ) { - return new hopeAnnotation( range, tag ); - }; - - this.stripTag = function(tag) { - return tag.split(' ')[0]; - }; -}); - -hope.register( 'hope.fragment', function() { - - var self = this; - - function hopeFragment( text, annotations ) { - this.text = hope.fragment.text.create( text ); - this.annotations = hope.fragment.annotations.create( annotations ); - Object.freeze(this); - } - - hopeFragment.prototype.delete = function( range ) { - return new hopeFragment( - this.text.delete( range ), - this.annotations.delete( range ) - ); - }; - - hopeFragment.prototype.copy = function( range ) { - // return copy fragment at range with the content and annotations at that range - return new hopeFragment( - this.text.copy( range ), - this.annotations.copy( range ).delete( hope.range.create( 0, range.start ) ) - ); - }; - - hopeFragment.prototype.insert = function( position, fragment ) { - if ( ! ( fragment instanceof hopeFragment ) ) { - fragment = new hopeFragment( fragment ); - } - var result = new hopeFragment( - this.text.insert(position, fragment.text), - this.annotations.grow(position, fragment.text.length ) - ); - for ( var i=0, l=fragment.annotations.length; i0); - //}); - list.sort( function( a, b ) { - return a.compare( b ); - }); - return new hopeAnnotationList(list); - }; - - hopeAnnotationList.prototype.apply = function( range, tag ) { - var list = this.list.slice(); - list.push( hope.annotation.create( range, tag ) ); - return new hopeAnnotationList(list).clean(); - }; - - hopeAnnotationList.prototype.grow = function( position, size ) { - var i; - - function getBlockIndexes(list, index, position) { - var blockIndexes = []; - for ( var i=index-1; i>=0; i-- ) { - if ( list[i].range.contains([position-1, position]) && list[i].isBlock() ) { - blockIndexes.push(i); - } - } - return blockIndexes; - } - - var list = this.list.slice(); - var removeRange = false; - var growRange = false; - var removeList = []; - var foundCaret = false; - if ( size < 0 ) { - removeRange = hope.range.create( position + size, position ); - } else { - growRange = hope.range.create( position, position + size ); - } - for ( i=0, l=list.length; i= list[i].range.start && removeRange.start <= list[i].range.start ) { - // range to remove overlaps start of this range, but is not equal - if ( list[i].isBlock() ) { - // block annotation must be merged with previous annotation, if available - // get block annotation at start of removeRange - var prevBlockIndexes = getBlockIndexes(list, i, removeRange.start); - if ( prevBlockIndexes.length === 0 ) { - // no block element in removeRange.start, so just move this block element - list[i] = hope.annotation.create( list[i].range.delete( removeRange ), list[i].tag ); - } else { - // prevBlocks must now contain this block - for ( var ii=0, ll=prevBlockIndexes.length; ii= list[i].range.end ) { - // range to remove overlaps end of this range, but is not equal - // if this range needs to be extended, that will done when we find the next block range - // so just shrink this range - list[i] = hope.annotation.create( list[i].range.delete( removeRange ), list[i].tag ); - } - } else if (growRange) { - var range; - if ( list[i].range.start == position ) { - if (list[i].tag.indexOf("data-hope-caret") > -1) { - foundCaret = true; - range = list[i].range.grow( size ); - list[i] = hope.annotation.create( range, list[i].tag ); - } else { - if (foundCaret) { - range = list[i].range.move( size, position ); - list[i] = hope.annotation.create( range, list[i].tag ); - } - } - } else if (list[i].range.end == position ) { - if (list[i].tag.indexOf("data-hope-caret") > -1) { - foundCaret = true; - range = list[i].range.grow( size ); - list[i] = hope.annotation.create( range, list[i].tag ); - } else { - if (foundCaret) { - range = list[i].range.grow( size ); - list[i] = hope.annotation.create( range, list[i].tag ); - } - } - } else if ( list[i].range.start > position ) { - range = list[i].range.move( size, position ); - list[i] = hope.annotation.create( range, list[i].tag ); - } else if ( list[i].range.end > position ) { - range = list[i].range.grow( size ); - list[i] = hope.annotation.create( range, list[i].tag ); - } - } - } - // now remove indexes in removeList from list - for ( i=removeList.length-1; i>=0; i--) { - list.splice( removeList[i], 1); - } - return new hopeAnnotationList(list).clean(); - }; - - hopeAnnotationList.prototype.clear = function( range ) { - var i; - range = hope.range.create(range); - var list = this.list.slice(); - var remove = []; - for ( i=0, l=list.length; i range.start ) { - list[i] = hope.annotation.create( [range.end, listRange.end], list[i].tag ); - } else if ( listRange.end <= range.end ) { - list[i] = hope.annotation.create( [listRange.start, range.start], list[i].tag ); - } - } - } - for ( i=remove.length-1; i>=0; i-- ) { - list.splice( remove[i], 1); - } - return new hopeAnnotationList(list).clean(); - }; - - hopeAnnotationList.prototype.remove = function( range, tag ) { - var i; - range = hope.range.create(range); - var list = this.list.slice(); - var remove = []; - var add = []; - for ( i=0, l=list.length; irange.end) { - // range is enclosed entirely in annotation range - list[i] = hope.annotation.create( - [ listRange.start, range.start ], - list[i].tag - ); - add.push( hope.annotation.create( - [ range.end, listRange.end ], - list[i].tag - )); - } else if ( listRange.start < range.start ) { - // range overlaps annotation to the right - list[i] = hope.annotation.create( - [ listRange.start, range.start ], - list[i].tag - ); - } else if ( listRange.end > range.end ) { - // range overlaps annotation to the left - list[i] = hope.annotation.create( - [ range.end, listRange.end ], - list[i].tag - ); - } - - } - for ( i=remove.length-1;i>=0; i-- ) { - list.splice( remove[i], 1); - } - list = list.concat(add); - return new hopeAnnotationList(list).clean(); - }; - - hopeAnnotationList.prototype.delete = function( range ) { - range = hope.range.create(range); - return this.grow( range.end, -range.length ); - }; - - hopeAnnotationList.prototype.copy = function( range ) { - range = hope.range.create(range); - var copy = []; - for ( var i=0, l=this.list.length; i 0 ) { - current++; - } - if ( current < 0 ) { - current = 0; - } - if ( !groupedList[current] ) { - groupedList[current] = { offset: eventList[i].offset, markup: [] }; - } - groupedList[current].markup.push( { type: eventList[i].type, index: eventList[i].index } ); - } - return groupedList; - } - - var relativeList = getUnsortedEventList.call(this); - relativeList.sort(function(a,b) { - if ( a.offset < b.offset ) { - return -1; - } else if ( a.offset > b.offset ) { - return 1; - } - return 0; - }); - relativeList = calculateRelativeOffsets.call( this, relativeList ); - relativeList = groupByOffset.call( this, relativeList ); - return relativeList; - }; - - this.create = function( annotations ) { - return new hopeAnnotationList( annotations ); - }; - -});hope.register( 'hope.fragment.text', function() { - - function hopeTextFragment( text ) { - this.content = text+''; - } - - hopeTextFragment.prototype = { - constructor: hopeTextFragment, - get length () { - return this.content.length; - } - }; - - hopeTextFragment.prototype.delete = function( range ) { - range = hope.range.create(range); - // cut range from content, return the cut content - if ( range.start >= range.end ) { - return this; - } else { - return new hopeTextFragment( this.content.slice( 0, range.start ) + this.content.slice( range.end ) ); - } - }; - - hopeTextFragment.prototype.copy = function( range ) { - range = hope.range.create(range); - // return copy of content at range - return new hopeTextFragment( this.content.slice( range.start, range.end ) ); - }; - - hopeTextFragment.prototype.insert = function( position, content ) { - // insert fragment at range, return cut fragment - return new hopeTextFragment( this.content.slice( 0, position ) + content + this.content.slice( position ) ); - }; - - hopeTextFragment.prototype.toString = function() { - return this.content; - }; - - hopeTextFragment.prototype.search = function( re, matchIndex ) { - function escapeRegExp(s) { - return s.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&'); - } - if ( ! ( re instanceof RegExp ) ) { - re = new RegExp( escapeRegExp( re ) , 'g' ); - } - var result = []; - var match = null; - if ( !matchIndex ) { - matchIndex = 0; - } - while ( ( match = re.exec( this.content ) ) !== null ) { - result.push( hope.range.create( match.index, match.index + match[matchIndex].length ) ); - if ( !re.global ) { - break; - } - } - return result; - }; - - this.create = function( content ) { - return new hopeTextFragment( content ); - }; - -});hope.register( 'hope.render.html', function() { - - var nestingSets = { - 'inline' : [ 'tt', 'u', 'strike', 'em', 'strong', 'dfn', 'code', 'samp', 'kbd', 'var', 'cite', 'abbr', 'acronym', 'sub', 'sup', 'q', 'span', 'bdo', 'a', 'object', 'img', 'bd', 'br', 'i' ], - 'block' : [ 'address', 'dir', 'menu', 'hr', 'li', 'table', 'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'pre', 'ul', 'ol', 'dl', 'div', 'blockquote', 'iframe' ] - }; - - nestingSets.all = nestingSets.block.concat( nestingSets.inline ); - - this.rules = { - nesting: { - 'a' : nestingSets.inline.filter( function(element) { return element != 'a'; } ), - 'abbr' : nestingSets.inline, - 'acronym' : nestingSets.inline, - 'address' : [ 'p' ].concat( nestingSets.inline ), - 'bdo' : nestingSets.inline, - 'blockquote': nestingSets.all, - 'br' : [], - 'caption' : nestingSets.inline, - 'cite' : nestingSets.inline, - 'code' : nestingSets.inline, - 'col' : [], - 'colgroup' : [ 'col' ], - 'dd' : nestingSets.all, - 'dfn' : nestingSets.inline, - 'dir' : [ 'li' ], - 'div' : nestingSets.all, - 'dl' : [ 'dt', 'dd' ], - 'dt' : nestingSets.inline, - 'em' : nestingSets.inline, - 'h1' : nestingSets.inline, - 'h2' : nestingSets.inline, - 'h3' : nestingSets.inline, - 'h4' : nestingSets.inline, - 'h5' : nestingSets.inline, - 'h6' : nestingSets.inline, - 'hr' : [], - 'img' : [], - 'kbd' : nestingSets.inline, - 'li' : nestingSets.all, - 'menu' : [ 'li' ], - 'object' : [ 'param' ].concat( nestingSets.all ), - 'ol' : [ 'li' ], - 'p' : nestingSets.inline, - 'pre' : nestingSets.inline, - 'q' : nestingSets.inline, - 'samp' : nestingSets.inline, - 'span' : nestingSets.inline, - 'strike' : nestingSets.inline, - 'strong' : nestingSets.inline, - 'sub' : nestingSets.inline, - 'sup' : nestingSets.inline, - 'table' : [ 'caption', 'colgroup', 'col', 'thead', 'tbody' ], - 'tbody' : [ 'tr' ], - 'td' : nestingSets.all, - 'th' : nestingSets.all, - 'thead' : [ 'tr' ], - 'tr' : [ 'td', 'th' ], - 'tt' : nestingSets.inline, - 'u' : nestingSets.inline, - 'ul' : [ 'li' ], - 'var' : nestingSets.inline - }, - // which html elements can not have child elements at all and shouldn't be closed - 'noChildren' : [ 'hr', 'br', 'col', 'img' ], - // which html elements must have a specific child element - 'obligChild' : { - 'ol' : [ 'li' ], - 'ul' : [ 'li' ], - 'dl' : [ 'dt', 'dd' ] - }, - // which html elements must have a specific parent element - 'obligParent' : { - 'li' : [ 'ul', 'ol', 'dir', 'menu' ], - 'dt' : [ 'dl' ], - 'dd' : [ 'dl' ] - }, - // which html elements to allow as the top level, default is only block elements - 'toplevel' : nestingSets.block.concat(nestingSets.inline), // [ 'li', 'img', 'span', 'strong', 'em', 'code' ], - 'nestingSets' : nestingSets - }; - - this.getTag = function( markup ) { - return markup.split(' ')[0].toLowerCase(); // FIXME: more robust parsing needed - }; - - this.getAnnotationStack = function( annotationSet ) { - // { index:nextAnnotationEntry.index, entry:nextAnnotation } - // { start:, end:, annotation: } - // assert: annotationSet must only contain annotation that has overlapping ranges - // if not results will be unpredictable - var annotationStack = []; - if ( !annotationSet.length ) { - return []; - } - - var rules = this.rules; - - annotationSet.sort( function( a, b ) { - if ( a.range.start < b.range.start ) { - return -1; - } else if ( a.range.start > b.range.start ) { - return 1; - } else if ( a.range.end > b.range.end ) { - return -1; - } else if ( a.range.end < b.range.end ) { - return 1; - } - - // if comparing ul/ol and li on the same range, ul/ol goes first; - if (rules.obligParent[a.tag.split(/ /)[0]]) { - if (rules.obligParent[a.tag.split(/ /)[0]].indexOf(b.tag.split(/ /)[0]) != -1) { - return 1; - } - } - if (rules.obligParent[b.tag.split(/ /)[0]]) { - if (rules.obligParent[b.tag.split(/ /)[0]].indexOf(a.tag.split(/ /)[0]) != -1) { - return -1; - } - } - - // block elementen komen voor andere elementen - if (nestingSets.block.indexOf(a.tag.split(/ /)[0]) != '-1') { - return -1; - } - if (nestingSets.block.indexOf(b.tag.split(/ /)[0]) != '-1') { - return 1; - } - - // hack om hyperlinks met images er in te laten werken. - if (a.tag.split(/ /)[0] == 'a') { - return -1; - } - if (b.tag.split(/ /)[0] == 'a') { - return 1; - } - - // daarna komen inline elementen - if (nestingSets.inline.indexOf(a.tag.split(/ /)[0]) != '-1') { - return -1; - } - if (nestingSets.inline.indexOf(b.tag.split(/ /)[0]) != '-1') { - return 1; - } - - return 0; - }); - var unfilteredStack = []; - for ( var i=0, l=annotationSet.length; icommonIndex; i-- ) { - annotationDiff.push( { type : 'close', annotation : annotationStackFrom[i] } ); - } - for ( i=commonIndex+1, l=annotationStackTo.length; i'; - } - } else if ( annotationDiff[i].type == 'insert' ) { - renderedDiff += '<' + annotationDiff[i].annotation.tag + '>'; - annotationTag = this.getTag( annotationDiff[i].annotation.tag ); - if ( this.rules.noChildren.indexOf( annotationTag ) == -1 ) { - renderedDiff += ''; - } - } else { - renderedDiff += '<' + annotationDiff[i].annotation.tag + '>'; - } - } - return renderedDiff; - }; - - this.escape = function( content ) { - return content - .replace(/&/g, "&") - .replace(//g, ">") - .replace(/"/g, """) - .replace(/'/g, "'"); - }; - - this.render = function( fragment ) { - // FIXME: annotation should be the relative annotation list to speed things up - var annotationSet = []; // set of applicable annotation at current position - var annotationStack = []; // stack of applied (valid) annotation at current position - - var relativeAnnotation = fragment.annotations.getEventList(); - var content = fragment.text.toString(); - - var renderedHTML = ''; - var cursor = 0; - - while ( relativeAnnotation.length ) { - - var annotationChangeSet = relativeAnnotation.shift(); - var annotationAdded = []; // list of annotation added in this change set - var annotationSetOnce = []; // list of annotation that can not have children, needs no close - for ( i=0, l=annotationChangeSet.markup.length; i 0 ) { - if (diffHTML && ( - diffHTML.indexOf("
") !== -1 || - diffHTML.indexOf("
") !== -1 || - diffHTML.indexOf("= caret) { - try { - selection.setStart(node.childNodes[i], caret - nodeOffset); - } catch (e) { - console.log("Warning: could not set caret position"); - } - node.removeAttribute("data-hope-caret"); - return selection; - } - } - - } - - function tagsToText(tags) { - var result = ''; - var i,j; - - for (i=0; i -1) { - result += " data-hope-caret=\"" + tags[i].caret + "\""; - } - result += "\n"; - } - return result; - } - - function hopeEditor( textEl, annotationsEl, outputEl, renderEl ) { - this.refs = { - text: textEl, - annotations: annotationsEl, - output: outputEl, - render: renderEl - }; - this.selection = hope.editor.selection.create(0,0,this); - this.commandsKeyUp = {}; - - if (this.refs.output.innerHTML !== '') { - this.refs.output.innerHTML = this.refs.output.innerHTML.replace(/\/p>/g, "/p>"); - this.parseHTML(); - } - - this.browserCountsWhitespace = browserCountsWhitespace; - - var text = this.refs.text.value; - var annotations = this.refs.annotations.value; - this.fragment = hope.fragment.create( text, annotations ); - this.refs.output.contentEditable = true; - this.update(); - this.initDone = true; -// initEvents(this); - } - - function initEvents(editor) { - hope.events.listen(editor.refs.output, 'keypress', function( evt ) { - if ( !evt.ctrlKey && !evt.altKey ) { - // check selection length - // remove text in selection - // add character - var range = editor.selection.getRange(); - var charCode = evt.which; - - if (evt.which) { - var charTyped = String.fromCharCode(charCode); - if ( charTyped ) { // ignore non printable characters - if ( range.length ) { - editor.fragment = editor.fragment.delete(range); - } - editor.fragment = editor.fragment.insert(range.start, charTyped ); - editor.selection.collapse().move(1); - setTimeout( function() { - editor.update(); - }, 0 ); - } - return hope.events.cancel(evt); - } - } - }); - - hope.events.listen(editor.refs.output, 'keydown', function( evt ) { - var key = hope.keyboard.getKey( evt ); - if ( editor.commands[key] ) { - var range = editor.selection.getRange(); - editor.commands[key].call(editor, range); - setTimeout( function() { - editor.update(); - }, 0); - return hope.events.cancel(evt); - } else if ( evt.ctrlKey || evt.altKey ) { - return hope.events.cancel(evt); - } - }); - - hope.events.listen(editor.refs.output, 'keyup', function( evt ) { - var key = hope.keyboard.getKey( evt ); - if ( editor.selection.cursorCommands.indexOf(key)<0 ) { - if ( editor.commandsKeyUp[key] ) { - var range = editor.selection.getRange(); - editor.commandsKeyUp[key].call(editor, range); - setTimeout( function() { - editor.update(); - }, 0); - } - return hope.events.cancel(evt); - } - }); - - } - - hopeEditor.prototype.setCaretOffset = setCaretOffset; - hopeEditor.prototype.getCaretOffset = getCaretOffset; - hopeEditor.prototype.unrender = unrender; - - hopeEditor.prototype.parseHTML = function() { - hopeTokenCounter = 0; - - var data = this.unrender(this.refs.output); - this.refs.annotations.value = tagsToText(data.tags); - this.refs.text.value = data.text; - this.fragment = hope.fragment.create( this.refs.text.value, this.refs.annotations.value ); - }; - - hopeEditor.prototype.getEditorRange = function(start, end ) { - var treeWalker = document.createTreeWalker( - this.refs.output, - NodeFilter.SHOW_TEXT | NodeFilter.SHOW_ELEMENT, - function(node) { - if ( - node.nodeType == document.TEXT_NODE || - !node.hasChildNodes() - ) { - return NodeFilter.FILTER_ACCEPT; - } else { - return NodeFilter.FILTER_SKIP; - } - }, - false - ); - var offset = 0; - var node = null; - var range = document.createRange(); - var lastNode = null; - do { - lastNode = node; - node = treeWalker.nextNode(); - if ( node ) { - if (node.nodeType == document.ELEMENT_NODE) { - offset += 1; - } else { - offset += node.textContent.length; - } - } - } while ( offset < start && node ); - if ( !node ) { - if (lastNode) { - if (lastNode.nodeType == document.ELEMENT_NODE) { - range.setStart(lastNode, 0); - range.setEndAfter(lastNode); - } else { - range.setStart(lastNode, lastNode.textContent ? lastNode.textContent.length : 1 ); - range.setEnd(lastNode, lastNode.textContent ? lastNode.textContent.length : 1 ); - } - return range; - } - return false; - } - - var preOffset = offset - (node.nodeType == document.TEXT_NODE ? node.textContent.length : 1); - var nextNode; - if (node.nodeType == document.ELEMENT_NODE) { - nextNode = treeWalker.nextNode(); - treeWalker.previousNode(); - if (nextNode) { - range.setStartBefore(nextNode); - } else { - range.setStartAfter(node); - } - } else { - if (start-preOffset == node.textContent.length) { - nextNode = treeWalker.nextNode(); - treeWalker.previousNode(); - if (nextNode) { - range.setStartBefore(nextNode); - } else { - range.setStartAfter(node); - } - } else { - range.setStart(node, start - preOffset ); - } - } - while ( offset < end && node ) { - node = treeWalker.nextNode(); - if ( node ) { - if (node.nodeType == document.ELEMENT_NODE) { - offset += 1; - } else { - offset += node.textContent.length; - } - } - } - if ( !node ) { - if (lastNode) { - range.setEnd(lastNode, lastNode.textContent ? lastNode.textContent.length : 1 ); - return range; - } - return false; - } - - preOffset = offset - (node.nodeType == document.TEXT_NODE ? node.textContent.length : 1); - - if (node.nodeType == document.ELEMENT_NODE) { - range.setEndAfter(node); - } else { - range.setEnd(node, end - preOffset ); - } - return range; - }; - - hopeEditor.prototype.showCursor = function() { - var range = this.selection.getRange(); - var selection = this.getEditorRange(range.start, range.end); - var caretElm = document.querySelector('[data-hope-caret]'); - if (caretElm) { - selection = this.setCaretOffset(caretElm); - } - // remove all other caret attributes from the other elements; - var otherCarets = document.querySelectorAll('[data-hope-caret]'); - for (var i=0; i', '>'); - } - if ( this.refs.annotations ) { - this.refs.annotations.value = this.fragment.annotations+''; - } - }; - - hopeEditor.prototype.command = function( key, callback, keyup ) { - if ( keyup ) { - this.commandsKeyUp[key] = callback; - } else { - this.commands[key] = callback; - } - }; - - this.create = function( textEl, annotationsEl, outputEl, previewEl ) { - return new hopeEditor( textEl, annotationsEl, outputEl, previewEl); - }; - -});hope.register( 'hope.editor.selection', function() { - function hopeEditorSelection(start, end, editor) { - this.start = start; - this.end = end; - this.editor = editor; - - var self = this; - - var updateRange = function() { - var sel = window.getSelection(); - var rangeStart, rangeEnd; - var bestStart, bestEnd; - - if (sel.rangeCount) { - for (var i=0; i not a text node - var nodeRect = null; - var range = null; - var rangeRect = null; - var yBias = null; - // find textnode to place cursor in - do { - node = this.getNextTextNode(node); - if ( node ) { - range = document.createRange(); - range.setStart(node, 0); - range.setEnd(node, node.textContent.length); - nodeRect = range.getBoundingClientRect(); - if ( !yBias ) { - if ( nodeRect.top > cursorRect.top ) { - yBias = nodeRect.top; - } else { - yBias = cursorRect.top; - } - } - } - } while ( node && nodeRect.height!==0 && nodeRect.top <= yBias ); //< cursorRect.bottom ); //left >= this.xBias ); - - if ( node && nodeRect.right >= this.xBias ) { - // find range in textnode to set cursor to - var nodeLength = node.textContent.length; - range.setEnd( node, 0 ); - var offset = 0; - do { - offset++; - range.setStart( node, offset); - range.setEnd( node, offset); - rangeRect = range.getBoundingClientRect(); - } while ( - offset < nodeLength && - ( - (rangeRect.top <= yBias ) || - ( rangeRect.right < this.xBias) - ) - ); - - return range.endOffset + this.getTotalOffset(node); // should check distance for end-1 as well - } else if ( node && range ) { - range.setStart( range.endContainer, range.endOffset ); - rangeRect = range.getBoundingClientRect(); - if ( rangeRect.top > yBias ) { - // cannot set cursor to x pos > xBias, so get rightmost position in current node - range.setEnd(node, node.textContent.length); - return range.endOffset + this.getTotalOffset(node); - } else { - // cursor cannot advance further - return this.getCursor(); - } - } else { - return this.getCursor(); - } - }; - - - this.create = function(start, end, editor) { - return new hopeEditorSelection(start, end, editor); - }; - -}); \ No newline at end of file diff --git a/www/hope/hope.polyfills.js b/www/hope/hope.polyfills.js deleted file mode 100644 index 67345af..0000000 --- a/www/hope/hope.polyfills.js +++ /dev/null @@ -1,30 +0,0 @@ -if (![].includes) { - Array.prototype.includes = function(searchElement /*, fromIndex*/ ) {'use strict'; - if (this === undefined || this === null) { - throw new TypeError('Cannot convert this value to object'); - } - var O = Object(this); - var len = parseInt(O.length) || 0; - if (len === 0) { - return false; - } - var n = parseInt(arguments[1]) || 0; - var k; - if (n >= 0) { - k = n; - } else { - k = len + n; - if (k < 0) {k = 0;} - } - var currentElement; - while (k < len) { - currentElement = O[k]; - if (searchElement === currentElement || - (searchElement !== searchElement && currentElement !== currentElement)) { - return true; - } - k++; - } - return false; - }; -} \ No newline at end of file diff --git a/www/hope/hope.range.js b/www/hope/hope.range.js deleted file mode 100644 index 1d09c39..0000000 --- a/www/hope/hope.range.js +++ /dev/null @@ -1,247 +0,0 @@ -/** - * hope.range - * - * This implements an immutable range object. - * Once created using hope.range.create() a range cannot change its start and end properties. - * Any method that needs to change start or end, will instead create a new range with the new start/end - * values and return that. - * If you need to change a range value in place, you can assign the return value back to the original variable, e.g.: - * range = range.collapse(); - */ - -hope.register( 'hope.range', function() { - - - function hopeRange( start, end ) { - if ( typeof end == 'undefined' || end < start ) { - end = start; - } - this.start = start; - this.end = end; - Object.freeze(this); - } - - hopeRange.prototype = { - constructor: hopeRange, - get length () { - return this.end - this.start; - } - }; - - hopeRange.prototype.collapse = function( toEnd ) { - var start = this.start; - var end = this.end; - if ( toEnd ) { - start = end; - } else { - end = start; - } - return new hopeRange(start, end ); - }; - - hopeRange.prototype.compare = function( range ) { - range = hope.range.create(range); - if ( range.start < this.start ) { - return 1; - } else if ( range.start > this.start ) { - return -1; - } else if ( range.end < this.end ) { - return 1; - } else if ( range.end > this.end ) { - return -1; - } - return 0; - }; - - hopeRange.prototype.equals = function( range ) { - return this.compare(range)===0; - }; - - hopeRange.prototype.smallerThan = function( range ) { - return ( this.compare( range ) == -1 ); - }; - - hopeRange.prototype.largerThan = function( range ) { - return ( this.compare( range ) == 1 ); - }; - - hopeRange.prototype.contains = function( range ) { - range = hope.range.create(range); - return this.start <= range.start && this.end >= range.end; - }; - - hopeRange.prototype.overlaps = function( range ) { - range = hope.range.create(range); - if (range.equals(this)) { - return true; - } - - // not overlapping if only the edges touch... - if ((range.start == this.end) && (range.start < range.end)) { - return false; - } - if ((range.end == this.start) && (range.start < range.end)) { - return false; - } - - // but overlapping if the range to check is collapsed - if ((range.start == this.end) && (range.start == range.end)) { - return true; - } - if ((range.end == this.start) && (range.start == range.end)) { - return true; - } - - return ( range.start <= this.end && range.end >= this.start ); - }; - - hopeRange.prototype.isEmpty = function() { - return this.start >= this.end; - }; - - hopeRange.prototype.overlap = function( range ) { - range = hope.range.create(range); - var start = 0; - var end = 0; - if ( this.overlaps( range ) ) { - if ( range.start < this.start ) { - start = this.start; - } else { - start = range.start; - } - if ( range.end < this.end ) { - end = range.end; - } else { - end = this.end; - } - } - return new hopeRange(start, end); // FIXME: is this range( 0, 0 ) a useful return value when there is no overlap? - }; - - hopeRange.prototype.exclude = function( range ) { - // return parts of this that do not overlap with range - var left = null; - var right = null; - if ( this.equals(range) ) { - // nop - } else if ( this.overlaps( range ) ) { - left = new hopeRange( this.start, range.start ); - right = new hopeRange( range.end, this.end ); - if ( left.isEmpty() ) { - left = null; - } - if ( right.isEmpty() ) { - right = null; - } - } else if ( this.largerThan(range) ) { - left = null; - right = right; - } else { - left = this; - right = left; - } - return [ left, right ]; - }; - - hopeRange.prototype.excludeLeft = function( range ) { - return this.exclude(range)[0]; - }; - - hopeRange.prototype.excludeRight = function( range ) { - return this.exclude(range)[1]; - }; - - /** - * remove overlapping part of range from this range - * [ 5 .. 20 ].delete( 10, 25 ) => [ 5 .. 10 ] - * [ 5 .. 20 ].delete( 10, 15) => [ 5 .. 15 ] - * [ 5 .. 20 ].delete( 5, 20 ) => [ 5 .. 5 ] - * [ 5 .. 20 ].delete( 0, 10 ) => [ 0 .. 10 ] ? - */ - hopeRange.prototype.delete = function( range ) { - range = hope.range.create(range); - var moveLeft = 0; - var end = this.end; - if ( this.overlaps(range) ) { - var cutRange = this.overlap( range ); - var cutLength = cutRange.length; - end -= cutLength; - } - var result = new hopeRange( this.start, end ); - var exclude = range.excludeLeft( this ); - if ( exclude ) { - result = result.move( -exclude.length ); - } - return result; - }; - - hopeRange.prototype.copy = function( range ) { - range = hope.range.create(range); - return new hopeRange( 0, this.overlap( range ).length ); - }; - - hopeRange.prototype.extend = function( length, direction ) { - var start = this.start; - var end = this.end; - if ( !direction ) { - direction = 1; - } - if ( direction == 1 ) { - end += length; - } else { - start = Math.max( 0, start - length ); - } - return new hopeRange(start, end); - }; - - hopeRange.prototype.toString = function() { - if ( this.start != this.end ) { - return this.start + '-' + this.end; - } else { - return this.start + ''; - } - }; - - hopeRange.prototype.grow = function( size ) { - var end = this.end + size; - if ( end < this.start ) { - end = this.start; - } - return new hopeRange(this.start, end); - }; - - hopeRange.prototype.shrink = function( size ) { - return this.grow( -size ); - }; - - hopeRange.prototype.move = function( length, min, max ) { - var start = this.start; - var end = this.end; - start += length; - end += length; - if ( !min ) { - min = 0; - } - start = Math.max( min, start ); - end = Math.max( start, end ); - if ( max ) { - start = Math.min( max, start ); - end = Math.min( max, start ); - } - return new hopeRange(start, end); - }; - - this.create = function( start, end ) { - if ( start instanceof hopeRange ) { - return start; - } - if ( typeof end =='undefined' && parseInt(start,10)==start ) { - end = start; - } else if ( Array.isArray(start) && typeof start[1] != 'undefined' ) { - end = start[1]; - start = start[0]; - } - return new hopeRange( parseInt(start), parseInt(end) ); - }; - -}); \ No newline at end of file diff --git a/www/hope/hope.render.html.js b/www/hope/hope.render.html.js deleted file mode 100644 index 212211f..0000000 --- a/www/hope/hope.render.html.js +++ /dev/null @@ -1,353 +0,0 @@ -hope.register( 'hope.render.html', function() { - - var nestingSets = { - 'inline' : [ 'tt', 'u', 'strike', 'em', 'strong', 'dfn', 'code', 'samp', 'kbd', 'var', 'cite', 'abbr', 'acronym', 'sub', 'sup', 'q', 'span', 'bdo', 'a', 'object', 'img', 'bd', 'br', 'i' ], - 'block' : [ 'address', 'dir', 'menu', 'hr', 'li', 'table', 'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'pre', 'ul', 'ol', 'dl', 'div', 'blockquote', 'iframe' ] - }; - - nestingSets.all = nestingSets.block.concat( nestingSets.inline ); - - this.rules = { - nesting: { - 'a' : nestingSets.inline.filter( function(element) { return element != 'a'; } ), - 'abbr' : nestingSets.inline, - 'acronym' : nestingSets.inline, - 'address' : [ 'p' ].concat( nestingSets.inline ), - 'bdo' : nestingSets.inline, - 'blockquote': nestingSets.all, - 'br' : [], - 'caption' : nestingSets.inline, - 'cite' : nestingSets.inline, - 'code' : nestingSets.inline, - 'col' : [], - 'colgroup' : [ 'col' ], - 'dd' : nestingSets.all, - 'dfn' : nestingSets.inline, - 'dir' : [ 'li' ], - 'div' : nestingSets.all, - 'dl' : [ 'dt', 'dd' ], - 'dt' : nestingSets.inline, - 'em' : nestingSets.inline, - 'h1' : nestingSets.inline, - 'h2' : nestingSets.inline, - 'h3' : nestingSets.inline, - 'h4' : nestingSets.inline, - 'h5' : nestingSets.inline, - 'h6' : nestingSets.inline, - 'hr' : [], - 'img' : [], - 'kbd' : nestingSets.inline, - 'li' : nestingSets.all, - 'menu' : [ 'li' ], - 'object' : [ 'param' ].concat( nestingSets.all ), - 'ol' : [ 'li' ], - 'p' : nestingSets.inline, - 'pre' : nestingSets.inline, - 'q' : nestingSets.inline, - 'samp' : nestingSets.inline, - 'span' : nestingSets.inline, - 'strike' : nestingSets.inline, - 'strong' : nestingSets.inline, - 'sub' : nestingSets.inline, - 'sup' : nestingSets.inline, - 'table' : [ 'caption', 'colgroup', 'col', 'thead', 'tbody' ], - 'tbody' : [ 'tr' ], - 'td' : nestingSets.all, - 'th' : nestingSets.all, - 'thead' : [ 'tr' ], - 'tr' : [ 'td', 'th' ], - 'tt' : nestingSets.inline, - 'u' : nestingSets.inline, - 'ul' : [ 'li' ], - 'var' : nestingSets.inline - }, - // which html elements can not have child elements at all and shouldn't be closed - 'noChildren' : [ 'hr', 'br', 'col', 'img' ], - // which html elements must have a specific child element - 'obligChild' : { - 'ol' : [ 'li' ], - 'ul' : [ 'li' ], - 'dl' : [ 'dt', 'dd' ] - }, - // which html elements must have a specific parent element - 'obligParent' : { - 'li' : [ 'ul', 'ol', 'dir', 'menu' ], - 'dt' : [ 'dl' ], - 'dd' : [ 'dl' ] - }, - // which html elements to allow as the top level, default is only block elements - 'toplevel' : nestingSets.block.concat(nestingSets.inline), // [ 'li', 'img', 'span', 'strong', 'em', 'code' ], - 'nestingSets' : nestingSets - }; - - this.getTag = function( markup ) { - return markup.split(' ')[0].toLowerCase(); // FIXME: more robust parsing needed - }; - - this.getAnnotationStack = function( annotationSet ) { - // { index:nextAnnotationEntry.index, entry:nextAnnotation } - // { start:, end:, annotation: } - // assert: annotationSet must only contain annotation that has overlapping ranges - // if not results will be unpredictable - var annotationStack = []; - if ( !annotationSet.length ) { - return []; - } - - var rules = this.rules; - - annotationSet.sort( function( a, b ) { - if ( a.range.start < b.range.start ) { - return -1; - } else if ( a.range.start > b.range.start ) { - return 1; - } else if ( a.range.end > b.range.end ) { - return -1; - } else if ( a.range.end < b.range.end ) { - return 1; - } - - // if comparing ul/ol and li on the same range, ul/ol goes first; - if (rules.obligParent[a.tag.split(/ /)[0]]) { - if (rules.obligParent[a.tag.split(/ /)[0]].indexOf(b.tag.split(/ /)[0]) != -1) { - return 1; - } - } - if (rules.obligParent[b.tag.split(/ /)[0]]) { - if (rules.obligParent[b.tag.split(/ /)[0]].indexOf(a.tag.split(/ /)[0]) != -1) { - return -1; - } - } - - // block elementen komen voor andere elementen - if (nestingSets.block.indexOf(a.tag.split(/ /)[0]) != '-1') { - return -1; - } - if (nestingSets.block.indexOf(b.tag.split(/ /)[0]) != '-1') { - return 1; - } - - // hack om hyperlinks met images er in te laten werken. - if (a.tag.split(/ /)[0] == 'a') { - return -1; - } - if (b.tag.split(/ /)[0] == 'a') { - return 1; - } - - // daarna komen inline elementen - if (nestingSets.inline.indexOf(a.tag.split(/ /)[0]) != '-1') { - return -1; - } - if (nestingSets.inline.indexOf(b.tag.split(/ /)[0]) != '-1') { - return 1; - } - - return 0; - }); - var unfilteredStack = []; - for ( var i=0, l=annotationSet.length; icommonIndex; i-- ) { - annotationDiff.push( { type : 'close', annotation : annotationStackFrom[i] } ); - } - for ( i=commonIndex+1, l=annotationStackTo.length; i'; - } - } else if ( annotationDiff[i].type == 'insert' ) { - renderedDiff += '<' + annotationDiff[i].annotation.tag + '>'; - annotationTag = this.getTag( annotationDiff[i].annotation.tag ); - if ( this.rules.noChildren.indexOf( annotationTag ) == -1 ) { - renderedDiff += ''; - } - } else { - renderedDiff += '<' + annotationDiff[i].annotation.tag + '>'; - } - } - return renderedDiff; - }; - - this.escape = function( content ) { - return content - .replace(/&/g, "&") - .replace(//g, ">") - .replace(/"/g, """) - .replace(/'/g, "'"); - }; - - this.render = function( fragment ) { - // FIXME: annotation should be the relative annotation list to speed things up - var annotationSet = []; // set of applicable annotation at current position - var annotationStack = []; // stack of applied (valid) annotation at current position - - var relativeAnnotation = fragment.annotations.getEventList(); - var content = fragment.text.toString(); - - var renderedHTML = ''; - var cursor = 0; - - while ( relativeAnnotation.length ) { - - var annotationChangeSet = relativeAnnotation.shift(); - var annotationAdded = []; // list of annotation added in this change set - var annotationSetOnce = []; // list of annotation that can not have children, needs no close - for ( i=0, l=annotationChangeSet.markup.length; i 0 ) { - if (diffHTML && ( - diffHTML.indexOf("
") !== -1 || - diffHTML.indexOf("
") !== -1 || - diffHTML.indexOf("/g, ">"); - n = n.replace(/"/g, """); - - return n; - }; - - this.diffString = function( o, n ) { - o = o.replace(/\s+$/, ''); - n = n.replace(/\s+$/, ''); - - var out = this.diff(o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ); - var str = ""; - - var oSpace = o.match(/\s+/g); - if (oSpace === null) { - oSpace = ["\n"]; - } else { - oSpace.push("\n"); - } - var nSpace = n.match(/\s+/g); - if (nSpace === null) { - nSpace = ["\n"]; - } else { - nSpace.push("\n"); - } - - var i; - if (out.n.length === 0) { - for ( i = 0; i < out.o.length; i++) { - str += '' + this.escape(out.o[i]) + oSpace[i] + ""; - } - } else { - if (out.n[0].text === null) { - for (n = 0; n < out.o.length && out.o[n].text === null; n++) { - str += '' + this.escape(out.o[n]) + oSpace[n] + ""; - } - } - - for ( i = 0; i < out.n.length; i++ ) { - if (out.n[i].text === null) { - str += '' + this.escape(out.n[i]) + nSpace[i] + ""; - } else { - var pre = ""; - - for (n = out.n[i].row + 1; n < out.o.length && out.o[n].text === null; n++ ) { - pre += '' + this.escape(out.o[n]) + oSpace[n] + ""; - } - str += " " + out.n[i].text + nSpace[i] + pre; - } - } - } - - return str; - }; - - this.randomColor = function() { - return "rgb(" + (Math.random() * 100) + "%, " + - (Math.random() * 100) + "%, " + - (Math.random() * 100) + "%)"; - }; - - this.diffString2 = function( o, n ) { - o = o.replace(/\s+$/, ''); - n = n.replace(/\s+$/, ''); - - var out = this.diff(o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ); - - var oSpace = o.match(/\s+/g); - if (oSpace === null) { - oSpace = ["\n"]; - } else { - oSpace.push("\n"); - } - var nSpace = n.match(/\s+/g); - if (nSpace === null) { - nSpace = ["\n"]; - } else { - nSpace.push("\n"); - } - - var os = ""; - var colors = []; - var i; - for (i = 0; i < out.o.length; i++) { - colors[i] = this.randomColor(); - - if (out.o[i].text !== null) { - os += '' + - this.escape(out.o[i].text) + oSpace[i] + ""; - } else { - os += "" + this.escape(out.o[i]) + oSpace[i] + ""; - } - } - - var ns = ""; - for (i = 0; i < out.n.length; i++) { - if (out.n[i].text !== null) { - ns += '' + - this.escape(out.n[i].text) + nSpace[i] + ""; - } else { - ns += "" + this.escape(out.n[i]) + nSpace[i] + ""; - } - } - - return { o : os , n : ns }; - }; - - this.diff = function( o, n ) { - var ns = {}; - var os = {}; - var i; - - for ( i = 0; i < n.length; i++ ) { - if ( ns[ n[i] ] === null ) - ns[ n[i] ] = { rows: [], o: null }; - ns[ n[i] ].rows.push( i ); - } - - for ( i = 0; i < o.length; i++ ) { - if ( os[ o[i] ] === null ) - os[ o[i] ] = { rows: [], n: null }; - os[ o[i] ].rows.push( i ); - } - - for ( i in ns ) { - if ( ns[i].rows.length == 1 && typeof(os[i]) != "undefined" && os[i].rows.length == 1 ) { - n[ ns[i].rows[0] ] = { text: n[ ns[i].rows[0] ], row: os[i].rows[0] }; - o[ os[i].rows[0] ] = { text: o[ os[i].rows[0] ], row: ns[i].rows[0] }; - } - } - - for ( i = 0; i < n.length - 1; i++ ) { - if ( n[i].text !== null && n[i+1].text === null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text === null && - n[i+1] == o[ n[i].row + 1 ] ) - { - n[i+1] = { text: n[i+1], row: n[i].row + 1 }; - o[n[i].row+1] = { text: o[n[i].row+1], row: i + 1 }; - } - } - - for ( i = n.length - 1; i > 0; i-- ) { - if ( n[i].text !== null && n[i-1].text === null && n[i].row > 0 && o[ n[i].row - 1 ].text === null && - n[i-1] == o[ n[i].row - 1 ] ) - { - n[i-1] = { text: n[i-1], row: n[i].row - 1 }; - o[n[i].row-1] = { text: o[n[i].row-1], row: i - 1 }; - } - } - - return { o: o, n: n }; - }; - - - this.isArray = function( o ) { - if ( Object.prototype.toString.call( o ) === '[object Array]' ) { - return true; - } - return false; - }; - - this.getPrototypeName = function( o ) { - return Object.prototype.toString.call( o ); - }; - - this.isString = function( o ) { - if ( typeof o === 'string' ) { - return true; - } - return false; - }; - - this.assertTrue = function( expression ) { - this.countAssert++; - if ( expression !== true ) { - this.errors.push( 'test failed: expression not true at ' + this.currentTest + ' assertion ' + this.countAssert ); - this.write( this.errors[ this.errors.length - 1 ] ); - } else { - this.success++; - } - }; - - this.assertFalse = function( expression ) { - this.countAssert++; - if ( expression !== false ) { - this.errors.push( 'test failed: expression not false at ' + this.currentTest + ' assertion ' + this.countAssert ); - this.write( this.errors[ this.errors.length - 1 ] ); - } else { - this.success++; - } - }; - - this.assertEquals = function( var1, var2 ) { - var i, ii, l; - this.countAssert++; - if ( var1 === var2 ) { - this.success++; - } else { - var reason = ''; - var diff; - if ( (typeof var1) !== (typeof var2) ) { - reason = 'typeof var1 '+(typeof var1)+' is not typeof var2 '+(typeof var2); - } else if ( var1 instanceof Object && ( this.getPrototypeName(var1) !== this.getPrototypeName(var2) ) ) { - reason = 'prototype of var1 '+this.getPrototypeName(var1)+' is not prototype of var2 '+this.getPrototypeName(var2); - } else if ( this.isString(var1) ) { - diff = this.diffString2(var1, var2); - reason = 'difference:
'+diff.o+'
'+diff.n+'
'; - - } else if ( this.isArray(var1) ) { - diff = []; - for ( i=0, l=var1.length; i 0 ) { - reason = 'arraydiff: ' + diff.join("\n"); - } - } else if ( var1 instanceof Object ) { - diff = []; - var seen = {}; - var count = 0; - for ( i in var1 ) { - if ( var1[i] !== var2[i] ) { - diff[count++] = i + ': ' + var1[i] + ' is not ' + var2[i]; - seen[i] = true; - } - } - for (i in var2 ) { - if ( !seen[i] && var1[i] != var2[i] ) { - diff[count++] = i + ': ' + var1[i] + ' is not ' + var2[i]; - } - } - if ( diff.length > 0 ) { - reason = 'objectdiff: ' + diff.join("\n"); - } - } else { - reason = var1 + ' != ' + var2; - } - if ( reason ) { - this.errors.push( 'test failed: variables not equal at ' + this.currentTest + ' assertion ' + this.countAssert + ' reason: ' + reason ); - this.write( this.errors[ this.errors.length - 1 ] ); - } else { - this.success++; - } - } - }; - - this.run = function() { - this.errors = []; - this.success = 0; - for ( var i in this ) { - if ( i.substr(0,4)=='test' ) { - this.currentTest = i; - this.countAssert = 0; - this[i].call(); - } - } - this.write( this.errors.length + ' errors; ' + this.success + ' tests succeeded.'); - }; - - this.write = function( message ) { - var output = document.getElementById('hopeTestOutput'); - if ( output ) { - //message = document.createTextNode( message ); - var messageDiv = document.createElement( 'div' ); - messageDiv.innerHTML = message; //appendChild( message ); - output.appendChild( messageDiv ); - } else { - console.log( message ); - } - }; - - } - - this.create = function() { - return new hopeTest(); - }; - -}); \ No newline at end of file diff --git a/www/hope/pack b/www/hope/pack deleted file mode 100755 index 3943b5f..0000000 --- a/www/hope/pack +++ /dev/null @@ -1 +0,0 @@ -cat hope.js hope.polyfills.js hope.range.js hope.annotation.js hope.fragment.js hope.fragment.annotations.js hope.fragment.text.js hope.render.html.js hope.events.js hope.keyboard.js hope.editor.js hope.editor.selection.js > hope.packed.js diff --git a/www/index.html b/www/index.html deleted file mode 100644 index dbe42ac..0000000 --- a/www/index.html +++ /dev/null @@ -1,5378 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - -
-
    - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
- - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/www/js/codemirror/lib/codemirror.css b/www/js/codemirror/lib/codemirror.css deleted file mode 100644 index f4d5718..0000000 --- a/www/js/codemirror/lib/codemirror.css +++ /dev/null @@ -1,344 +0,0 @@ -/* BASICS */ - -.CodeMirror { - /* Set height, width, borders, and global font properties here */ - font-family: monospace; - height: 300px; - color: black; - direction: ltr; -} - -/* PADDING */ - -.CodeMirror-lines { - padding: 4px 0; /* Vertical padding around content */ -} -.CodeMirror pre.CodeMirror-line, -.CodeMirror pre.CodeMirror-line-like { - padding: 0 4px; /* Horizontal padding of content */ -} - -.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { - background-color: white; /* The little square between H and V scrollbars */ -} - -/* GUTTER */ - -.CodeMirror-gutters { - border-right: 1px solid #ddd; - background-color: #f7f7f7; - white-space: nowrap; -} -.CodeMirror-linenumbers {} -.CodeMirror-linenumber { - padding: 0 3px 0 5px; - min-width: 20px; - text-align: right; - color: #999; - white-space: nowrap; -} - -.CodeMirror-guttermarker { color: black; } -.CodeMirror-guttermarker-subtle { color: #999; } - -/* CURSOR */ - -.CodeMirror-cursor { - border-left: 1px solid black; - border-right: none; - width: 0; -} -/* Shown when moving in bi-directional text */ -.CodeMirror div.CodeMirror-secondarycursor { - border-left: 1px solid silver; -} -.cm-fat-cursor .CodeMirror-cursor { - width: auto; - border: 0 !important; - background: #7e7; -} -.cm-fat-cursor div.CodeMirror-cursors { - z-index: 1; -} -.cm-fat-cursor .CodeMirror-line::selection, -.cm-fat-cursor .CodeMirror-line > span::selection, -.cm-fat-cursor .CodeMirror-line > span > span::selection { background: transparent; } -.cm-fat-cursor .CodeMirror-line::-moz-selection, -.cm-fat-cursor .CodeMirror-line > span::-moz-selection, -.cm-fat-cursor .CodeMirror-line > span > span::-moz-selection { background: transparent; } -.cm-fat-cursor { caret-color: transparent; } -@-moz-keyframes blink { - 0% {} - 50% { background-color: transparent; } - 100% {} -} -@-webkit-keyframes blink { - 0% {} - 50% { background-color: transparent; } - 100% {} -} -@keyframes blink { - 0% {} - 50% { background-color: transparent; } - 100% {} -} - -/* Can style cursor different in overwrite (non-insert) mode */ -.CodeMirror-overwrite .CodeMirror-cursor {} - -.cm-tab { display: inline-block; text-decoration: inherit; } - -.CodeMirror-rulers { - position: absolute; - left: 0; right: 0; top: -50px; bottom: 0; - overflow: hidden; -} -.CodeMirror-ruler { - border-left: 1px solid #ccc; - top: 0; bottom: 0; - position: absolute; -} - -/* DEFAULT THEME */ - -.cm-s-default .cm-header {color: blue;} -.cm-s-default .cm-quote {color: #090;} -.cm-negative {color: #d44;} -.cm-positive {color: #292;} -.cm-header, .cm-strong {font-weight: bold;} -.cm-em {font-style: italic;} -.cm-link {text-decoration: underline;} -.cm-strikethrough {text-decoration: line-through;} - -.cm-s-default .cm-keyword {color: #708;} -.cm-s-default .cm-atom {color: #219;} -.cm-s-default .cm-number {color: #164;} -.cm-s-default .cm-def {color: #00f;} -.cm-s-default .cm-variable, -.cm-s-default .cm-punctuation, -.cm-s-default .cm-property, -.cm-s-default .cm-operator {} -.cm-s-default .cm-variable-2 {color: #05a;} -.cm-s-default .cm-variable-3, .cm-s-default .cm-type {color: #085;} -.cm-s-default .cm-comment {color: #a50;} -.cm-s-default .cm-string {color: #a11;} -.cm-s-default .cm-string-2 {color: #f50;} -.cm-s-default .cm-meta {color: #555;} -.cm-s-default .cm-qualifier {color: #555;} -.cm-s-default .cm-builtin {color: #30a;} -.cm-s-default .cm-bracket {color: #997;} -.cm-s-default .cm-tag {color: #170;} -.cm-s-default .cm-attribute {color: #00c;} -.cm-s-default .cm-hr {color: #999;} -.cm-s-default .cm-link {color: #00c;} - -.cm-s-default .cm-error {color: #f00;} -.cm-invalidchar {color: #f00;} - -.CodeMirror-composing { border-bottom: 2px solid; } - -/* Default styles for common addons */ - -div.CodeMirror span.CodeMirror-matchingbracket {color: #0b0;} -div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;} -.CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); } -.CodeMirror-activeline-background {background: #e8f2ff;} - -/* STOP */ - -/* The rest of this file contains styles related to the mechanics of - the editor. You probably shouldn't touch them. */ - -.CodeMirror { - position: relative; - overflow: hidden; - background: white; -} - -.CodeMirror-scroll { - overflow: scroll !important; /* Things will break if this is overridden */ - /* 50px is the magic margin used to hide the element's real scrollbars */ - /* See overflow: hidden in .CodeMirror */ - margin-bottom: -50px; margin-right: -50px; - padding-bottom: 50px; - height: 100%; - outline: none; /* Prevent dragging from highlighting the element */ - position: relative; - z-index: 0; -} -.CodeMirror-sizer { - position: relative; - border-right: 50px solid transparent; -} - -/* The fake, visible scrollbars. Used to force redraw during scrolling - before actual scrolling happens, thus preventing shaking and - flickering artifacts. */ -.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { - position: absolute; - z-index: 6; - display: none; - outline: none; -} -.CodeMirror-vscrollbar { - right: 0; top: 0; - overflow-x: hidden; - overflow-y: scroll; -} -.CodeMirror-hscrollbar { - bottom: 0; left: 0; - overflow-y: hidden; - overflow-x: scroll; -} -.CodeMirror-scrollbar-filler { - right: 0; bottom: 0; -} -.CodeMirror-gutter-filler { - left: 0; bottom: 0; -} - -.CodeMirror-gutters { - position: absolute; left: 0; top: 0; - min-height: 100%; - z-index: 3; -} -.CodeMirror-gutter { - white-space: normal; - height: 100%; - display: inline-block; - vertical-align: top; - margin-bottom: -50px; -} -.CodeMirror-gutter-wrapper { - position: absolute; - z-index: 4; - background: none !important; - border: none !important; -} -.CodeMirror-gutter-background { - position: absolute; - top: 0; bottom: 0; - z-index: 4; -} -.CodeMirror-gutter-elt { - position: absolute; - cursor: default; - z-index: 4; -} -.CodeMirror-gutter-wrapper ::selection { background-color: transparent } -.CodeMirror-gutter-wrapper ::-moz-selection { background-color: transparent } - -.CodeMirror-lines { - cursor: text; - min-height: 1px; /* prevents collapsing before first draw */ -} -.CodeMirror pre.CodeMirror-line, -.CodeMirror pre.CodeMirror-line-like { - /* Reset some styles that the rest of the page might have set */ - -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0; - border-width: 0; - background: transparent; - font-family: inherit; - font-size: inherit; - margin: 0; - white-space: pre; - word-wrap: normal; - line-height: inherit; - color: inherit; - z-index: 2; - position: relative; - overflow: visible; - -webkit-tap-highlight-color: transparent; - -webkit-font-variant-ligatures: contextual; - font-variant-ligatures: contextual; -} -.CodeMirror-wrap pre.CodeMirror-line, -.CodeMirror-wrap pre.CodeMirror-line-like { - word-wrap: break-word; - white-space: pre-wrap; - word-break: normal; -} - -.CodeMirror-linebackground { - position: absolute; - left: 0; right: 0; top: 0; bottom: 0; - z-index: 0; -} - -.CodeMirror-linewidget { - position: relative; - z-index: 2; - padding: 0.1px; /* Force widget margins to stay inside of the container */ -} - -.CodeMirror-widget {} - -.CodeMirror-rtl pre { direction: rtl; } - -.CodeMirror-code { - outline: none; -} - -/* Force content-box sizing for the elements where we expect it */ -.CodeMirror-scroll, -.CodeMirror-sizer, -.CodeMirror-gutter, -.CodeMirror-gutters, -.CodeMirror-linenumber { - -moz-box-sizing: content-box; - box-sizing: content-box; -} - -.CodeMirror-measure { - position: absolute; - width: 100%; - height: 0; - overflow: hidden; - visibility: hidden; -} - -.CodeMirror-cursor { - position: absolute; - pointer-events: none; -} -.CodeMirror-measure pre { position: static; } - -div.CodeMirror-cursors { - visibility: hidden; - position: relative; - z-index: 3; -} -div.CodeMirror-dragcursors { - visibility: visible; -} - -.CodeMirror-focused div.CodeMirror-cursors { - visibility: visible; -} - -.CodeMirror-selected { background: #d9d9d9; } -.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; } -.CodeMirror-crosshair { cursor: crosshair; } -.CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; } -.CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; } - -.cm-searching { - background-color: #ffa; - background-color: rgba(255, 255, 0, .4); -} - -/* Used to force a border model for a node */ -.cm-force-border { padding-right: .1px; } - -@media print { - /* Hide the cursor when printing */ - .CodeMirror div.CodeMirror-cursors { - visibility: hidden; - } -} - -/* See issue #2901 */ -.cm-tab-wrap-hack:after { content: ''; } - -/* Help users use markselection to safely style text background */ -span.CodeMirror-selectedtext { background: none; } diff --git a/www/js/codemirror/lib/codemirror.js b/www/js/codemirror/lib/codemirror.js deleted file mode 100644 index 193d445..0000000 --- a/www/js/codemirror/lib/codemirror.js +++ /dev/null @@ -1,9849 +0,0 @@ -// CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE - -// This is CodeMirror (https://codemirror.net), a code editor -// implemented in JavaScript on top of the browser's DOM. -// -// You can find some technical background for some of the code below -// at http://marijnhaverbeke.nl/blog/#cm-internals . - -(function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : - typeof define === 'function' && define.amd ? define(factory) : - (global = global || self, global.CodeMirror = factory()); -}(this, (function () { 'use strict'; - - // Kludges for bugs and behavior differences that can't be feature - // detected are enabled based on userAgent etc sniffing. - var userAgent = navigator.userAgent; - var platform = navigator.platform; - - var gecko = /gecko\/\d/i.test(userAgent); - var ie_upto10 = /MSIE \d/.test(userAgent); - var ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(userAgent); - var edge = /Edge\/(\d+)/.exec(userAgent); - var ie = ie_upto10 || ie_11up || edge; - var ie_version = ie && (ie_upto10 ? document.documentMode || 6 : +(edge || ie_11up)[1]); - var webkit = !edge && /WebKit\//.test(userAgent); - var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(userAgent); - var chrome = !edge && /Chrome\//.test(userAgent); - var presto = /Opera\//.test(userAgent); - var safari = /Apple Computer/.test(navigator.vendor); - var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(userAgent); - var phantom = /PhantomJS/.test(userAgent); - - var ios = safari && (/Mobile\/\w+/.test(userAgent) || navigator.maxTouchPoints > 2); - var android = /Android/.test(userAgent); - // This is woefully incomplete. Suggestions for alternative methods welcome. - var mobile = ios || android || /webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(userAgent); - var mac = ios || /Mac/.test(platform); - var chromeOS = /\bCrOS\b/.test(userAgent); - var windows = /win/i.test(platform); - - var presto_version = presto && userAgent.match(/Version\/(\d*\.\d*)/); - if (presto_version) { presto_version = Number(presto_version[1]); } - if (presto_version && presto_version >= 15) { presto = false; webkit = true; } - // Some browsers use the wrong event properties to signal cmd/ctrl on OS X - var flipCtrlCmd = mac && (qtwebkit || presto && (presto_version == null || presto_version < 12.11)); - var captureRightClick = gecko || (ie && ie_version >= 9); - - function classTest(cls) { return new RegExp("(^|\\s)" + cls + "(?:$|\\s)\\s*") } - - var rmClass = function(node, cls) { - var current = node.className; - var match = classTest(cls).exec(current); - if (match) { - var after = current.slice(match.index + match[0].length); - node.className = current.slice(0, match.index) + (after ? match[1] + after : ""); - } - }; - - function removeChildren(e) { - for (var count = e.childNodes.length; count > 0; --count) - { e.removeChild(e.firstChild); } - return e - } - - function removeChildrenAndAdd(parent, e) { - return removeChildren(parent).appendChild(e) - } - - function elt(tag, content, className, style) { - var e = document.createElement(tag); - if (className) { e.className = className; } - if (style) { e.style.cssText = style; } - if (typeof content == "string") { e.appendChild(document.createTextNode(content)); } - else if (content) { for (var i = 0; i < content.length; ++i) { e.appendChild(content[i]); } } - return e - } - // wrapper for elt, which removes the elt from the accessibility tree - function eltP(tag, content, className, style) { - var e = elt(tag, content, className, style); - e.setAttribute("role", "presentation"); - return e - } - - var range; - if (document.createRange) { range = function(node, start, end, endNode) { - var r = document.createRange(); - r.setEnd(endNode || node, end); - r.setStart(node, start); - return r - }; } - else { range = function(node, start, end) { - var r = document.body.createTextRange(); - try { r.moveToElementText(node.parentNode); } - catch(e) { return r } - r.collapse(true); - r.moveEnd("character", end); - r.moveStart("character", start); - return r - }; } - - function contains(parent, child) { - if (child.nodeType == 3) // Android browser always returns false when child is a textnode - { child = child.parentNode; } - if (parent.contains) - { return parent.contains(child) } - do { - if (child.nodeType == 11) { child = child.host; } - if (child == parent) { return true } - } while (child = child.parentNode) - } - - function activeElt() { - // IE and Edge may throw an "Unspecified Error" when accessing document.activeElement. - // IE < 10 will throw when accessed while the page is loading or in an iframe. - // IE > 9 and Edge will throw when accessed in an iframe if document.body is unavailable. - var activeElement; - try { - activeElement = document.activeElement; - } catch(e) { - activeElement = document.body || null; - } - while (activeElement && activeElement.shadowRoot && activeElement.shadowRoot.activeElement) - { activeElement = activeElement.shadowRoot.activeElement; } - return activeElement - } - - function addClass(node, cls) { - var current = node.className; - if (!classTest(cls).test(current)) { node.className += (current ? " " : "") + cls; } - } - function joinClasses(a, b) { - var as = a.split(" "); - for (var i = 0; i < as.length; i++) - { if (as[i] && !classTest(as[i]).test(b)) { b += " " + as[i]; } } - return b - } - - var selectInput = function(node) { node.select(); }; - if (ios) // Mobile Safari apparently has a bug where select() is broken. - { selectInput = function(node) { node.selectionStart = 0; node.selectionEnd = node.value.length; }; } - else if (ie) // Suppress mysterious IE10 errors - { selectInput = function(node) { try { node.select(); } catch(_e) {} }; } - - function bind(f) { - var args = Array.prototype.slice.call(arguments, 1); - return function(){return f.apply(null, args)} - } - - function copyObj(obj, target, overwrite) { - if (!target) { target = {}; } - for (var prop in obj) - { if (obj.hasOwnProperty(prop) && (overwrite !== false || !target.hasOwnProperty(prop))) - { target[prop] = obj[prop]; } } - return target - } - - // Counts the column offset in a string, taking tabs into account. - // Used mostly to find indentation. - function countColumn(string, end, tabSize, startIndex, startValue) { - if (end == null) { - end = string.search(/[^\s\u00a0]/); - if (end == -1) { end = string.length; } - } - for (var i = startIndex || 0, n = startValue || 0;;) { - var nextTab = string.indexOf("\t", i); - if (nextTab < 0 || nextTab >= end) - { return n + (end - i) } - n += nextTab - i; - n += tabSize - (n % tabSize); - i = nextTab + 1; - } - } - - var Delayed = function() { - this.id = null; - this.f = null; - this.time = 0; - this.handler = bind(this.onTimeout, this); - }; - Delayed.prototype.onTimeout = function (self) { - self.id = 0; - if (self.time <= +new Date) { - self.f(); - } else { - setTimeout(self.handler, self.time - +new Date); - } - }; - Delayed.prototype.set = function (ms, f) { - this.f = f; - var time = +new Date + ms; - if (!this.id || time < this.time) { - clearTimeout(this.id); - this.id = setTimeout(this.handler, ms); - this.time = time; - } - }; - - function indexOf(array, elt) { - for (var i = 0; i < array.length; ++i) - { if (array[i] == elt) { return i } } - return -1 - } - - // Number of pixels added to scroller and sizer to hide scrollbar - var scrollerGap = 50; - - // Returned or thrown by various protocols to signal 'I'm not - // handling this'. - var Pass = {toString: function(){return "CodeMirror.Pass"}}; - - // Reused option objects for setSelection & friends - var sel_dontScroll = {scroll: false}, sel_mouse = {origin: "*mouse"}, sel_move = {origin: "+move"}; - - // The inverse of countColumn -- find the offset that corresponds to - // a particular column. - function findColumn(string, goal, tabSize) { - for (var pos = 0, col = 0;;) { - var nextTab = string.indexOf("\t", pos); - if (nextTab == -1) { nextTab = string.length; } - var skipped = nextTab - pos; - if (nextTab == string.length || col + skipped >= goal) - { return pos + Math.min(skipped, goal - col) } - col += nextTab - pos; - col += tabSize - (col % tabSize); - pos = nextTab + 1; - if (col >= goal) { return pos } - } - } - - var spaceStrs = [""]; - function spaceStr(n) { - while (spaceStrs.length <= n) - { spaceStrs.push(lst(spaceStrs) + " "); } - return spaceStrs[n] - } - - function lst(arr) { return arr[arr.length-1] } - - function map(array, f) { - var out = []; - for (var i = 0; i < array.length; i++) { out[i] = f(array[i], i); } - return out - } - - function insertSorted(array, value, score) { - var pos = 0, priority = score(value); - while (pos < array.length && score(array[pos]) <= priority) { pos++; } - array.splice(pos, 0, value); - } - - function nothing() {} - - function createObj(base, props) { - var inst; - if (Object.create) { - inst = Object.create(base); - } else { - nothing.prototype = base; - inst = new nothing(); - } - if (props) { copyObj(props, inst); } - return inst - } - - var nonASCIISingleCaseWordChar = /[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/; - function isWordCharBasic(ch) { - return /\w/.test(ch) || ch > "\x80" && - (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch)) - } - function isWordChar(ch, helper) { - if (!helper) { return isWordCharBasic(ch) } - if (helper.source.indexOf("\\w") > -1 && isWordCharBasic(ch)) { return true } - return helper.test(ch) - } - - function isEmpty(obj) { - for (var n in obj) { if (obj.hasOwnProperty(n) && obj[n]) { return false } } - return true - } - - // Extending unicode characters. A series of a non-extending char + - // any number of extending chars is treated as a single unit as far - // as editing and measuring is concerned. This is not fully correct, - // since some scripts/fonts/browsers also treat other configurations - // of code points as a group. - var extendingChars = /[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/; - function isExtendingChar(ch) { return ch.charCodeAt(0) >= 768 && extendingChars.test(ch) } - - // Returns a number from the range [`0`; `str.length`] unless `pos` is outside that range. - function skipExtendingChars(str, pos, dir) { - while ((dir < 0 ? pos > 0 : pos < str.length) && isExtendingChar(str.charAt(pos))) { pos += dir; } - return pos - } - - // Returns the value from the range [`from`; `to`] that satisfies - // `pred` and is closest to `from`. Assumes that at least `to` - // satisfies `pred`. Supports `from` being greater than `to`. - function findFirst(pred, from, to) { - // At any point we are certain `to` satisfies `pred`, don't know - // whether `from` does. - var dir = from > to ? -1 : 1; - for (;;) { - if (from == to) { return from } - var midF = (from + to) / 2, mid = dir < 0 ? Math.ceil(midF) : Math.floor(midF); - if (mid == from) { return pred(mid) ? from : to } - if (pred(mid)) { to = mid; } - else { from = mid + dir; } - } - } - - // BIDI HELPERS - - function iterateBidiSections(order, from, to, f) { - if (!order) { return f(from, to, "ltr", 0) } - var found = false; - for (var i = 0; i < order.length; ++i) { - var part = order[i]; - if (part.from < to && part.to > from || from == to && part.to == from) { - f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr", i); - found = true; - } - } - if (!found) { f(from, to, "ltr"); } - } - - var bidiOther = null; - function getBidiPartAt(order, ch, sticky) { - var found; - bidiOther = null; - for (var i = 0; i < order.length; ++i) { - var cur = order[i]; - if (cur.from < ch && cur.to > ch) { return i } - if (cur.to == ch) { - if (cur.from != cur.to && sticky == "before") { found = i; } - else { bidiOther = i; } - } - if (cur.from == ch) { - if (cur.from != cur.to && sticky != "before") { found = i; } - else { bidiOther = i; } - } - } - return found != null ? found : bidiOther - } - - // Bidirectional ordering algorithm - // See http://unicode.org/reports/tr9/tr9-13.html for the algorithm - // that this (partially) implements. - - // One-char codes used for character types: - // L (L): Left-to-Right - // R (R): Right-to-Left - // r (AL): Right-to-Left Arabic - // 1 (EN): European Number - // + (ES): European Number Separator - // % (ET): European Number Terminator - // n (AN): Arabic Number - // , (CS): Common Number Separator - // m (NSM): Non-Spacing Mark - // b (BN): Boundary Neutral - // s (B): Paragraph Separator - // t (S): Segment Separator - // w (WS): Whitespace - // N (ON): Other Neutrals - - // Returns null if characters are ordered as they appear - // (left-to-right), or an array of sections ({from, to, level} - // objects) in the order in which they occur visually. - var bidiOrdering = (function() { - // Character types for codepoints 0 to 0xff - var lowTypes = "bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN"; - // Character types for codepoints 0x600 to 0x6f9 - var arabicTypes = "nnnnnnNNr%%r,rNNmmmmmmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmmmnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmnNmmmmmmrrmmNmmmmrr1111111111"; - function charType(code) { - if (code <= 0xf7) { return lowTypes.charAt(code) } - else if (0x590 <= code && code <= 0x5f4) { return "R" } - else if (0x600 <= code && code <= 0x6f9) { return arabicTypes.charAt(code - 0x600) } - else if (0x6ee <= code && code <= 0x8ac) { return "r" } - else if (0x2000 <= code && code <= 0x200b) { return "w" } - else if (code == 0x200c) { return "b" } - else { return "L" } - } - - var bidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/; - var isNeutral = /[stwN]/, isStrong = /[LRr]/, countsAsLeft = /[Lb1n]/, countsAsNum = /[1n]/; - - function BidiSpan(level, from, to) { - this.level = level; - this.from = from; this.to = to; - } - - return function(str, direction) { - var outerType = direction == "ltr" ? "L" : "R"; - - if (str.length == 0 || direction == "ltr" && !bidiRE.test(str)) { return false } - var len = str.length, types = []; - for (var i = 0; i < len; ++i) - { types.push(charType(str.charCodeAt(i))); } - - // W1. Examine each non-spacing mark (NSM) in the level run, and - // change the type of the NSM to the type of the previous - // character. If the NSM is at the start of the level run, it will - // get the type of sor. - for (var i$1 = 0, prev = outerType; i$1 < len; ++i$1) { - var type = types[i$1]; - if (type == "m") { types[i$1] = prev; } - else { prev = type; } - } - - // W2. Search backwards from each instance of a European number - // until the first strong type (R, L, AL, or sor) is found. If an - // AL is found, change the type of the European number to Arabic - // number. - // W3. Change all ALs to R. - for (var i$2 = 0, cur = outerType; i$2 < len; ++i$2) { - var type$1 = types[i$2]; - if (type$1 == "1" && cur == "r") { types[i$2] = "n"; } - else if (isStrong.test(type$1)) { cur = type$1; if (type$1 == "r") { types[i$2] = "R"; } } - } - - // W4. A single European separator between two European numbers - // changes to a European number. A single common separator between - // two numbers of the same type changes to that type. - for (var i$3 = 1, prev$1 = types[0]; i$3 < len - 1; ++i$3) { - var type$2 = types[i$3]; - if (type$2 == "+" && prev$1 == "1" && types[i$3+1] == "1") { types[i$3] = "1"; } - else if (type$2 == "," && prev$1 == types[i$3+1] && - (prev$1 == "1" || prev$1 == "n")) { types[i$3] = prev$1; } - prev$1 = type$2; - } - - // W5. A sequence of European terminators adjacent to European - // numbers changes to all European numbers. - // W6. Otherwise, separators and terminators change to Other - // Neutral. - for (var i$4 = 0; i$4 < len; ++i$4) { - var type$3 = types[i$4]; - if (type$3 == ",") { types[i$4] = "N"; } - else if (type$3 == "%") { - var end = (void 0); - for (end = i$4 + 1; end < len && types[end] == "%"; ++end) {} - var replace = (i$4 && types[i$4-1] == "!") || (end < len && types[end] == "1") ? "1" : "N"; - for (var j = i$4; j < end; ++j) { types[j] = replace; } - i$4 = end - 1; - } - } - - // W7. Search backwards from each instance of a European number - // until the first strong type (R, L, or sor) is found. If an L is - // found, then change the type of the European number to L. - for (var i$5 = 0, cur$1 = outerType; i$5 < len; ++i$5) { - var type$4 = types[i$5]; - if (cur$1 == "L" && type$4 == "1") { types[i$5] = "L"; } - else if (isStrong.test(type$4)) { cur$1 = type$4; } - } - - // N1. A sequence of neutrals takes the direction of the - // surrounding strong text if the text on both sides has the same - // direction. European and Arabic numbers act as if they were R in - // terms of their influence on neutrals. Start-of-level-run (sor) - // and end-of-level-run (eor) are used at level run boundaries. - // N2. Any remaining neutrals take the embedding direction. - for (var i$6 = 0; i$6 < len; ++i$6) { - if (isNeutral.test(types[i$6])) { - var end$1 = (void 0); - for (end$1 = i$6 + 1; end$1 < len && isNeutral.test(types[end$1]); ++end$1) {} - var before = (i$6 ? types[i$6-1] : outerType) == "L"; - var after = (end$1 < len ? types[end$1] : outerType) == "L"; - var replace$1 = before == after ? (before ? "L" : "R") : outerType; - for (var j$1 = i$6; j$1 < end$1; ++j$1) { types[j$1] = replace$1; } - i$6 = end$1 - 1; - } - } - - // Here we depart from the documented algorithm, in order to avoid - // building up an actual levels array. Since there are only three - // levels (0, 1, 2) in an implementation that doesn't take - // explicit embedding into account, we can build up the order on - // the fly, without following the level-based algorithm. - var order = [], m; - for (var i$7 = 0; i$7 < len;) { - if (countsAsLeft.test(types[i$7])) { - var start = i$7; - for (++i$7; i$7 < len && countsAsLeft.test(types[i$7]); ++i$7) {} - order.push(new BidiSpan(0, start, i$7)); - } else { - var pos = i$7, at = order.length, isRTL = direction == "rtl" ? 1 : 0; - for (++i$7; i$7 < len && types[i$7] != "L"; ++i$7) {} - for (var j$2 = pos; j$2 < i$7;) { - if (countsAsNum.test(types[j$2])) { - if (pos < j$2) { order.splice(at, 0, new BidiSpan(1, pos, j$2)); at += isRTL; } - var nstart = j$2; - for (++j$2; j$2 < i$7 && countsAsNum.test(types[j$2]); ++j$2) {} - order.splice(at, 0, new BidiSpan(2, nstart, j$2)); - at += isRTL; - pos = j$2; - } else { ++j$2; } - } - if (pos < i$7) { order.splice(at, 0, new BidiSpan(1, pos, i$7)); } - } - } - if (direction == "ltr") { - if (order[0].level == 1 && (m = str.match(/^\s+/))) { - order[0].from = m[0].length; - order.unshift(new BidiSpan(0, 0, m[0].length)); - } - if (lst(order).level == 1 && (m = str.match(/\s+$/))) { - lst(order).to -= m[0].length; - order.push(new BidiSpan(0, len - m[0].length, len)); - } - } - - return direction == "rtl" ? order.reverse() : order - } - })(); - - // Get the bidi ordering for the given line (and cache it). Returns - // false for lines that are fully left-to-right, and an array of - // BidiSpan objects otherwise. - function getOrder(line, direction) { - var order = line.order; - if (order == null) { order = line.order = bidiOrdering(line.text, direction); } - return order - } - - // EVENT HANDLING - - // Lightweight event framework. on/off also work on DOM nodes, - // registering native DOM handlers. - - var noHandlers = []; - - var on = function(emitter, type, f) { - if (emitter.addEventListener) { - emitter.addEventListener(type, f, false); - } else if (emitter.attachEvent) { - emitter.attachEvent("on" + type, f); - } else { - var map = emitter._handlers || (emitter._handlers = {}); - map[type] = (map[type] || noHandlers).concat(f); - } - }; - - function getHandlers(emitter, type) { - return emitter._handlers && emitter._handlers[type] || noHandlers - } - - function off(emitter, type, f) { - if (emitter.removeEventListener) { - emitter.removeEventListener(type, f, false); - } else if (emitter.detachEvent) { - emitter.detachEvent("on" + type, f); - } else { - var map = emitter._handlers, arr = map && map[type]; - if (arr) { - var index = indexOf(arr, f); - if (index > -1) - { map[type] = arr.slice(0, index).concat(arr.slice(index + 1)); } - } - } - } - - function signal(emitter, type /*, values...*/) { - var handlers = getHandlers(emitter, type); - if (!handlers.length) { return } - var args = Array.prototype.slice.call(arguments, 2); - for (var i = 0; i < handlers.length; ++i) { handlers[i].apply(null, args); } - } - - // The DOM events that CodeMirror handles can be overridden by - // registering a (non-DOM) handler on the editor for the event name, - // and preventDefault-ing the event in that handler. - function signalDOMEvent(cm, e, override) { - if (typeof e == "string") - { e = {type: e, preventDefault: function() { this.defaultPrevented = true; }}; } - signal(cm, override || e.type, cm, e); - return e_defaultPrevented(e) || e.codemirrorIgnore - } - - function signalCursorActivity(cm) { - var arr = cm._handlers && cm._handlers.cursorActivity; - if (!arr) { return } - var set = cm.curOp.cursorActivityHandlers || (cm.curOp.cursorActivityHandlers = []); - for (var i = 0; i < arr.length; ++i) { if (indexOf(set, arr[i]) == -1) - { set.push(arr[i]); } } - } - - function hasHandler(emitter, type) { - return getHandlers(emitter, type).length > 0 - } - - // Add on and off methods to a constructor's prototype, to make - // registering events on such objects more convenient. - function eventMixin(ctor) { - ctor.prototype.on = function(type, f) {on(this, type, f);}; - ctor.prototype.off = function(type, f) {off(this, type, f);}; - } - - // Due to the fact that we still support jurassic IE versions, some - // compatibility wrappers are needed. - - function e_preventDefault(e) { - if (e.preventDefault) { e.preventDefault(); } - else { e.returnValue = false; } - } - function e_stopPropagation(e) { - if (e.stopPropagation) { e.stopPropagation(); } - else { e.cancelBubble = true; } - } - function e_defaultPrevented(e) { - return e.defaultPrevented != null ? e.defaultPrevented : e.returnValue == false - } - function e_stop(e) {e_preventDefault(e); e_stopPropagation(e);} - - function e_target(e) {return e.target || e.srcElement} - function e_button(e) { - var b = e.which; - if (b == null) { - if (e.button & 1) { b = 1; } - else if (e.button & 2) { b = 3; } - else if (e.button & 4) { b = 2; } - } - if (mac && e.ctrlKey && b == 1) { b = 3; } - return b - } - - // Detect drag-and-drop - var dragAndDrop = function() { - // There is *some* kind of drag-and-drop support in IE6-8, but I - // couldn't get it to work yet. - if (ie && ie_version < 9) { return false } - var div = elt('div'); - return "draggable" in div || "dragDrop" in div - }(); - - var zwspSupported; - function zeroWidthElement(measure) { - if (zwspSupported == null) { - var test = elt("span", "\u200b"); - removeChildrenAndAdd(measure, elt("span", [test, document.createTextNode("x")])); - if (measure.firstChild.offsetHeight != 0) - { zwspSupported = test.offsetWidth <= 1 && test.offsetHeight > 2 && !(ie && ie_version < 8); } - } - var node = zwspSupported ? elt("span", "\u200b") : - elt("span", "\u00a0", null, "display: inline-block; width: 1px; margin-right: -1px"); - node.setAttribute("cm-text", ""); - return node - } - - // Feature-detect IE's crummy client rect reporting for bidi text - var badBidiRects; - function hasBadBidiRects(measure) { - if (badBidiRects != null) { return badBidiRects } - var txt = removeChildrenAndAdd(measure, document.createTextNode("A\u062eA")); - var r0 = range(txt, 0, 1).getBoundingClientRect(); - var r1 = range(txt, 1, 2).getBoundingClientRect(); - removeChildren(measure); - if (!r0 || r0.left == r0.right) { return false } // Safari returns null in some cases (#2780) - return badBidiRects = (r1.right - r0.right < 3) - } - - // See if "".split is the broken IE version, if so, provide an - // alternative way to split lines. - var splitLinesAuto = "\n\nb".split(/\n/).length != 3 ? function (string) { - var pos = 0, result = [], l = string.length; - while (pos <= l) { - var nl = string.indexOf("\n", pos); - if (nl == -1) { nl = string.length; } - var line = string.slice(pos, string.charAt(nl - 1) == "\r" ? nl - 1 : nl); - var rt = line.indexOf("\r"); - if (rt != -1) { - result.push(line.slice(0, rt)); - pos += rt + 1; - } else { - result.push(line); - pos = nl + 1; - } - } - return result - } : function (string) { return string.split(/\r\n?|\n/); }; - - var hasSelection = window.getSelection ? function (te) { - try { return te.selectionStart != te.selectionEnd } - catch(e) { return false } - } : function (te) { - var range; - try {range = te.ownerDocument.selection.createRange();} - catch(e) {} - if (!range || range.parentElement() != te) { return false } - return range.compareEndPoints("StartToEnd", range) != 0 - }; - - var hasCopyEvent = (function () { - var e = elt("div"); - if ("oncopy" in e) { return true } - e.setAttribute("oncopy", "return;"); - return typeof e.oncopy == "function" - })(); - - var badZoomedRects = null; - function hasBadZoomedRects(measure) { - if (badZoomedRects != null) { return badZoomedRects } - var node = removeChildrenAndAdd(measure, elt("span", "x")); - var normal = node.getBoundingClientRect(); - var fromRange = range(node, 0, 1).getBoundingClientRect(); - return badZoomedRects = Math.abs(normal.left - fromRange.left) > 1 - } - - // Known modes, by name and by MIME - var modes = {}, mimeModes = {}; - - // Extra arguments are stored as the mode's dependencies, which is - // used by (legacy) mechanisms like loadmode.js to automatically - // load a mode. (Preferred mechanism is the require/define calls.) - function defineMode(name, mode) { - if (arguments.length > 2) - { mode.dependencies = Array.prototype.slice.call(arguments, 2); } - modes[name] = mode; - } - - function defineMIME(mime, spec) { - mimeModes[mime] = spec; - } - - // Given a MIME type, a {name, ...options} config object, or a name - // string, return a mode config object. - function resolveMode(spec) { - if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) { - spec = mimeModes[spec]; - } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) { - var found = mimeModes[spec.name]; - if (typeof found == "string") { found = {name: found}; } - spec = createObj(found, spec); - spec.name = found.name; - } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec)) { - return resolveMode("application/xml") - } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+json$/.test(spec)) { - return resolveMode("application/json") - } - if (typeof spec == "string") { return {name: spec} } - else { return spec || {name: "null"} } - } - - // Given a mode spec (anything that resolveMode accepts), find and - // initialize an actual mode object. - function getMode(options, spec) { - spec = resolveMode(spec); - var mfactory = modes[spec.name]; - if (!mfactory) { return getMode(options, "text/plain") } - var modeObj = mfactory(options, spec); - if (modeExtensions.hasOwnProperty(spec.name)) { - var exts = modeExtensions[spec.name]; - for (var prop in exts) { - if (!exts.hasOwnProperty(prop)) { continue } - if (modeObj.hasOwnProperty(prop)) { modeObj["_" + prop] = modeObj[prop]; } - modeObj[prop] = exts[prop]; - } - } - modeObj.name = spec.name; - if (spec.helperType) { modeObj.helperType = spec.helperType; } - if (spec.modeProps) { for (var prop$1 in spec.modeProps) - { modeObj[prop$1] = spec.modeProps[prop$1]; } } - - return modeObj - } - - // This can be used to attach properties to mode objects from - // outside the actual mode definition. - var modeExtensions = {}; - function extendMode(mode, properties) { - var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {}); - copyObj(properties, exts); - } - - function copyState(mode, state) { - if (state === true) { return state } - if (mode.copyState) { return mode.copyState(state) } - var nstate = {}; - for (var n in state) { - var val = state[n]; - if (val instanceof Array) { val = val.concat([]); } - nstate[n] = val; - } - return nstate - } - - // Given a mode and a state (for that mode), find the inner mode and - // state at the position that the state refers to. - function innerMode(mode, state) { - var info; - while (mode.innerMode) { - info = mode.innerMode(state); - if (!info || info.mode == mode) { break } - state = info.state; - mode = info.mode; - } - return info || {mode: mode, state: state} - } - - function startState(mode, a1, a2) { - return mode.startState ? mode.startState(a1, a2) : true - } - - // STRING STREAM - - // Fed to the mode parsers, provides helper functions to make - // parsers more succinct. - - var StringStream = function(string, tabSize, lineOracle) { - this.pos = this.start = 0; - this.string = string; - this.tabSize = tabSize || 8; - this.lastColumnPos = this.lastColumnValue = 0; - this.lineStart = 0; - this.lineOracle = lineOracle; - }; - - StringStream.prototype.eol = function () {return this.pos >= this.string.length}; - StringStream.prototype.sol = function () {return this.pos == this.lineStart}; - StringStream.prototype.peek = function () {return this.string.charAt(this.pos) || undefined}; - StringStream.prototype.next = function () { - if (this.pos < this.string.length) - { return this.string.charAt(this.pos++) } - }; - StringStream.prototype.eat = function (match) { - var ch = this.string.charAt(this.pos); - var ok; - if (typeof match == "string") { ok = ch == match; } - else { ok = ch && (match.test ? match.test(ch) : match(ch)); } - if (ok) {++this.pos; return ch} - }; - StringStream.prototype.eatWhile = function (match) { - var start = this.pos; - while (this.eat(match)){} - return this.pos > start - }; - StringStream.prototype.eatSpace = function () { - var start = this.pos; - while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) { ++this.pos; } - return this.pos > start - }; - StringStream.prototype.skipToEnd = function () {this.pos = this.string.length;}; - StringStream.prototype.skipTo = function (ch) { - var found = this.string.indexOf(ch, this.pos); - if (found > -1) {this.pos = found; return true} - }; - StringStream.prototype.backUp = function (n) {this.pos -= n;}; - StringStream.prototype.column = function () { - if (this.lastColumnPos < this.start) { - this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue); - this.lastColumnPos = this.start; - } - return this.lastColumnValue - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0) - }; - StringStream.prototype.indentation = function () { - return countColumn(this.string, null, this.tabSize) - - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0) - }; - StringStream.prototype.match = function (pattern, consume, caseInsensitive) { - if (typeof pattern == "string") { - var cased = function (str) { return caseInsensitive ? str.toLowerCase() : str; }; - var substr = this.string.substr(this.pos, pattern.length); - if (cased(substr) == cased(pattern)) { - if (consume !== false) { this.pos += pattern.length; } - return true - } - } else { - var match = this.string.slice(this.pos).match(pattern); - if (match && match.index > 0) { return null } - if (match && consume !== false) { this.pos += match[0].length; } - return match - } - }; - StringStream.prototype.current = function (){return this.string.slice(this.start, this.pos)}; - StringStream.prototype.hideFirstChars = function (n, inner) { - this.lineStart += n; - try { return inner() } - finally { this.lineStart -= n; } - }; - StringStream.prototype.lookAhead = function (n) { - var oracle = this.lineOracle; - return oracle && oracle.lookAhead(n) - }; - StringStream.prototype.baseToken = function () { - var oracle = this.lineOracle; - return oracle && oracle.baseToken(this.pos) - }; - - // Find the line object corresponding to the given line number. - function getLine(doc, n) { - n -= doc.first; - if (n < 0 || n >= doc.size) { throw new Error("There is no line " + (n + doc.first) + " in the document.") } - var chunk = doc; - while (!chunk.lines) { - for (var i = 0;; ++i) { - var child = chunk.children[i], sz = child.chunkSize(); - if (n < sz) { chunk = child; break } - n -= sz; - } - } - return chunk.lines[n] - } - - // Get the part of a document between two positions, as an array of - // strings. - function getBetween(doc, start, end) { - var out = [], n = start.line; - doc.iter(start.line, end.line + 1, function (line) { - var text = line.text; - if (n == end.line) { text = text.slice(0, end.ch); } - if (n == start.line) { text = text.slice(start.ch); } - out.push(text); - ++n; - }); - return out - } - // Get the lines between from and to, as array of strings. - function getLines(doc, from, to) { - var out = []; - doc.iter(from, to, function (line) { out.push(line.text); }); // iter aborts when callback returns truthy value - return out - } - - // Update the height of a line, propagating the height change - // upwards to parent nodes. - function updateLineHeight(line, height) { - var diff = height - line.height; - if (diff) { for (var n = line; n; n = n.parent) { n.height += diff; } } - } - - // Given a line object, find its line number by walking up through - // its parent links. - function lineNo(line) { - if (line.parent == null) { return null } - var cur = line.parent, no = indexOf(cur.lines, line); - for (var chunk = cur.parent; chunk; cur = chunk, chunk = chunk.parent) { - for (var i = 0;; ++i) { - if (chunk.children[i] == cur) { break } - no += chunk.children[i].chunkSize(); - } - } - return no + cur.first - } - - // Find the line at the given vertical position, using the height - // information in the document tree. - function lineAtHeight(chunk, h) { - var n = chunk.first; - outer: do { - for (var i$1 = 0; i$1 < chunk.children.length; ++i$1) { - var child = chunk.children[i$1], ch = child.height; - if (h < ch) { chunk = child; continue outer } - h -= ch; - n += child.chunkSize(); - } - return n - } while (!chunk.lines) - var i = 0; - for (; i < chunk.lines.length; ++i) { - var line = chunk.lines[i], lh = line.height; - if (h < lh) { break } - h -= lh; - } - return n + i - } - - function isLine(doc, l) {return l >= doc.first && l < doc.first + doc.size} - - function lineNumberFor(options, i) { - return String(options.lineNumberFormatter(i + options.firstLineNumber)) - } - - // A Pos instance represents a position within the text. - function Pos(line, ch, sticky) { - if ( sticky === void 0 ) sticky = null; - - if (!(this instanceof Pos)) { return new Pos(line, ch, sticky) } - this.line = line; - this.ch = ch; - this.sticky = sticky; - } - - // Compare two positions, return 0 if they are the same, a negative - // number when a is less, and a positive number otherwise. - function cmp(a, b) { return a.line - b.line || a.ch - b.ch } - - function equalCursorPos(a, b) { return a.sticky == b.sticky && cmp(a, b) == 0 } - - function copyPos(x) {return Pos(x.line, x.ch)} - function maxPos(a, b) { return cmp(a, b) < 0 ? b : a } - function minPos(a, b) { return cmp(a, b) < 0 ? a : b } - - // Most of the external API clips given positions to make sure they - // actually exist within the document. - function clipLine(doc, n) {return Math.max(doc.first, Math.min(n, doc.first + doc.size - 1))} - function clipPos(doc, pos) { - if (pos.line < doc.first) { return Pos(doc.first, 0) } - var last = doc.first + doc.size - 1; - if (pos.line > last) { return Pos(last, getLine(doc, last).text.length) } - return clipToLen(pos, getLine(doc, pos.line).text.length) - } - function clipToLen(pos, linelen) { - var ch = pos.ch; - if (ch == null || ch > linelen) { return Pos(pos.line, linelen) } - else if (ch < 0) { return Pos(pos.line, 0) } - else { return pos } - } - function clipPosArray(doc, array) { - var out = []; - for (var i = 0; i < array.length; i++) { out[i] = clipPos(doc, array[i]); } - return out - } - - var SavedContext = function(state, lookAhead) { - this.state = state; - this.lookAhead = lookAhead; - }; - - var Context = function(doc, state, line, lookAhead) { - this.state = state; - this.doc = doc; - this.line = line; - this.maxLookAhead = lookAhead || 0; - this.baseTokens = null; - this.baseTokenPos = 1; - }; - - Context.prototype.lookAhead = function (n) { - var line = this.doc.getLine(this.line + n); - if (line != null && n > this.maxLookAhead) { this.maxLookAhead = n; } - return line - }; - - Context.prototype.baseToken = function (n) { - if (!this.baseTokens) { return null } - while (this.baseTokens[this.baseTokenPos] <= n) - { this.baseTokenPos += 2; } - var type = this.baseTokens[this.baseTokenPos + 1]; - return {type: type && type.replace(/( |^)overlay .*/, ""), - size: this.baseTokens[this.baseTokenPos] - n} - }; - - Context.prototype.nextLine = function () { - this.line++; - if (this.maxLookAhead > 0) { this.maxLookAhead--; } - }; - - Context.fromSaved = function (doc, saved, line) { - if (saved instanceof SavedContext) - { return new Context(doc, copyState(doc.mode, saved.state), line, saved.lookAhead) } - else - { return new Context(doc, copyState(doc.mode, saved), line) } - }; - - Context.prototype.save = function (copy) { - var state = copy !== false ? copyState(this.doc.mode, this.state) : this.state; - return this.maxLookAhead > 0 ? new SavedContext(state, this.maxLookAhead) : state - }; - - - // Compute a style array (an array starting with a mode generation - // -- for invalidation -- followed by pairs of end positions and - // style strings), which is used to highlight the tokens on the - // line. - function highlightLine(cm, line, context, forceToEnd) { - // A styles array always starts with a number identifying the - // mode/overlays that it is based on (for easy invalidation). - var st = [cm.state.modeGen], lineClasses = {}; - // Compute the base array of styles - runMode(cm, line.text, cm.doc.mode, context, function (end, style) { return st.push(end, style); }, - lineClasses, forceToEnd); - var state = context.state; - - // Run overlays, adjust style array. - var loop = function ( o ) { - context.baseTokens = st; - var overlay = cm.state.overlays[o], i = 1, at = 0; - context.state = true; - runMode(cm, line.text, overlay.mode, context, function (end, style) { - var start = i; - // Ensure there's a token end at the current position, and that i points at it - while (at < end) { - var i_end = st[i]; - if (i_end > end) - { st.splice(i, 1, end, st[i+1], i_end); } - i += 2; - at = Math.min(end, i_end); - } - if (!style) { return } - if (overlay.opaque) { - st.splice(start, i - start, end, "overlay " + style); - i = start + 2; - } else { - for (; start < i; start += 2) { - var cur = st[start+1]; - st[start+1] = (cur ? cur + " " : "") + "overlay " + style; - } - } - }, lineClasses); - context.state = state; - context.baseTokens = null; - context.baseTokenPos = 1; - }; - - for (var o = 0; o < cm.state.overlays.length; ++o) loop( o ); - - return {styles: st, classes: lineClasses.bgClass || lineClasses.textClass ? lineClasses : null} - } - - function getLineStyles(cm, line, updateFrontier) { - if (!line.styles || line.styles[0] != cm.state.modeGen) { - var context = getContextBefore(cm, lineNo(line)); - var resetState = line.text.length > cm.options.maxHighlightLength && copyState(cm.doc.mode, context.state); - var result = highlightLine(cm, line, context); - if (resetState) { context.state = resetState; } - line.stateAfter = context.save(!resetState); - line.styles = result.styles; - if (result.classes) { line.styleClasses = result.classes; } - else if (line.styleClasses) { line.styleClasses = null; } - if (updateFrontier === cm.doc.highlightFrontier) - { cm.doc.modeFrontier = Math.max(cm.doc.modeFrontier, ++cm.doc.highlightFrontier); } - } - return line.styles - } - - function getContextBefore(cm, n, precise) { - var doc = cm.doc, display = cm.display; - if (!doc.mode.startState) { return new Context(doc, true, n) } - var start = findStartLine(cm, n, precise); - var saved = start > doc.first && getLine(doc, start - 1).stateAfter; - var context = saved ? Context.fromSaved(doc, saved, start) : new Context(doc, startState(doc.mode), start); - - doc.iter(start, n, function (line) { - processLine(cm, line.text, context); - var pos = context.line; - line.stateAfter = pos == n - 1 || pos % 5 == 0 || pos >= display.viewFrom && pos < display.viewTo ? context.save() : null; - context.nextLine(); - }); - if (precise) { doc.modeFrontier = context.line; } - return context - } - - // Lightweight form of highlight -- proceed over this line and - // update state, but don't save a style array. Used for lines that - // aren't currently visible. - function processLine(cm, text, context, startAt) { - var mode = cm.doc.mode; - var stream = new StringStream(text, cm.options.tabSize, context); - stream.start = stream.pos = startAt || 0; - if (text == "") { callBlankLine(mode, context.state); } - while (!stream.eol()) { - readToken(mode, stream, context.state); - stream.start = stream.pos; - } - } - - function callBlankLine(mode, state) { - if (mode.blankLine) { return mode.blankLine(state) } - if (!mode.innerMode) { return } - var inner = innerMode(mode, state); - if (inner.mode.blankLine) { return inner.mode.blankLine(inner.state) } - } - - function readToken(mode, stream, state, inner) { - for (var i = 0; i < 10; i++) { - if (inner) { inner[0] = innerMode(mode, state).mode; } - var style = mode.token(stream, state); - if (stream.pos > stream.start) { return style } - } - throw new Error("Mode " + mode.name + " failed to advance stream.") - } - - var Token = function(stream, type, state) { - this.start = stream.start; this.end = stream.pos; - this.string = stream.current(); - this.type = type || null; - this.state = state; - }; - - // Utility for getTokenAt and getLineTokens - function takeToken(cm, pos, precise, asArray) { - var doc = cm.doc, mode = doc.mode, style; - pos = clipPos(doc, pos); - var line = getLine(doc, pos.line), context = getContextBefore(cm, pos.line, precise); - var stream = new StringStream(line.text, cm.options.tabSize, context), tokens; - if (asArray) { tokens = []; } - while ((asArray || stream.pos < pos.ch) && !stream.eol()) { - stream.start = stream.pos; - style = readToken(mode, stream, context.state); - if (asArray) { tokens.push(new Token(stream, style, copyState(doc.mode, context.state))); } - } - return asArray ? tokens : new Token(stream, style, context.state) - } - - function extractLineClasses(type, output) { - if (type) { for (;;) { - var lineClass = type.match(/(?:^|\s+)line-(background-)?(\S+)/); - if (!lineClass) { break } - type = type.slice(0, lineClass.index) + type.slice(lineClass.index + lineClass[0].length); - var prop = lineClass[1] ? "bgClass" : "textClass"; - if (output[prop] == null) - { output[prop] = lineClass[2]; } - else if (!(new RegExp("(?:^|\\s)" + lineClass[2] + "(?:$|\\s)")).test(output[prop])) - { output[prop] += " " + lineClass[2]; } - } } - return type - } - - // Run the given mode's parser over a line, calling f for each token. - function runMode(cm, text, mode, context, f, lineClasses, forceToEnd) { - var flattenSpans = mode.flattenSpans; - if (flattenSpans == null) { flattenSpans = cm.options.flattenSpans; } - var curStart = 0, curStyle = null; - var stream = new StringStream(text, cm.options.tabSize, context), style; - var inner = cm.options.addModeClass && [null]; - if (text == "") { extractLineClasses(callBlankLine(mode, context.state), lineClasses); } - while (!stream.eol()) { - if (stream.pos > cm.options.maxHighlightLength) { - flattenSpans = false; - if (forceToEnd) { processLine(cm, text, context, stream.pos); } - stream.pos = text.length; - style = null; - } else { - style = extractLineClasses(readToken(mode, stream, context.state, inner), lineClasses); - } - if (inner) { - var mName = inner[0].name; - if (mName) { style = "m-" + (style ? mName + " " + style : mName); } - } - if (!flattenSpans || curStyle != style) { - while (curStart < stream.start) { - curStart = Math.min(stream.start, curStart + 5000); - f(curStart, curStyle); - } - curStyle = style; - } - stream.start = stream.pos; - } - while (curStart < stream.pos) { - // Webkit seems to refuse to render text nodes longer than 57444 - // characters, and returns inaccurate measurements in nodes - // starting around 5000 chars. - var pos = Math.min(stream.pos, curStart + 5000); - f(pos, curStyle); - curStart = pos; - } - } - - // Finds the line to start with when starting a parse. Tries to - // find a line with a stateAfter, so that it can start with a - // valid state. If that fails, it returns the line with the - // smallest indentation, which tends to need the least context to - // parse correctly. - function findStartLine(cm, n, precise) { - var minindent, minline, doc = cm.doc; - var lim = precise ? -1 : n - (cm.doc.mode.innerMode ? 1000 : 100); - for (var search = n; search > lim; --search) { - if (search <= doc.first) { return doc.first } - var line = getLine(doc, search - 1), after = line.stateAfter; - if (after && (!precise || search + (after instanceof SavedContext ? after.lookAhead : 0) <= doc.modeFrontier)) - { return search } - var indented = countColumn(line.text, null, cm.options.tabSize); - if (minline == null || minindent > indented) { - minline = search - 1; - minindent = indented; - } - } - return minline - } - - function retreatFrontier(doc, n) { - doc.modeFrontier = Math.min(doc.modeFrontier, n); - if (doc.highlightFrontier < n - 10) { return } - var start = doc.first; - for (var line = n - 1; line > start; line--) { - var saved = getLine(doc, line).stateAfter; - // change is on 3 - // state on line 1 looked ahead 2 -- so saw 3 - // test 1 + 2 < 3 should cover this - if (saved && (!(saved instanceof SavedContext) || line + saved.lookAhead < n)) { - start = line + 1; - break - } - } - doc.highlightFrontier = Math.min(doc.highlightFrontier, start); - } - - // Optimize some code when these features are not used. - var sawReadOnlySpans = false, sawCollapsedSpans = false; - - function seeReadOnlySpans() { - sawReadOnlySpans = true; - } - - function seeCollapsedSpans() { - sawCollapsedSpans = true; - } - - // TEXTMARKER SPANS - - function MarkedSpan(marker, from, to) { - this.marker = marker; - this.from = from; this.to = to; - } - - // Search an array of spans for a span matching the given marker. - function getMarkedSpanFor(spans, marker) { - if (spans) { for (var i = 0; i < spans.length; ++i) { - var span = spans[i]; - if (span.marker == marker) { return span } - } } - } - - // Remove a span from an array, returning undefined if no spans are - // left (we don't store arrays for lines without spans). - function removeMarkedSpan(spans, span) { - var r; - for (var i = 0; i < spans.length; ++i) - { if (spans[i] != span) { (r || (r = [])).push(spans[i]); } } - return r - } - - // Add a span to a line. - function addMarkedSpan(line, span, op) { - var inThisOp = op && window.WeakSet && (op.markedSpans || (op.markedSpans = new WeakSet)); - if (inThisOp && inThisOp.has(line.markedSpans)) { - line.markedSpans.push(span); - } else { - line.markedSpans = line.markedSpans ? line.markedSpans.concat([span]) : [span]; - if (inThisOp) { inThisOp.add(line.markedSpans); } - } - span.marker.attachLine(line); - } - - // Used for the algorithm that adjusts markers for a change in the - // document. These functions cut an array of spans at a given - // character position, returning an array of remaining chunks (or - // undefined if nothing remains). - function markedSpansBefore(old, startCh, isInsert) { - var nw; - if (old) { for (var i = 0; i < old.length; ++i) { - var span = old[i], marker = span.marker; - var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= startCh : span.from < startCh); - if (startsBefore || span.from == startCh && marker.type == "bookmark" && (!isInsert || !span.marker.insertLeft)) { - var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= startCh : span.to > startCh) - ;(nw || (nw = [])).push(new MarkedSpan(marker, span.from, endsAfter ? null : span.to)); - } - } } - return nw - } - function markedSpansAfter(old, endCh, isInsert) { - var nw; - if (old) { for (var i = 0; i < old.length; ++i) { - var span = old[i], marker = span.marker; - var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= endCh : span.to > endCh); - if (endsAfter || span.from == endCh && marker.type == "bookmark" && (!isInsert || span.marker.insertLeft)) { - var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= endCh : span.from < endCh) - ;(nw || (nw = [])).push(new MarkedSpan(marker, startsBefore ? null : span.from - endCh, - span.to == null ? null : span.to - endCh)); - } - } } - return nw - } - - // Given a change object, compute the new set of marker spans that - // cover the line in which the change took place. Removes spans - // entirely within the change, reconnects spans belonging to the - // same marker that appear on both sides of the change, and cuts off - // spans partially within the change. Returns an array of span - // arrays with one element for each line in (after) the change. - function stretchSpansOverChange(doc, change) { - if (change.full) { return null } - var oldFirst = isLine(doc, change.from.line) && getLine(doc, change.from.line).markedSpans; - var oldLast = isLine(doc, change.to.line) && getLine(doc, change.to.line).markedSpans; - if (!oldFirst && !oldLast) { return null } - - var startCh = change.from.ch, endCh = change.to.ch, isInsert = cmp(change.from, change.to) == 0; - // Get the spans that 'stick out' on both sides - var first = markedSpansBefore(oldFirst, startCh, isInsert); - var last = markedSpansAfter(oldLast, endCh, isInsert); - - // Next, merge those two ends - var sameLine = change.text.length == 1, offset = lst(change.text).length + (sameLine ? startCh : 0); - if (first) { - // Fix up .to properties of first - for (var i = 0; i < first.length; ++i) { - var span = first[i]; - if (span.to == null) { - var found = getMarkedSpanFor(last, span.marker); - if (!found) { span.to = startCh; } - else if (sameLine) { span.to = found.to == null ? null : found.to + offset; } - } - } - } - if (last) { - // Fix up .from in last (or move them into first in case of sameLine) - for (var i$1 = 0; i$1 < last.length; ++i$1) { - var span$1 = last[i$1]; - if (span$1.to != null) { span$1.to += offset; } - if (span$1.from == null) { - var found$1 = getMarkedSpanFor(first, span$1.marker); - if (!found$1) { - span$1.from = offset; - if (sameLine) { (first || (first = [])).push(span$1); } - } - } else { - span$1.from += offset; - if (sameLine) { (first || (first = [])).push(span$1); } - } - } - } - // Make sure we didn't create any zero-length spans - if (first) { first = clearEmptySpans(first); } - if (last && last != first) { last = clearEmptySpans(last); } - - var newMarkers = [first]; - if (!sameLine) { - // Fill gap with whole-line-spans - var gap = change.text.length - 2, gapMarkers; - if (gap > 0 && first) - { for (var i$2 = 0; i$2 < first.length; ++i$2) - { if (first[i$2].to == null) - { (gapMarkers || (gapMarkers = [])).push(new MarkedSpan(first[i$2].marker, null, null)); } } } - for (var i$3 = 0; i$3 < gap; ++i$3) - { newMarkers.push(gapMarkers); } - newMarkers.push(last); - } - return newMarkers - } - - // Remove spans that are empty and don't have a clearWhenEmpty - // option of false. - function clearEmptySpans(spans) { - for (var i = 0; i < spans.length; ++i) { - var span = spans[i]; - if (span.from != null && span.from == span.to && span.marker.clearWhenEmpty !== false) - { spans.splice(i--, 1); } - } - if (!spans.length) { return null } - return spans - } - - // Used to 'clip' out readOnly ranges when making a change. - function removeReadOnlyRanges(doc, from, to) { - var markers = null; - doc.iter(from.line, to.line + 1, function (line) { - if (line.markedSpans) { for (var i = 0; i < line.markedSpans.length; ++i) { - var mark = line.markedSpans[i].marker; - if (mark.readOnly && (!markers || indexOf(markers, mark) == -1)) - { (markers || (markers = [])).push(mark); } - } } - }); - if (!markers) { return null } - var parts = [{from: from, to: to}]; - for (var i = 0; i < markers.length; ++i) { - var mk = markers[i], m = mk.find(0); - for (var j = 0; j < parts.length; ++j) { - var p = parts[j]; - if (cmp(p.to, m.from) < 0 || cmp(p.from, m.to) > 0) { continue } - var newParts = [j, 1], dfrom = cmp(p.from, m.from), dto = cmp(p.to, m.to); - if (dfrom < 0 || !mk.inclusiveLeft && !dfrom) - { newParts.push({from: p.from, to: m.from}); } - if (dto > 0 || !mk.inclusiveRight && !dto) - { newParts.push({from: m.to, to: p.to}); } - parts.splice.apply(parts, newParts); - j += newParts.length - 3; - } - } - return parts - } - - // Connect or disconnect spans from a line. - function detachMarkedSpans(line) { - var spans = line.markedSpans; - if (!spans) { return } - for (var i = 0; i < spans.length; ++i) - { spans[i].marker.detachLine(line); } - line.markedSpans = null; - } - function attachMarkedSpans(line, spans) { - if (!spans) { return } - for (var i = 0; i < spans.length; ++i) - { spans[i].marker.attachLine(line); } - line.markedSpans = spans; - } - - // Helpers used when computing which overlapping collapsed span - // counts as the larger one. - function extraLeft(marker) { return marker.inclusiveLeft ? -1 : 0 } - function extraRight(marker) { return marker.inclusiveRight ? 1 : 0 } - - // Returns a number indicating which of two overlapping collapsed - // spans is larger (and thus includes the other). Falls back to - // comparing ids when the spans cover exactly the same range. - function compareCollapsedMarkers(a, b) { - var lenDiff = a.lines.length - b.lines.length; - if (lenDiff != 0) { return lenDiff } - var aPos = a.find(), bPos = b.find(); - var fromCmp = cmp(aPos.from, bPos.from) || extraLeft(a) - extraLeft(b); - if (fromCmp) { return -fromCmp } - var toCmp = cmp(aPos.to, bPos.to) || extraRight(a) - extraRight(b); - if (toCmp) { return toCmp } - return b.id - a.id - } - - // Find out whether a line ends or starts in a collapsed span. If - // so, return the marker for that span. - function collapsedSpanAtSide(line, start) { - var sps = sawCollapsedSpans && line.markedSpans, found; - if (sps) { for (var sp = (void 0), i = 0; i < sps.length; ++i) { - sp = sps[i]; - if (sp.marker.collapsed && (start ? sp.from : sp.to) == null && - (!found || compareCollapsedMarkers(found, sp.marker) < 0)) - { found = sp.marker; } - } } - return found - } - function collapsedSpanAtStart(line) { return collapsedSpanAtSide(line, true) } - function collapsedSpanAtEnd(line) { return collapsedSpanAtSide(line, false) } - - function collapsedSpanAround(line, ch) { - var sps = sawCollapsedSpans && line.markedSpans, found; - if (sps) { for (var i = 0; i < sps.length; ++i) { - var sp = sps[i]; - if (sp.marker.collapsed && (sp.from == null || sp.from < ch) && (sp.to == null || sp.to > ch) && - (!found || compareCollapsedMarkers(found, sp.marker) < 0)) { found = sp.marker; } - } } - return found - } - - // Test whether there exists a collapsed span that partially - // overlaps (covers the start or end, but not both) of a new span. - // Such overlap is not allowed. - function conflictingCollapsedRange(doc, lineNo, from, to, marker) { - var line = getLine(doc, lineNo); - var sps = sawCollapsedSpans && line.markedSpans; - if (sps) { for (var i = 0; i < sps.length; ++i) { - var sp = sps[i]; - if (!sp.marker.collapsed) { continue } - var found = sp.marker.find(0); - var fromCmp = cmp(found.from, from) || extraLeft(sp.marker) - extraLeft(marker); - var toCmp = cmp(found.to, to) || extraRight(sp.marker) - extraRight(marker); - if (fromCmp >= 0 && toCmp <= 0 || fromCmp <= 0 && toCmp >= 0) { continue } - if (fromCmp <= 0 && (sp.marker.inclusiveRight && marker.inclusiveLeft ? cmp(found.to, from) >= 0 : cmp(found.to, from) > 0) || - fromCmp >= 0 && (sp.marker.inclusiveRight && marker.inclusiveLeft ? cmp(found.from, to) <= 0 : cmp(found.from, to) < 0)) - { return true } - } } - } - - // A visual line is a line as drawn on the screen. Folding, for - // example, can cause multiple logical lines to appear on the same - // visual line. This finds the start of the visual line that the - // given line is part of (usually that is the line itself). - function visualLine(line) { - var merged; - while (merged = collapsedSpanAtStart(line)) - { line = merged.find(-1, true).line; } - return line - } - - function visualLineEnd(line) { - var merged; - while (merged = collapsedSpanAtEnd(line)) - { line = merged.find(1, true).line; } - return line - } - - // Returns an array of logical lines that continue the visual line - // started by the argument, or undefined if there are no such lines. - function visualLineContinued(line) { - var merged, lines; - while (merged = collapsedSpanAtEnd(line)) { - line = merged.find(1, true).line - ;(lines || (lines = [])).push(line); - } - return lines - } - - // Get the line number of the start of the visual line that the - // given line number is part of. - function visualLineNo(doc, lineN) { - var line = getLine(doc, lineN), vis = visualLine(line); - if (line == vis) { return lineN } - return lineNo(vis) - } - - // Get the line number of the start of the next visual line after - // the given line. - function visualLineEndNo(doc, lineN) { - if (lineN > doc.lastLine()) { return lineN } - var line = getLine(doc, lineN), merged; - if (!lineIsHidden(doc, line)) { return lineN } - while (merged = collapsedSpanAtEnd(line)) - { line = merged.find(1, true).line; } - return lineNo(line) + 1 - } - - // Compute whether a line is hidden. Lines count as hidden when they - // are part of a visual line that starts with another line, or when - // they are entirely covered by collapsed, non-widget span. - function lineIsHidden(doc, line) { - var sps = sawCollapsedSpans && line.markedSpans; - if (sps) { for (var sp = (void 0), i = 0; i < sps.length; ++i) { - sp = sps[i]; - if (!sp.marker.collapsed) { continue } - if (sp.from == null) { return true } - if (sp.marker.widgetNode) { continue } - if (sp.from == 0 && sp.marker.inclusiveLeft && lineIsHiddenInner(doc, line, sp)) - { return true } - } } - } - function lineIsHiddenInner(doc, line, span) { - if (span.to == null) { - var end = span.marker.find(1, true); - return lineIsHiddenInner(doc, end.line, getMarkedSpanFor(end.line.markedSpans, span.marker)) - } - if (span.marker.inclusiveRight && span.to == line.text.length) - { return true } - for (var sp = (void 0), i = 0; i < line.markedSpans.length; ++i) { - sp = line.markedSpans[i]; - if (sp.marker.collapsed && !sp.marker.widgetNode && sp.from == span.to && - (sp.to == null || sp.to != span.from) && - (sp.marker.inclusiveLeft || span.marker.inclusiveRight) && - lineIsHiddenInner(doc, line, sp)) { return true } - } - } - - // Find the height above the given line. - function heightAtLine(lineObj) { - lineObj = visualLine(lineObj); - - var h = 0, chunk = lineObj.parent; - for (var i = 0; i < chunk.lines.length; ++i) { - var line = chunk.lines[i]; - if (line == lineObj) { break } - else { h += line.height; } - } - for (var p = chunk.parent; p; chunk = p, p = chunk.parent) { - for (var i$1 = 0; i$1 < p.children.length; ++i$1) { - var cur = p.children[i$1]; - if (cur == chunk) { break } - else { h += cur.height; } - } - } - return h - } - - // Compute the character length of a line, taking into account - // collapsed ranges (see markText) that might hide parts, and join - // other lines onto it. - function lineLength(line) { - if (line.height == 0) { return 0 } - var len = line.text.length, merged, cur = line; - while (merged = collapsedSpanAtStart(cur)) { - var found = merged.find(0, true); - cur = found.from.line; - len += found.from.ch - found.to.ch; - } - cur = line; - while (merged = collapsedSpanAtEnd(cur)) { - var found$1 = merged.find(0, true); - len -= cur.text.length - found$1.from.ch; - cur = found$1.to.line; - len += cur.text.length - found$1.to.ch; - } - return len - } - - // Find the longest line in the document. - function findMaxLine(cm) { - var d = cm.display, doc = cm.doc; - d.maxLine = getLine(doc, doc.first); - d.maxLineLength = lineLength(d.maxLine); - d.maxLineChanged = true; - doc.iter(function (line) { - var len = lineLength(line); - if (len > d.maxLineLength) { - d.maxLineLength = len; - d.maxLine = line; - } - }); - } - - // LINE DATA STRUCTURE - - // Line objects. These hold state related to a line, including - // highlighting info (the styles array). - var Line = function(text, markedSpans, estimateHeight) { - this.text = text; - attachMarkedSpans(this, markedSpans); - this.height = estimateHeight ? estimateHeight(this) : 1; - }; - - Line.prototype.lineNo = function () { return lineNo(this) }; - eventMixin(Line); - - // Change the content (text, markers) of a line. Automatically - // invalidates cached information and tries to re-estimate the - // line's height. - function updateLine(line, text, markedSpans, estimateHeight) { - line.text = text; - if (line.stateAfter) { line.stateAfter = null; } - if (line.styles) { line.styles = null; } - if (line.order != null) { line.order = null; } - detachMarkedSpans(line); - attachMarkedSpans(line, markedSpans); - var estHeight = estimateHeight ? estimateHeight(line) : 1; - if (estHeight != line.height) { updateLineHeight(line, estHeight); } - } - - // Detach a line from the document tree and its markers. - function cleanUpLine(line) { - line.parent = null; - detachMarkedSpans(line); - } - - // Convert a style as returned by a mode (either null, or a string - // containing one or more styles) to a CSS style. This is cached, - // and also looks for line-wide styles. - var styleToClassCache = {}, styleToClassCacheWithMode = {}; - function interpretTokenStyle(style, options) { - if (!style || /^\s*$/.test(style)) { return null } - var cache = options.addModeClass ? styleToClassCacheWithMode : styleToClassCache; - return cache[style] || - (cache[style] = style.replace(/\S+/g, "cm-$&")) - } - - // Render the DOM representation of the text of a line. Also builds - // up a 'line map', which points at the DOM nodes that represent - // specific stretches of text, and is used by the measuring code. - // The returned object contains the DOM node, this map, and - // information about line-wide styles that were set by the mode. - function buildLineContent(cm, lineView) { - // The padding-right forces the element to have a 'border', which - // is needed on Webkit to be able to get line-level bounding - // rectangles for it (in measureChar). - var content = eltP("span", null, null, webkit ? "padding-right: .1px" : null); - var builder = {pre: eltP("pre", [content], "CodeMirror-line"), content: content, - col: 0, pos: 0, cm: cm, - trailingSpace: false, - splitSpaces: cm.getOption("lineWrapping")}; - lineView.measure = {}; - - // Iterate over the logical lines that make up this visual line. - for (var i = 0; i <= (lineView.rest ? lineView.rest.length : 0); i++) { - var line = i ? lineView.rest[i - 1] : lineView.line, order = (void 0); - builder.pos = 0; - builder.addToken = buildToken; - // Optionally wire in some hacks into the token-rendering - // algorithm, to deal with browser quirks. - if (hasBadBidiRects(cm.display.measure) && (order = getOrder(line, cm.doc.direction))) - { builder.addToken = buildTokenBadBidi(builder.addToken, order); } - builder.map = []; - var allowFrontierUpdate = lineView != cm.display.externalMeasured && lineNo(line); - insertLineContent(line, builder, getLineStyles(cm, line, allowFrontierUpdate)); - if (line.styleClasses) { - if (line.styleClasses.bgClass) - { builder.bgClass = joinClasses(line.styleClasses.bgClass, builder.bgClass || ""); } - if (line.styleClasses.textClass) - { builder.textClass = joinClasses(line.styleClasses.textClass, builder.textClass || ""); } - } - - // Ensure at least a single node is present, for measuring. - if (builder.map.length == 0) - { builder.map.push(0, 0, builder.content.appendChild(zeroWidthElement(cm.display.measure))); } - - // Store the map and a cache object for the current logical line - if (i == 0) { - lineView.measure.map = builder.map; - lineView.measure.cache = {}; - } else { - (lineView.measure.maps || (lineView.measure.maps = [])).push(builder.map) - ;(lineView.measure.caches || (lineView.measure.caches = [])).push({}); - } - } - - // See issue #2901 - if (webkit) { - var last = builder.content.lastChild; - if (/\bcm-tab\b/.test(last.className) || (last.querySelector && last.querySelector(".cm-tab"))) - { builder.content.className = "cm-tab-wrap-hack"; } - } - - signal(cm, "renderLine", cm, lineView.line, builder.pre); - if (builder.pre.className) - { builder.textClass = joinClasses(builder.pre.className, builder.textClass || ""); } - - return builder - } - - function defaultSpecialCharPlaceholder(ch) { - var token = elt("span", "\u2022", "cm-invalidchar"); - token.title = "\\u" + ch.charCodeAt(0).toString(16); - token.setAttribute("aria-label", token.title); - return token - } - - // Build up the DOM representation for a single token, and add it to - // the line map. Takes care to render special characters separately. - function buildToken(builder, text, style, startStyle, endStyle, css, attributes) { - if (!text) { return } - var displayText = builder.splitSpaces ? splitSpaces(text, builder.trailingSpace) : text; - var special = builder.cm.state.specialChars, mustWrap = false; - var content; - if (!special.test(text)) { - builder.col += text.length; - content = document.createTextNode(displayText); - builder.map.push(builder.pos, builder.pos + text.length, content); - if (ie && ie_version < 9) { mustWrap = true; } - builder.pos += text.length; - } else { - content = document.createDocumentFragment(); - var pos = 0; - while (true) { - special.lastIndex = pos; - var m = special.exec(text); - var skipped = m ? m.index - pos : text.length - pos; - if (skipped) { - var txt = document.createTextNode(displayText.slice(pos, pos + skipped)); - if (ie && ie_version < 9) { content.appendChild(elt("span", [txt])); } - else { content.appendChild(txt); } - builder.map.push(builder.pos, builder.pos + skipped, txt); - builder.col += skipped; - builder.pos += skipped; - } - if (!m) { break } - pos += skipped + 1; - var txt$1 = (void 0); - if (m[0] == "\t") { - var tabSize = builder.cm.options.tabSize, tabWidth = tabSize - builder.col % tabSize; - txt$1 = content.appendChild(elt("span", spaceStr(tabWidth), "cm-tab")); - txt$1.setAttribute("role", "presentation"); - txt$1.setAttribute("cm-text", "\t"); - builder.col += tabWidth; - } else if (m[0] == "\r" || m[0] == "\n") { - txt$1 = content.appendChild(elt("span", m[0] == "\r" ? "\u240d" : "\u2424", "cm-invalidchar")); - txt$1.setAttribute("cm-text", m[0]); - builder.col += 1; - } else { - txt$1 = builder.cm.options.specialCharPlaceholder(m[0]); - txt$1.setAttribute("cm-text", m[0]); - if (ie && ie_version < 9) { content.appendChild(elt("span", [txt$1])); } - else { content.appendChild(txt$1); } - builder.col += 1; - } - builder.map.push(builder.pos, builder.pos + 1, txt$1); - builder.pos++; - } - } - builder.trailingSpace = displayText.charCodeAt(text.length - 1) == 32; - if (style || startStyle || endStyle || mustWrap || css || attributes) { - var fullStyle = style || ""; - if (startStyle) { fullStyle += startStyle; } - if (endStyle) { fullStyle += endStyle; } - var token = elt("span", [content], fullStyle, css); - if (attributes) { - for (var attr in attributes) { if (attributes.hasOwnProperty(attr) && attr != "style" && attr != "class") - { token.setAttribute(attr, attributes[attr]); } } - } - return builder.content.appendChild(token) - } - builder.content.appendChild(content); - } - - // Change some spaces to NBSP to prevent the browser from collapsing - // trailing spaces at the end of a line when rendering text (issue #1362). - function splitSpaces(text, trailingBefore) { - if (text.length > 1 && !/ /.test(text)) { return text } - var spaceBefore = trailingBefore, result = ""; - for (var i = 0; i < text.length; i++) { - var ch = text.charAt(i); - if (ch == " " && spaceBefore && (i == text.length - 1 || text.charCodeAt(i + 1) == 32)) - { ch = "\u00a0"; } - result += ch; - spaceBefore = ch == " "; - } - return result - } - - // Work around nonsense dimensions being reported for stretches of - // right-to-left text. - function buildTokenBadBidi(inner, order) { - return function (builder, text, style, startStyle, endStyle, css, attributes) { - style = style ? style + " cm-force-border" : "cm-force-border"; - var start = builder.pos, end = start + text.length; - for (;;) { - // Find the part that overlaps with the start of this text - var part = (void 0); - for (var i = 0; i < order.length; i++) { - part = order[i]; - if (part.to > start && part.from <= start) { break } - } - if (part.to >= end) { return inner(builder, text, style, startStyle, endStyle, css, attributes) } - inner(builder, text.slice(0, part.to - start), style, startStyle, null, css, attributes); - startStyle = null; - text = text.slice(part.to - start); - start = part.to; - } - } - } - - function buildCollapsedSpan(builder, size, marker, ignoreWidget) { - var widget = !ignoreWidget && marker.widgetNode; - if (widget) { builder.map.push(builder.pos, builder.pos + size, widget); } - if (!ignoreWidget && builder.cm.display.input.needsContentAttribute) { - if (!widget) - { widget = builder.content.appendChild(document.createElement("span")); } - widget.setAttribute("cm-marker", marker.id); - } - if (widget) { - builder.cm.display.input.setUneditable(widget); - builder.content.appendChild(widget); - } - builder.pos += size; - builder.trailingSpace = false; - } - - // Outputs a number of spans to make up a line, taking highlighting - // and marked text into account. - function insertLineContent(line, builder, styles) { - var spans = line.markedSpans, allText = line.text, at = 0; - if (!spans) { - for (var i$1 = 1; i$1 < styles.length; i$1+=2) - { builder.addToken(builder, allText.slice(at, at = styles[i$1]), interpretTokenStyle(styles[i$1+1], builder.cm.options)); } - return - } - - var len = allText.length, pos = 0, i = 1, text = "", style, css; - var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, collapsed, attributes; - for (;;) { - if (nextChange == pos) { // Update current marker set - spanStyle = spanEndStyle = spanStartStyle = css = ""; - attributes = null; - collapsed = null; nextChange = Infinity; - var foundBookmarks = [], endStyles = (void 0); - for (var j = 0; j < spans.length; ++j) { - var sp = spans[j], m = sp.marker; - if (m.type == "bookmark" && sp.from == pos && m.widgetNode) { - foundBookmarks.push(m); - } else if (sp.from <= pos && (sp.to == null || sp.to > pos || m.collapsed && sp.to == pos && sp.from == pos)) { - if (sp.to != null && sp.to != pos && nextChange > sp.to) { - nextChange = sp.to; - spanEndStyle = ""; - } - if (m.className) { spanStyle += " " + m.className; } - if (m.css) { css = (css ? css + ";" : "") + m.css; } - if (m.startStyle && sp.from == pos) { spanStartStyle += " " + m.startStyle; } - if (m.endStyle && sp.to == nextChange) { (endStyles || (endStyles = [])).push(m.endStyle, sp.to); } - // support for the old title property - // https://github.com/codemirror/CodeMirror/pull/5673 - if (m.title) { (attributes || (attributes = {})).title = m.title; } - if (m.attributes) { - for (var attr in m.attributes) - { (attributes || (attributes = {}))[attr] = m.attributes[attr]; } - } - if (m.collapsed && (!collapsed || compareCollapsedMarkers(collapsed.marker, m) < 0)) - { collapsed = sp; } - } else if (sp.from > pos && nextChange > sp.from) { - nextChange = sp.from; - } - } - if (endStyles) { for (var j$1 = 0; j$1 < endStyles.length; j$1 += 2) - { if (endStyles[j$1 + 1] == nextChange) { spanEndStyle += " " + endStyles[j$1]; } } } - - if (!collapsed || collapsed.from == pos) { for (var j$2 = 0; j$2 < foundBookmarks.length; ++j$2) - { buildCollapsedSpan(builder, 0, foundBookmarks[j$2]); } } - if (collapsed && (collapsed.from || 0) == pos) { - buildCollapsedSpan(builder, (collapsed.to == null ? len + 1 : collapsed.to) - pos, - collapsed.marker, collapsed.from == null); - if (collapsed.to == null) { return } - if (collapsed.to == pos) { collapsed = false; } - } - } - if (pos >= len) { break } - - var upto = Math.min(len, nextChange); - while (true) { - if (text) { - var end = pos + text.length; - if (!collapsed) { - var tokenText = end > upto ? text.slice(0, upto - pos) : text; - builder.addToken(builder, tokenText, style ? style + spanStyle : spanStyle, - spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : "", css, attributes); - } - if (end >= upto) {text = text.slice(upto - pos); pos = upto; break} - pos = end; - spanStartStyle = ""; - } - text = allText.slice(at, at = styles[i++]); - style = interpretTokenStyle(styles[i++], builder.cm.options); - } - } - } - - - // These objects are used to represent the visible (currently drawn) - // part of the document. A LineView may correspond to multiple - // logical lines, if those are connected by collapsed ranges. - function LineView(doc, line, lineN) { - // The starting line - this.line = line; - // Continuing lines, if any - this.rest = visualLineContinued(line); - // Number of logical lines in this visual line - this.size = this.rest ? lineNo(lst(this.rest)) - lineN + 1 : 1; - this.node = this.text = null; - this.hidden = lineIsHidden(doc, line); - } - - // Create a range of LineView objects for the given lines. - function buildViewArray(cm, from, to) { - var array = [], nextPos; - for (var pos = from; pos < to; pos = nextPos) { - var view = new LineView(cm.doc, getLine(cm.doc, pos), pos); - nextPos = pos + view.size; - array.push(view); - } - return array - } - - var operationGroup = null; - - function pushOperation(op) { - if (operationGroup) { - operationGroup.ops.push(op); - } else { - op.ownsGroup = operationGroup = { - ops: [op], - delayedCallbacks: [] - }; - } - } - - function fireCallbacksForOps(group) { - // Calls delayed callbacks and cursorActivity handlers until no - // new ones appear - var callbacks = group.delayedCallbacks, i = 0; - do { - for (; i < callbacks.length; i++) - { callbacks[i].call(null); } - for (var j = 0; j < group.ops.length; j++) { - var op = group.ops[j]; - if (op.cursorActivityHandlers) - { while (op.cursorActivityCalled < op.cursorActivityHandlers.length) - { op.cursorActivityHandlers[op.cursorActivityCalled++].call(null, op.cm); } } - } - } while (i < callbacks.length) - } - - function finishOperation(op, endCb) { - var group = op.ownsGroup; - if (!group) { return } - - try { fireCallbacksForOps(group); } - finally { - operationGroup = null; - endCb(group); - } - } - - var orphanDelayedCallbacks = null; - - // Often, we want to signal events at a point where we are in the - // middle of some work, but don't want the handler to start calling - // other methods on the editor, which might be in an inconsistent - // state or simply not expect any other events to happen. - // signalLater looks whether there are any handlers, and schedules - // them to be executed when the last operation ends, or, if no - // operation is active, when a timeout fires. - function signalLater(emitter, type /*, values...*/) { - var arr = getHandlers(emitter, type); - if (!arr.length) { return } - var args = Array.prototype.slice.call(arguments, 2), list; - if (operationGroup) { - list = operationGroup.delayedCallbacks; - } else if (orphanDelayedCallbacks) { - list = orphanDelayedCallbacks; - } else { - list = orphanDelayedCallbacks = []; - setTimeout(fireOrphanDelayed, 0); - } - var loop = function ( i ) { - list.push(function () { return arr[i].apply(null, args); }); - }; - - for (var i = 0; i < arr.length; ++i) - loop( i ); - } - - function fireOrphanDelayed() { - var delayed = orphanDelayedCallbacks; - orphanDelayedCallbacks = null; - for (var i = 0; i < delayed.length; ++i) { delayed[i](); } - } - - // When an aspect of a line changes, a string is added to - // lineView.changes. This updates the relevant part of the line's - // DOM structure. - function updateLineForChanges(cm, lineView, lineN, dims) { - for (var j = 0; j < lineView.changes.length; j++) { - var type = lineView.changes[j]; - if (type == "text") { updateLineText(cm, lineView); } - else if (type == "gutter") { updateLineGutter(cm, lineView, lineN, dims); } - else if (type == "class") { updateLineClasses(cm, lineView); } - else if (type == "widget") { updateLineWidgets(cm, lineView, dims); } - } - lineView.changes = null; - } - - // Lines with gutter elements, widgets or a background class need to - // be wrapped, and have the extra elements added to the wrapper div - function ensureLineWrapped(lineView) { - if (lineView.node == lineView.text) { - lineView.node = elt("div", null, null, "position: relative"); - if (lineView.text.parentNode) - { lineView.text.parentNode.replaceChild(lineView.node, lineView.text); } - lineView.node.appendChild(lineView.text); - if (ie && ie_version < 8) { lineView.node.style.zIndex = 2; } - } - return lineView.node - } - - function updateLineBackground(cm, lineView) { - var cls = lineView.bgClass ? lineView.bgClass + " " + (lineView.line.bgClass || "") : lineView.line.bgClass; - if (cls) { cls += " CodeMirror-linebackground"; } - if (lineView.background) { - if (cls) { lineView.background.className = cls; } - else { lineView.background.parentNode.removeChild(lineView.background); lineView.background = null; } - } else if (cls) { - var wrap = ensureLineWrapped(lineView); - lineView.background = wrap.insertBefore(elt("div", null, cls), wrap.firstChild); - cm.display.input.setUneditable(lineView.background); - } - } - - // Wrapper around buildLineContent which will reuse the structure - // in display.externalMeasured when possible. - function getLineContent(cm, lineView) { - var ext = cm.display.externalMeasured; - if (ext && ext.line == lineView.line) { - cm.display.externalMeasured = null; - lineView.measure = ext.measure; - return ext.built - } - return buildLineContent(cm, lineView) - } - - // Redraw the line's text. Interacts with the background and text - // classes because the mode may output tokens that influence these - // classes. - function updateLineText(cm, lineView) { - var cls = lineView.text.className; - var built = getLineContent(cm, lineView); - if (lineView.text == lineView.node) { lineView.node = built.pre; } - lineView.text.parentNode.replaceChild(built.pre, lineView.text); - lineView.text = built.pre; - if (built.bgClass != lineView.bgClass || built.textClass != lineView.textClass) { - lineView.bgClass = built.bgClass; - lineView.textClass = built.textClass; - updateLineClasses(cm, lineView); - } else if (cls) { - lineView.text.className = cls; - } - } - - function updateLineClasses(cm, lineView) { - updateLineBackground(cm, lineView); - if (lineView.line.wrapClass) - { ensureLineWrapped(lineView).className = lineView.line.wrapClass; } - else if (lineView.node != lineView.text) - { lineView.node.className = ""; } - var textClass = lineView.textClass ? lineView.textClass + " " + (lineView.line.textClass || "") : lineView.line.textClass; - lineView.text.className = textClass || ""; - } - - function updateLineGutter(cm, lineView, lineN, dims) { - if (lineView.gutter) { - lineView.node.removeChild(lineView.gutter); - lineView.gutter = null; - } - if (lineView.gutterBackground) { - lineView.node.removeChild(lineView.gutterBackground); - lineView.gutterBackground = null; - } - if (lineView.line.gutterClass) { - var wrap = ensureLineWrapped(lineView); - lineView.gutterBackground = elt("div", null, "CodeMirror-gutter-background " + lineView.line.gutterClass, - ("left: " + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px; width: " + (dims.gutterTotalWidth) + "px")); - cm.display.input.setUneditable(lineView.gutterBackground); - wrap.insertBefore(lineView.gutterBackground, lineView.text); - } - var markers = lineView.line.gutterMarkers; - if (cm.options.lineNumbers || markers) { - var wrap$1 = ensureLineWrapped(lineView); - var gutterWrap = lineView.gutter = elt("div", null, "CodeMirror-gutter-wrapper", ("left: " + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px")); - gutterWrap.setAttribute("aria-hidden", "true"); - cm.display.input.setUneditable(gutterWrap); - wrap$1.insertBefore(gutterWrap, lineView.text); - if (lineView.line.gutterClass) - { gutterWrap.className += " " + lineView.line.gutterClass; } - if (cm.options.lineNumbers && (!markers || !markers["CodeMirror-linenumbers"])) - { lineView.lineNumber = gutterWrap.appendChild( - elt("div", lineNumberFor(cm.options, lineN), - "CodeMirror-linenumber CodeMirror-gutter-elt", - ("left: " + (dims.gutterLeft["CodeMirror-linenumbers"]) + "px; width: " + (cm.display.lineNumInnerWidth) + "px"))); } - if (markers) { for (var k = 0; k < cm.display.gutterSpecs.length; ++k) { - var id = cm.display.gutterSpecs[k].className, found = markers.hasOwnProperty(id) && markers[id]; - if (found) - { gutterWrap.appendChild(elt("div", [found], "CodeMirror-gutter-elt", - ("left: " + (dims.gutterLeft[id]) + "px; width: " + (dims.gutterWidth[id]) + "px"))); } - } } - } - } - - function updateLineWidgets(cm, lineView, dims) { - if (lineView.alignable) { lineView.alignable = null; } - var isWidget = classTest("CodeMirror-linewidget"); - for (var node = lineView.node.firstChild, next = (void 0); node; node = next) { - next = node.nextSibling; - if (isWidget.test(node.className)) { lineView.node.removeChild(node); } - } - insertLineWidgets(cm, lineView, dims); - } - - // Build a line's DOM representation from scratch - function buildLineElement(cm, lineView, lineN, dims) { - var built = getLineContent(cm, lineView); - lineView.text = lineView.node = built.pre; - if (built.bgClass) { lineView.bgClass = built.bgClass; } - if (built.textClass) { lineView.textClass = built.textClass; } - - updateLineClasses(cm, lineView); - updateLineGutter(cm, lineView, lineN, dims); - insertLineWidgets(cm, lineView, dims); - return lineView.node - } - - // A lineView may contain multiple logical lines (when merged by - // collapsed spans). The widgets for all of them need to be drawn. - function insertLineWidgets(cm, lineView, dims) { - insertLineWidgetsFor(cm, lineView.line, lineView, dims, true); - if (lineView.rest) { for (var i = 0; i < lineView.rest.length; i++) - { insertLineWidgetsFor(cm, lineView.rest[i], lineView, dims, false); } } - } - - function insertLineWidgetsFor(cm, line, lineView, dims, allowAbove) { - if (!line.widgets) { return } - var wrap = ensureLineWrapped(lineView); - for (var i = 0, ws = line.widgets; i < ws.length; ++i) { - var widget = ws[i], node = elt("div", [widget.node], "CodeMirror-linewidget" + (widget.className ? " " + widget.className : "")); - if (!widget.handleMouseEvents) { node.setAttribute("cm-ignore-events", "true"); } - positionLineWidget(widget, node, lineView, dims); - cm.display.input.setUneditable(node); - if (allowAbove && widget.above) - { wrap.insertBefore(node, lineView.gutter || lineView.text); } - else - { wrap.appendChild(node); } - signalLater(widget, "redraw"); - } - } - - function positionLineWidget(widget, node, lineView, dims) { - if (widget.noHScroll) { - (lineView.alignable || (lineView.alignable = [])).push(node); - var width = dims.wrapperWidth; - node.style.left = dims.fixedPos + "px"; - if (!widget.coverGutter) { - width -= dims.gutterTotalWidth; - node.style.paddingLeft = dims.gutterTotalWidth + "px"; - } - node.style.width = width + "px"; - } - if (widget.coverGutter) { - node.style.zIndex = 5; - node.style.position = "relative"; - if (!widget.noHScroll) { node.style.marginLeft = -dims.gutterTotalWidth + "px"; } - } - } - - function widgetHeight(widget) { - if (widget.height != null) { return widget.height } - var cm = widget.doc.cm; - if (!cm) { return 0 } - if (!contains(document.body, widget.node)) { - var parentStyle = "position: relative;"; - if (widget.coverGutter) - { parentStyle += "margin-left: -" + cm.display.gutters.offsetWidth + "px;"; } - if (widget.noHScroll) - { parentStyle += "width: " + cm.display.wrapper.clientWidth + "px;"; } - removeChildrenAndAdd(cm.display.measure, elt("div", [widget.node], null, parentStyle)); - } - return widget.height = widget.node.parentNode.offsetHeight - } - - // Return true when the given mouse event happened in a widget - function eventInWidget(display, e) { - for (var n = e_target(e); n != display.wrapper; n = n.parentNode) { - if (!n || (n.nodeType == 1 && n.getAttribute("cm-ignore-events") == "true") || - (n.parentNode == display.sizer && n != display.mover)) - { return true } - } - } - - // POSITION MEASUREMENT - - function paddingTop(display) {return display.lineSpace.offsetTop} - function paddingVert(display) {return display.mover.offsetHeight - display.lineSpace.offsetHeight} - function paddingH(display) { - if (display.cachedPaddingH) { return display.cachedPaddingH } - var e = removeChildrenAndAdd(display.measure, elt("pre", "x", "CodeMirror-line-like")); - var style = window.getComputedStyle ? window.getComputedStyle(e) : e.currentStyle; - var data = {left: parseInt(style.paddingLeft), right: parseInt(style.paddingRight)}; - if (!isNaN(data.left) && !isNaN(data.right)) { display.cachedPaddingH = data; } - return data - } - - function scrollGap(cm) { return scrollerGap - cm.display.nativeBarWidth } - function displayWidth(cm) { - return cm.display.scroller.clientWidth - scrollGap(cm) - cm.display.barWidth - } - function displayHeight(cm) { - return cm.display.scroller.clientHeight - scrollGap(cm) - cm.display.barHeight - } - - // Ensure the lineView.wrapping.heights array is populated. This is - // an array of bottom offsets for the lines that make up a drawn - // line. When lineWrapping is on, there might be more than one - // height. - function ensureLineHeights(cm, lineView, rect) { - var wrapping = cm.options.lineWrapping; - var curWidth = wrapping && displayWidth(cm); - if (!lineView.measure.heights || wrapping && lineView.measure.width != curWidth) { - var heights = lineView.measure.heights = []; - if (wrapping) { - lineView.measure.width = curWidth; - var rects = lineView.text.firstChild.getClientRects(); - for (var i = 0; i < rects.length - 1; i++) { - var cur = rects[i], next = rects[i + 1]; - if (Math.abs(cur.bottom - next.bottom) > 2) - { heights.push((cur.bottom + next.top) / 2 - rect.top); } - } - } - heights.push(rect.bottom - rect.top); - } - } - - // Find a line map (mapping character offsets to text nodes) and a - // measurement cache for the given line number. (A line view might - // contain multiple lines when collapsed ranges are present.) - function mapFromLineView(lineView, line, lineN) { - if (lineView.line == line) - { return {map: lineView.measure.map, cache: lineView.measure.cache} } - if (lineView.rest) { - for (var i = 0; i < lineView.rest.length; i++) - { if (lineView.rest[i] == line) - { return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i]} } } - for (var i$1 = 0; i$1 < lineView.rest.length; i$1++) - { if (lineNo(lineView.rest[i$1]) > lineN) - { return {map: lineView.measure.maps[i$1], cache: lineView.measure.caches[i$1], before: true} } } - } - } - - // Render a line into the hidden node display.externalMeasured. Used - // when measurement is needed for a line that's not in the viewport. - function updateExternalMeasurement(cm, line) { - line = visualLine(line); - var lineN = lineNo(line); - var view = cm.display.externalMeasured = new LineView(cm.doc, line, lineN); - view.lineN = lineN; - var built = view.built = buildLineContent(cm, view); - view.text = built.pre; - removeChildrenAndAdd(cm.display.lineMeasure, built.pre); - return view - } - - // Get a {top, bottom, left, right} box (in line-local coordinates) - // for a given character. - function measureChar(cm, line, ch, bias) { - return measureCharPrepared(cm, prepareMeasureForLine(cm, line), ch, bias) - } - - // Find a line view that corresponds to the given line number. - function findViewForLine(cm, lineN) { - if (lineN >= cm.display.viewFrom && lineN < cm.display.viewTo) - { return cm.display.view[findViewIndex(cm, lineN)] } - var ext = cm.display.externalMeasured; - if (ext && lineN >= ext.lineN && lineN < ext.lineN + ext.size) - { return ext } - } - - // Measurement can be split in two steps, the set-up work that - // applies to the whole line, and the measurement of the actual - // character. Functions like coordsChar, that need to do a lot of - // measurements in a row, can thus ensure that the set-up work is - // only done once. - function prepareMeasureForLine(cm, line) { - var lineN = lineNo(line); - var view = findViewForLine(cm, lineN); - if (view && !view.text) { - view = null; - } else if (view && view.changes) { - updateLineForChanges(cm, view, lineN, getDimensions(cm)); - cm.curOp.forceUpdate = true; - } - if (!view) - { view = updateExternalMeasurement(cm, line); } - - var info = mapFromLineView(view, line, lineN); - return { - line: line, view: view, rect: null, - map: info.map, cache: info.cache, before: info.before, - hasHeights: false - } - } - - // Given a prepared measurement object, measures the position of an - // actual character (or fetches it from the cache). - function measureCharPrepared(cm, prepared, ch, bias, varHeight) { - if (prepared.before) { ch = -1; } - var key = ch + (bias || ""), found; - if (prepared.cache.hasOwnProperty(key)) { - found = prepared.cache[key]; - } else { - if (!prepared.rect) - { prepared.rect = prepared.view.text.getBoundingClientRect(); } - if (!prepared.hasHeights) { - ensureLineHeights(cm, prepared.view, prepared.rect); - prepared.hasHeights = true; - } - found = measureCharInner(cm, prepared, ch, bias); - if (!found.bogus) { prepared.cache[key] = found; } - } - return {left: found.left, right: found.right, - top: varHeight ? found.rtop : found.top, - bottom: varHeight ? found.rbottom : found.bottom} - } - - var nullRect = {left: 0, right: 0, top: 0, bottom: 0}; - - function nodeAndOffsetInLineMap(map, ch, bias) { - var node, start, end, collapse, mStart, mEnd; - // First, search the line map for the text node corresponding to, - // or closest to, the target character. - for (var i = 0; i < map.length; i += 3) { - mStart = map[i]; - mEnd = map[i + 1]; - if (ch < mStart) { - start = 0; end = 1; - collapse = "left"; - } else if (ch < mEnd) { - start = ch - mStart; - end = start + 1; - } else if (i == map.length - 3 || ch == mEnd && map[i + 3] > ch) { - end = mEnd - mStart; - start = end - 1; - if (ch >= mEnd) { collapse = "right"; } - } - if (start != null) { - node = map[i + 2]; - if (mStart == mEnd && bias == (node.insertLeft ? "left" : "right")) - { collapse = bias; } - if (bias == "left" && start == 0) - { while (i && map[i - 2] == map[i - 3] && map[i - 1].insertLeft) { - node = map[(i -= 3) + 2]; - collapse = "left"; - } } - if (bias == "right" && start == mEnd - mStart) - { while (i < map.length - 3 && map[i + 3] == map[i + 4] && !map[i + 5].insertLeft) { - node = map[(i += 3) + 2]; - collapse = "right"; - } } - break - } - } - return {node: node, start: start, end: end, collapse: collapse, coverStart: mStart, coverEnd: mEnd} - } - - function getUsefulRect(rects, bias) { - var rect = nullRect; - if (bias == "left") { for (var i = 0; i < rects.length; i++) { - if ((rect = rects[i]).left != rect.right) { break } - } } else { for (var i$1 = rects.length - 1; i$1 >= 0; i$1--) { - if ((rect = rects[i$1]).left != rect.right) { break } - } } - return rect - } - - function measureCharInner(cm, prepared, ch, bias) { - var place = nodeAndOffsetInLineMap(prepared.map, ch, bias); - var node = place.node, start = place.start, end = place.end, collapse = place.collapse; - - var rect; - if (node.nodeType == 3) { // If it is a text node, use a range to retrieve the coordinates. - for (var i$1 = 0; i$1 < 4; i$1++) { // Retry a maximum of 4 times when nonsense rectangles are returned - while (start && isExtendingChar(prepared.line.text.charAt(place.coverStart + start))) { --start; } - while (place.coverStart + end < place.coverEnd && isExtendingChar(prepared.line.text.charAt(place.coverStart + end))) { ++end; } - if (ie && ie_version < 9 && start == 0 && end == place.coverEnd - place.coverStart) - { rect = node.parentNode.getBoundingClientRect(); } - else - { rect = getUsefulRect(range(node, start, end).getClientRects(), bias); } - if (rect.left || rect.right || start == 0) { break } - end = start; - start = start - 1; - collapse = "right"; - } - if (ie && ie_version < 11) { rect = maybeUpdateRectForZooming(cm.display.measure, rect); } - } else { // If it is a widget, simply get the box for the whole widget. - if (start > 0) { collapse = bias = "right"; } - var rects; - if (cm.options.lineWrapping && (rects = node.getClientRects()).length > 1) - { rect = rects[bias == "right" ? rects.length - 1 : 0]; } - else - { rect = node.getBoundingClientRect(); } - } - if (ie && ie_version < 9 && !start && (!rect || !rect.left && !rect.right)) { - var rSpan = node.parentNode.getClientRects()[0]; - if (rSpan) - { rect = {left: rSpan.left, right: rSpan.left + charWidth(cm.display), top: rSpan.top, bottom: rSpan.bottom}; } - else - { rect = nullRect; } - } - - var rtop = rect.top - prepared.rect.top, rbot = rect.bottom - prepared.rect.top; - var mid = (rtop + rbot) / 2; - var heights = prepared.view.measure.heights; - var i = 0; - for (; i < heights.length - 1; i++) - { if (mid < heights[i]) { break } } - var top = i ? heights[i - 1] : 0, bot = heights[i]; - var result = {left: (collapse == "right" ? rect.right : rect.left) - prepared.rect.left, - right: (collapse == "left" ? rect.left : rect.right) - prepared.rect.left, - top: top, bottom: bot}; - if (!rect.left && !rect.right) { result.bogus = true; } - if (!cm.options.singleCursorHeightPerLine) { result.rtop = rtop; result.rbottom = rbot; } - - return result - } - - // Work around problem with bounding client rects on ranges being - // returned incorrectly when zoomed on IE10 and below. - function maybeUpdateRectForZooming(measure, rect) { - if (!window.screen || screen.logicalXDPI == null || - screen.logicalXDPI == screen.deviceXDPI || !hasBadZoomedRects(measure)) - { return rect } - var scaleX = screen.logicalXDPI / screen.deviceXDPI; - var scaleY = screen.logicalYDPI / screen.deviceYDPI; - return {left: rect.left * scaleX, right: rect.right * scaleX, - top: rect.top * scaleY, bottom: rect.bottom * scaleY} - } - - function clearLineMeasurementCacheFor(lineView) { - if (lineView.measure) { - lineView.measure.cache = {}; - lineView.measure.heights = null; - if (lineView.rest) { for (var i = 0; i < lineView.rest.length; i++) - { lineView.measure.caches[i] = {}; } } - } - } - - function clearLineMeasurementCache(cm) { - cm.display.externalMeasure = null; - removeChildren(cm.display.lineMeasure); - for (var i = 0; i < cm.display.view.length; i++) - { clearLineMeasurementCacheFor(cm.display.view[i]); } - } - - function clearCaches(cm) { - clearLineMeasurementCache(cm); - cm.display.cachedCharWidth = cm.display.cachedTextHeight = cm.display.cachedPaddingH = null; - if (!cm.options.lineWrapping) { cm.display.maxLineChanged = true; } - cm.display.lineNumChars = null; - } - - function pageScrollX() { - // Work around https://bugs.chromium.org/p/chromium/issues/detail?id=489206 - // which causes page_Offset and bounding client rects to use - // different reference viewports and invalidate our calculations. - if (chrome && android) { return -(document.body.getBoundingClientRect().left - parseInt(getComputedStyle(document.body).marginLeft)) } - return window.pageXOffset || (document.documentElement || document.body).scrollLeft - } - function pageScrollY() { - if (chrome && android) { return -(document.body.getBoundingClientRect().top - parseInt(getComputedStyle(document.body).marginTop)) } - return window.pageYOffset || (document.documentElement || document.body).scrollTop - } - - function widgetTopHeight(lineObj) { - var ref = visualLine(lineObj); - var widgets = ref.widgets; - var height = 0; - if (widgets) { for (var i = 0; i < widgets.length; ++i) { if (widgets[i].above) - { height += widgetHeight(widgets[i]); } } } - return height - } - - // Converts a {top, bottom, left, right} box from line-local - // coordinates into another coordinate system. Context may be one of - // "line", "div" (display.lineDiv), "local"./null (editor), "window", - // or "page". - function intoCoordSystem(cm, lineObj, rect, context, includeWidgets) { - if (!includeWidgets) { - var height = widgetTopHeight(lineObj); - rect.top += height; rect.bottom += height; - } - if (context == "line") { return rect } - if (!context) { context = "local"; } - var yOff = heightAtLine(lineObj); - if (context == "local") { yOff += paddingTop(cm.display); } - else { yOff -= cm.display.viewOffset; } - if (context == "page" || context == "window") { - var lOff = cm.display.lineSpace.getBoundingClientRect(); - yOff += lOff.top + (context == "window" ? 0 : pageScrollY()); - var xOff = lOff.left + (context == "window" ? 0 : pageScrollX()); - rect.left += xOff; rect.right += xOff; - } - rect.top += yOff; rect.bottom += yOff; - return rect - } - - // Coverts a box from "div" coords to another coordinate system. - // Context may be "window", "page", "div", or "local"./null. - function fromCoordSystem(cm, coords, context) { - if (context == "div") { return coords } - var left = coords.left, top = coords.top; - // First move into "page" coordinate system - if (context == "page") { - left -= pageScrollX(); - top -= pageScrollY(); - } else if (context == "local" || !context) { - var localBox = cm.display.sizer.getBoundingClientRect(); - left += localBox.left; - top += localBox.top; - } - - var lineSpaceBox = cm.display.lineSpace.getBoundingClientRect(); - return {left: left - lineSpaceBox.left, top: top - lineSpaceBox.top} - } - - function charCoords(cm, pos, context, lineObj, bias) { - if (!lineObj) { lineObj = getLine(cm.doc, pos.line); } - return intoCoordSystem(cm, lineObj, measureChar(cm, lineObj, pos.ch, bias), context) - } - - // Returns a box for a given cursor position, which may have an - // 'other' property containing the position of the secondary cursor - // on a bidi boundary. - // A cursor Pos(line, char, "before") is on the same visual line as `char - 1` - // and after `char - 1` in writing order of `char - 1` - // A cursor Pos(line, char, "after") is on the same visual line as `char` - // and before `char` in writing order of `char` - // Examples (upper-case letters are RTL, lower-case are LTR): - // Pos(0, 1, ...) - // before after - // ab a|b a|b - // aB a|B aB| - // Ab |Ab A|b - // AB B|A B|A - // Every position after the last character on a line is considered to stick - // to the last character on the line. - function cursorCoords(cm, pos, context, lineObj, preparedMeasure, varHeight) { - lineObj = lineObj || getLine(cm.doc, pos.line); - if (!preparedMeasure) { preparedMeasure = prepareMeasureForLine(cm, lineObj); } - function get(ch, right) { - var m = measureCharPrepared(cm, preparedMeasure, ch, right ? "right" : "left", varHeight); - if (right) { m.left = m.right; } else { m.right = m.left; } - return intoCoordSystem(cm, lineObj, m, context) - } - var order = getOrder(lineObj, cm.doc.direction), ch = pos.ch, sticky = pos.sticky; - if (ch >= lineObj.text.length) { - ch = lineObj.text.length; - sticky = "before"; - } else if (ch <= 0) { - ch = 0; - sticky = "after"; - } - if (!order) { return get(sticky == "before" ? ch - 1 : ch, sticky == "before") } - - function getBidi(ch, partPos, invert) { - var part = order[partPos], right = part.level == 1; - return get(invert ? ch - 1 : ch, right != invert) - } - var partPos = getBidiPartAt(order, ch, sticky); - var other = bidiOther; - var val = getBidi(ch, partPos, sticky == "before"); - if (other != null) { val.other = getBidi(ch, other, sticky != "before"); } - return val - } - - // Used to cheaply estimate the coordinates for a position. Used for - // intermediate scroll updates. - function estimateCoords(cm, pos) { - var left = 0; - pos = clipPos(cm.doc, pos); - if (!cm.options.lineWrapping) { left = charWidth(cm.display) * pos.ch; } - var lineObj = getLine(cm.doc, pos.line); - var top = heightAtLine(lineObj) + paddingTop(cm.display); - return {left: left, right: left, top: top, bottom: top + lineObj.height} - } - - // Positions returned by coordsChar contain some extra information. - // xRel is the relative x position of the input coordinates compared - // to the found position (so xRel > 0 means the coordinates are to - // the right of the character position, for example). When outside - // is true, that means the coordinates lie outside the line's - // vertical range. - function PosWithInfo(line, ch, sticky, outside, xRel) { - var pos = Pos(line, ch, sticky); - pos.xRel = xRel; - if (outside) { pos.outside = outside; } - return pos - } - - // Compute the character position closest to the given coordinates. - // Input must be lineSpace-local ("div" coordinate system). - function coordsChar(cm, x, y) { - var doc = cm.doc; - y += cm.display.viewOffset; - if (y < 0) { return PosWithInfo(doc.first, 0, null, -1, -1) } - var lineN = lineAtHeight(doc, y), last = doc.first + doc.size - 1; - if (lineN > last) - { return PosWithInfo(doc.first + doc.size - 1, getLine(doc, last).text.length, null, 1, 1) } - if (x < 0) { x = 0; } - - var lineObj = getLine(doc, lineN); - for (;;) { - var found = coordsCharInner(cm, lineObj, lineN, x, y); - var collapsed = collapsedSpanAround(lineObj, found.ch + (found.xRel > 0 || found.outside > 0 ? 1 : 0)); - if (!collapsed) { return found } - var rangeEnd = collapsed.find(1); - if (rangeEnd.line == lineN) { return rangeEnd } - lineObj = getLine(doc, lineN = rangeEnd.line); - } - } - - function wrappedLineExtent(cm, lineObj, preparedMeasure, y) { - y -= widgetTopHeight(lineObj); - var end = lineObj.text.length; - var begin = findFirst(function (ch) { return measureCharPrepared(cm, preparedMeasure, ch - 1).bottom <= y; }, end, 0); - end = findFirst(function (ch) { return measureCharPrepared(cm, preparedMeasure, ch).top > y; }, begin, end); - return {begin: begin, end: end} - } - - function wrappedLineExtentChar(cm, lineObj, preparedMeasure, target) { - if (!preparedMeasure) { preparedMeasure = prepareMeasureForLine(cm, lineObj); } - var targetTop = intoCoordSystem(cm, lineObj, measureCharPrepared(cm, preparedMeasure, target), "line").top; - return wrappedLineExtent(cm, lineObj, preparedMeasure, targetTop) - } - - // Returns true if the given side of a box is after the given - // coordinates, in top-to-bottom, left-to-right order. - function boxIsAfter(box, x, y, left) { - return box.bottom <= y ? false : box.top > y ? true : (left ? box.left : box.right) > x - } - - function coordsCharInner(cm, lineObj, lineNo, x, y) { - // Move y into line-local coordinate space - y -= heightAtLine(lineObj); - var preparedMeasure = prepareMeasureForLine(cm, lineObj); - // When directly calling `measureCharPrepared`, we have to adjust - // for the widgets at this line. - var widgetHeight = widgetTopHeight(lineObj); - var begin = 0, end = lineObj.text.length, ltr = true; - - var order = getOrder(lineObj, cm.doc.direction); - // If the line isn't plain left-to-right text, first figure out - // which bidi section the coordinates fall into. - if (order) { - var part = (cm.options.lineWrapping ? coordsBidiPartWrapped : coordsBidiPart) - (cm, lineObj, lineNo, preparedMeasure, order, x, y); - ltr = part.level != 1; - // The awkward -1 offsets are needed because findFirst (called - // on these below) will treat its first bound as inclusive, - // second as exclusive, but we want to actually address the - // characters in the part's range - begin = ltr ? part.from : part.to - 1; - end = ltr ? part.to : part.from - 1; - } - - // A binary search to find the first character whose bounding box - // starts after the coordinates. If we run across any whose box wrap - // the coordinates, store that. - var chAround = null, boxAround = null; - var ch = findFirst(function (ch) { - var box = measureCharPrepared(cm, preparedMeasure, ch); - box.top += widgetHeight; box.bottom += widgetHeight; - if (!boxIsAfter(box, x, y, false)) { return false } - if (box.top <= y && box.left <= x) { - chAround = ch; - boxAround = box; - } - return true - }, begin, end); - - var baseX, sticky, outside = false; - // If a box around the coordinates was found, use that - if (boxAround) { - // Distinguish coordinates nearer to the left or right side of the box - var atLeft = x - boxAround.left < boxAround.right - x, atStart = atLeft == ltr; - ch = chAround + (atStart ? 0 : 1); - sticky = atStart ? "after" : "before"; - baseX = atLeft ? boxAround.left : boxAround.right; - } else { - // (Adjust for extended bound, if necessary.) - if (!ltr && (ch == end || ch == begin)) { ch++; } - // To determine which side to associate with, get the box to the - // left of the character and compare it's vertical position to the - // coordinates - sticky = ch == 0 ? "after" : ch == lineObj.text.length ? "before" : - (measureCharPrepared(cm, preparedMeasure, ch - (ltr ? 1 : 0)).bottom + widgetHeight <= y) == ltr ? - "after" : "before"; - // Now get accurate coordinates for this place, in order to get a - // base X position - var coords = cursorCoords(cm, Pos(lineNo, ch, sticky), "line", lineObj, preparedMeasure); - baseX = coords.left; - outside = y < coords.top ? -1 : y >= coords.bottom ? 1 : 0; - } - - ch = skipExtendingChars(lineObj.text, ch, 1); - return PosWithInfo(lineNo, ch, sticky, outside, x - baseX) - } - - function coordsBidiPart(cm, lineObj, lineNo, preparedMeasure, order, x, y) { - // Bidi parts are sorted left-to-right, and in a non-line-wrapping - // situation, we can take this ordering to correspond to the visual - // ordering. This finds the first part whose end is after the given - // coordinates. - var index = findFirst(function (i) { - var part = order[i], ltr = part.level != 1; - return boxIsAfter(cursorCoords(cm, Pos(lineNo, ltr ? part.to : part.from, ltr ? "before" : "after"), - "line", lineObj, preparedMeasure), x, y, true) - }, 0, order.length - 1); - var part = order[index]; - // If this isn't the first part, the part's start is also after - // the coordinates, and the coordinates aren't on the same line as - // that start, move one part back. - if (index > 0) { - var ltr = part.level != 1; - var start = cursorCoords(cm, Pos(lineNo, ltr ? part.from : part.to, ltr ? "after" : "before"), - "line", lineObj, preparedMeasure); - if (boxIsAfter(start, x, y, true) && start.top > y) - { part = order[index - 1]; } - } - return part - } - - function coordsBidiPartWrapped(cm, lineObj, _lineNo, preparedMeasure, order, x, y) { - // In a wrapped line, rtl text on wrapping boundaries can do things - // that don't correspond to the ordering in our `order` array at - // all, so a binary search doesn't work, and we want to return a - // part that only spans one line so that the binary search in - // coordsCharInner is safe. As such, we first find the extent of the - // wrapped line, and then do a flat search in which we discard any - // spans that aren't on the line. - var ref = wrappedLineExtent(cm, lineObj, preparedMeasure, y); - var begin = ref.begin; - var end = ref.end; - if (/\s/.test(lineObj.text.charAt(end - 1))) { end--; } - var part = null, closestDist = null; - for (var i = 0; i < order.length; i++) { - var p = order[i]; - if (p.from >= end || p.to <= begin) { continue } - var ltr = p.level != 1; - var endX = measureCharPrepared(cm, preparedMeasure, ltr ? Math.min(end, p.to) - 1 : Math.max(begin, p.from)).right; - // Weigh against spans ending before this, so that they are only - // picked if nothing ends after - var dist = endX < x ? x - endX + 1e9 : endX - x; - if (!part || closestDist > dist) { - part = p; - closestDist = dist; - } - } - if (!part) { part = order[order.length - 1]; } - // Clip the part to the wrapped line. - if (part.from < begin) { part = {from: begin, to: part.to, level: part.level}; } - if (part.to > end) { part = {from: part.from, to: end, level: part.level}; } - return part - } - - var measureText; - // Compute the default text height. - function textHeight(display) { - if (display.cachedTextHeight != null) { return display.cachedTextHeight } - if (measureText == null) { - measureText = elt("pre", null, "CodeMirror-line-like"); - // Measure a bunch of lines, for browsers that compute - // fractional heights. - for (var i = 0; i < 49; ++i) { - measureText.appendChild(document.createTextNode("x")); - measureText.appendChild(elt("br")); - } - measureText.appendChild(document.createTextNode("x")); - } - removeChildrenAndAdd(display.measure, measureText); - var height = measureText.offsetHeight / 50; - if (height > 3) { display.cachedTextHeight = height; } - removeChildren(display.measure); - return height || 1 - } - - // Compute the default character width. - function charWidth(display) { - if (display.cachedCharWidth != null) { return display.cachedCharWidth } - var anchor = elt("span", "xxxxxxxxxx"); - var pre = elt("pre", [anchor], "CodeMirror-line-like"); - removeChildrenAndAdd(display.measure, pre); - var rect = anchor.getBoundingClientRect(), width = (rect.right - rect.left) / 10; - if (width > 2) { display.cachedCharWidth = width; } - return width || 10 - } - - // Do a bulk-read of the DOM positions and sizes needed to draw the - // view, so that we don't interleave reading and writing to the DOM. - function getDimensions(cm) { - var d = cm.display, left = {}, width = {}; - var gutterLeft = d.gutters.clientLeft; - for (var n = d.gutters.firstChild, i = 0; n; n = n.nextSibling, ++i) { - var id = cm.display.gutterSpecs[i].className; - left[id] = n.offsetLeft + n.clientLeft + gutterLeft; - width[id] = n.clientWidth; - } - return {fixedPos: compensateForHScroll(d), - gutterTotalWidth: d.gutters.offsetWidth, - gutterLeft: left, - gutterWidth: width, - wrapperWidth: d.wrapper.clientWidth} - } - - // Computes display.scroller.scrollLeft + display.gutters.offsetWidth, - // but using getBoundingClientRect to get a sub-pixel-accurate - // result. - function compensateForHScroll(display) { - return display.scroller.getBoundingClientRect().left - display.sizer.getBoundingClientRect().left - } - - // Returns a function that estimates the height of a line, to use as - // first approximation until the line becomes visible (and is thus - // properly measurable). - function estimateHeight(cm) { - var th = textHeight(cm.display), wrapping = cm.options.lineWrapping; - var perLine = wrapping && Math.max(5, cm.display.scroller.clientWidth / charWidth(cm.display) - 3); - return function (line) { - if (lineIsHidden(cm.doc, line)) { return 0 } - - var widgetsHeight = 0; - if (line.widgets) { for (var i = 0; i < line.widgets.length; i++) { - if (line.widgets[i].height) { widgetsHeight += line.widgets[i].height; } - } } - - if (wrapping) - { return widgetsHeight + (Math.ceil(line.text.length / perLine) || 1) * th } - else - { return widgetsHeight + th } - } - } - - function estimateLineHeights(cm) { - var doc = cm.doc, est = estimateHeight(cm); - doc.iter(function (line) { - var estHeight = est(line); - if (estHeight != line.height) { updateLineHeight(line, estHeight); } - }); - } - - // Given a mouse event, find the corresponding position. If liberal - // is false, it checks whether a gutter or scrollbar was clicked, - // and returns null if it was. forRect is used by rectangular - // selections, and tries to estimate a character position even for - // coordinates beyond the right of the text. - function posFromMouse(cm, e, liberal, forRect) { - var display = cm.display; - if (!liberal && e_target(e).getAttribute("cm-not-content") == "true") { return null } - - var x, y, space = display.lineSpace.getBoundingClientRect(); - // Fails unpredictably on IE[67] when mouse is dragged around quickly. - try { x = e.clientX - space.left; y = e.clientY - space.top; } - catch (e$1) { return null } - var coords = coordsChar(cm, x, y), line; - if (forRect && coords.xRel > 0 && (line = getLine(cm.doc, coords.line).text).length == coords.ch) { - var colDiff = countColumn(line, line.length, cm.options.tabSize) - line.length; - coords = Pos(coords.line, Math.max(0, Math.round((x - paddingH(cm.display).left) / charWidth(cm.display)) - colDiff)); - } - return coords - } - - // Find the view element corresponding to a given line. Return null - // when the line isn't visible. - function findViewIndex(cm, n) { - if (n >= cm.display.viewTo) { return null } - n -= cm.display.viewFrom; - if (n < 0) { return null } - var view = cm.display.view; - for (var i = 0; i < view.length; i++) { - n -= view[i].size; - if (n < 0) { return i } - } - } - - // Updates the display.view data structure for a given change to the - // document. From and to are in pre-change coordinates. Lendiff is - // the amount of lines added or subtracted by the change. This is - // used for changes that span multiple lines, or change the way - // lines are divided into visual lines. regLineChange (below) - // registers single-line changes. - function regChange(cm, from, to, lendiff) { - if (from == null) { from = cm.doc.first; } - if (to == null) { to = cm.doc.first + cm.doc.size; } - if (!lendiff) { lendiff = 0; } - - var display = cm.display; - if (lendiff && to < display.viewTo && - (display.updateLineNumbers == null || display.updateLineNumbers > from)) - { display.updateLineNumbers = from; } - - cm.curOp.viewChanged = true; - - if (from >= display.viewTo) { // Change after - if (sawCollapsedSpans && visualLineNo(cm.doc, from) < display.viewTo) - { resetView(cm); } - } else if (to <= display.viewFrom) { // Change before - if (sawCollapsedSpans && visualLineEndNo(cm.doc, to + lendiff) > display.viewFrom) { - resetView(cm); - } else { - display.viewFrom += lendiff; - display.viewTo += lendiff; - } - } else if (from <= display.viewFrom && to >= display.viewTo) { // Full overlap - resetView(cm); - } else if (from <= display.viewFrom) { // Top overlap - var cut = viewCuttingPoint(cm, to, to + lendiff, 1); - if (cut) { - display.view = display.view.slice(cut.index); - display.viewFrom = cut.lineN; - display.viewTo += lendiff; - } else { - resetView(cm); - } - } else if (to >= display.viewTo) { // Bottom overlap - var cut$1 = viewCuttingPoint(cm, from, from, -1); - if (cut$1) { - display.view = display.view.slice(0, cut$1.index); - display.viewTo = cut$1.lineN; - } else { - resetView(cm); - } - } else { // Gap in the middle - var cutTop = viewCuttingPoint(cm, from, from, -1); - var cutBot = viewCuttingPoint(cm, to, to + lendiff, 1); - if (cutTop && cutBot) { - display.view = display.view.slice(0, cutTop.index) - .concat(buildViewArray(cm, cutTop.lineN, cutBot.lineN)) - .concat(display.view.slice(cutBot.index)); - display.viewTo += lendiff; - } else { - resetView(cm); - } - } - - var ext = display.externalMeasured; - if (ext) { - if (to < ext.lineN) - { ext.lineN += lendiff; } - else if (from < ext.lineN + ext.size) - { display.externalMeasured = null; } - } - } - - // Register a change to a single line. Type must be one of "text", - // "gutter", "class", "widget" - function regLineChange(cm, line, type) { - cm.curOp.viewChanged = true; - var display = cm.display, ext = cm.display.externalMeasured; - if (ext && line >= ext.lineN && line < ext.lineN + ext.size) - { display.externalMeasured = null; } - - if (line < display.viewFrom || line >= display.viewTo) { return } - var lineView = display.view[findViewIndex(cm, line)]; - if (lineView.node == null) { return } - var arr = lineView.changes || (lineView.changes = []); - if (indexOf(arr, type) == -1) { arr.push(type); } - } - - // Clear the view. - function resetView(cm) { - cm.display.viewFrom = cm.display.viewTo = cm.doc.first; - cm.display.view = []; - cm.display.viewOffset = 0; - } - - function viewCuttingPoint(cm, oldN, newN, dir) { - var index = findViewIndex(cm, oldN), diff, view = cm.display.view; - if (!sawCollapsedSpans || newN == cm.doc.first + cm.doc.size) - { return {index: index, lineN: newN} } - var n = cm.display.viewFrom; - for (var i = 0; i < index; i++) - { n += view[i].size; } - if (n != oldN) { - if (dir > 0) { - if (index == view.length - 1) { return null } - diff = (n + view[index].size) - oldN; - index++; - } else { - diff = n - oldN; - } - oldN += diff; newN += diff; - } - while (visualLineNo(cm.doc, newN) != newN) { - if (index == (dir < 0 ? 0 : view.length - 1)) { return null } - newN += dir * view[index - (dir < 0 ? 1 : 0)].size; - index += dir; - } - return {index: index, lineN: newN} - } - - // Force the view to cover a given range, adding empty view element - // or clipping off existing ones as needed. - function adjustView(cm, from, to) { - var display = cm.display, view = display.view; - if (view.length == 0 || from >= display.viewTo || to <= display.viewFrom) { - display.view = buildViewArray(cm, from, to); - display.viewFrom = from; - } else { - if (display.viewFrom > from) - { display.view = buildViewArray(cm, from, display.viewFrom).concat(display.view); } - else if (display.viewFrom < from) - { display.view = display.view.slice(findViewIndex(cm, from)); } - display.viewFrom = from; - if (display.viewTo < to) - { display.view = display.view.concat(buildViewArray(cm, display.viewTo, to)); } - else if (display.viewTo > to) - { display.view = display.view.slice(0, findViewIndex(cm, to)); } - } - display.viewTo = to; - } - - // Count the number of lines in the view whose DOM representation is - // out of date (or nonexistent). - function countDirtyView(cm) { - var view = cm.display.view, dirty = 0; - for (var i = 0; i < view.length; i++) { - var lineView = view[i]; - if (!lineView.hidden && (!lineView.node || lineView.changes)) { ++dirty; } - } - return dirty - } - - function updateSelection(cm) { - cm.display.input.showSelection(cm.display.input.prepareSelection()); - } - - function prepareSelection(cm, primary) { - if ( primary === void 0 ) primary = true; - - var doc = cm.doc, result = {}; - var curFragment = result.cursors = document.createDocumentFragment(); - var selFragment = result.selection = document.createDocumentFragment(); - - var customCursor = cm.options.$customCursor; - if (customCursor) { primary = true; } - for (var i = 0; i < doc.sel.ranges.length; i++) { - if (!primary && i == doc.sel.primIndex) { continue } - var range = doc.sel.ranges[i]; - if (range.from().line >= cm.display.viewTo || range.to().line < cm.display.viewFrom) { continue } - var collapsed = range.empty(); - if (customCursor) { - var head = customCursor(cm, range); - if (head) { drawSelectionCursor(cm, head, curFragment); } - } else if (collapsed || cm.options.showCursorWhenSelecting) { - drawSelectionCursor(cm, range.head, curFragment); - } - if (!collapsed) - { drawSelectionRange(cm, range, selFragment); } - } - return result - } - - // Draws a cursor for the given range - function drawSelectionCursor(cm, head, output) { - var pos = cursorCoords(cm, head, "div", null, null, !cm.options.singleCursorHeightPerLine); - - var cursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor")); - cursor.style.left = pos.left + "px"; - cursor.style.top = pos.top + "px"; - cursor.style.height = Math.max(0, pos.bottom - pos.top) * cm.options.cursorHeight + "px"; - - if (/\bcm-fat-cursor\b/.test(cm.getWrapperElement().className)) { - var charPos = charCoords(cm, head, "div", null, null); - var width = charPos.right - charPos.left; - cursor.style.width = (width > 0 ? width : cm.defaultCharWidth()) + "px"; - } - - if (pos.other) { - // Secondary cursor, shown when on a 'jump' in bi-directional text - var otherCursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor CodeMirror-secondarycursor")); - otherCursor.style.display = ""; - otherCursor.style.left = pos.other.left + "px"; - otherCursor.style.top = pos.other.top + "px"; - otherCursor.style.height = (pos.other.bottom - pos.other.top) * .85 + "px"; - } - } - - function cmpCoords(a, b) { return a.top - b.top || a.left - b.left } - - // Draws the given range as a highlighted selection - function drawSelectionRange(cm, range, output) { - var display = cm.display, doc = cm.doc; - var fragment = document.createDocumentFragment(); - var padding = paddingH(cm.display), leftSide = padding.left; - var rightSide = Math.max(display.sizerWidth, displayWidth(cm) - display.sizer.offsetLeft) - padding.right; - var docLTR = doc.direction == "ltr"; - - function add(left, top, width, bottom) { - if (top < 0) { top = 0; } - top = Math.round(top); - bottom = Math.round(bottom); - fragment.appendChild(elt("div", null, "CodeMirror-selected", ("position: absolute; left: " + left + "px;\n top: " + top + "px; width: " + (width == null ? rightSide - left : width) + "px;\n height: " + (bottom - top) + "px"))); - } - - function drawForLine(line, fromArg, toArg) { - var lineObj = getLine(doc, line); - var lineLen = lineObj.text.length; - var start, end; - function coords(ch, bias) { - return charCoords(cm, Pos(line, ch), "div", lineObj, bias) - } - - function wrapX(pos, dir, side) { - var extent = wrappedLineExtentChar(cm, lineObj, null, pos); - var prop = (dir == "ltr") == (side == "after") ? "left" : "right"; - var ch = side == "after" ? extent.begin : extent.end - (/\s/.test(lineObj.text.charAt(extent.end - 1)) ? 2 : 1); - return coords(ch, prop)[prop] - } - - var order = getOrder(lineObj, doc.direction); - iterateBidiSections(order, fromArg || 0, toArg == null ? lineLen : toArg, function (from, to, dir, i) { - var ltr = dir == "ltr"; - var fromPos = coords(from, ltr ? "left" : "right"); - var toPos = coords(to - 1, ltr ? "right" : "left"); - - var openStart = fromArg == null && from == 0, openEnd = toArg == null && to == lineLen; - var first = i == 0, last = !order || i == order.length - 1; - if (toPos.top - fromPos.top <= 3) { // Single line - var openLeft = (docLTR ? openStart : openEnd) && first; - var openRight = (docLTR ? openEnd : openStart) && last; - var left = openLeft ? leftSide : (ltr ? fromPos : toPos).left; - var right = openRight ? rightSide : (ltr ? toPos : fromPos).right; - add(left, fromPos.top, right - left, fromPos.bottom); - } else { // Multiple lines - var topLeft, topRight, botLeft, botRight; - if (ltr) { - topLeft = docLTR && openStart && first ? leftSide : fromPos.left; - topRight = docLTR ? rightSide : wrapX(from, dir, "before"); - botLeft = docLTR ? leftSide : wrapX(to, dir, "after"); - botRight = docLTR && openEnd && last ? rightSide : toPos.right; - } else { - topLeft = !docLTR ? leftSide : wrapX(from, dir, "before"); - topRight = !docLTR && openStart && first ? rightSide : fromPos.right; - botLeft = !docLTR && openEnd && last ? leftSide : toPos.left; - botRight = !docLTR ? rightSide : wrapX(to, dir, "after"); - } - add(topLeft, fromPos.top, topRight - topLeft, fromPos.bottom); - if (fromPos.bottom < toPos.top) { add(leftSide, fromPos.bottom, null, toPos.top); } - add(botLeft, toPos.top, botRight - botLeft, toPos.bottom); - } - - if (!start || cmpCoords(fromPos, start) < 0) { start = fromPos; } - if (cmpCoords(toPos, start) < 0) { start = toPos; } - if (!end || cmpCoords(fromPos, end) < 0) { end = fromPos; } - if (cmpCoords(toPos, end) < 0) { end = toPos; } - }); - return {start: start, end: end} - } - - var sFrom = range.from(), sTo = range.to(); - if (sFrom.line == sTo.line) { - drawForLine(sFrom.line, sFrom.ch, sTo.ch); - } else { - var fromLine = getLine(doc, sFrom.line), toLine = getLine(doc, sTo.line); - var singleVLine = visualLine(fromLine) == visualLine(toLine); - var leftEnd = drawForLine(sFrom.line, sFrom.ch, singleVLine ? fromLine.text.length + 1 : null).end; - var rightStart = drawForLine(sTo.line, singleVLine ? 0 : null, sTo.ch).start; - if (singleVLine) { - if (leftEnd.top < rightStart.top - 2) { - add(leftEnd.right, leftEnd.top, null, leftEnd.bottom); - add(leftSide, rightStart.top, rightStart.left, rightStart.bottom); - } else { - add(leftEnd.right, leftEnd.top, rightStart.left - leftEnd.right, leftEnd.bottom); - } - } - if (leftEnd.bottom < rightStart.top) - { add(leftSide, leftEnd.bottom, null, rightStart.top); } - } - - output.appendChild(fragment); - } - - // Cursor-blinking - function restartBlink(cm) { - if (!cm.state.focused) { return } - var display = cm.display; - clearInterval(display.blinker); - var on = true; - display.cursorDiv.style.visibility = ""; - if (cm.options.cursorBlinkRate > 0) - { display.blinker = setInterval(function () { - if (!cm.hasFocus()) { onBlur(cm); } - display.cursorDiv.style.visibility = (on = !on) ? "" : "hidden"; - }, cm.options.cursorBlinkRate); } - else if (cm.options.cursorBlinkRate < 0) - { display.cursorDiv.style.visibility = "hidden"; } - } - - function ensureFocus(cm) { - if (!cm.hasFocus()) { - cm.display.input.focus(); - if (!cm.state.focused) { onFocus(cm); } - } - } - - function delayBlurEvent(cm) { - cm.state.delayingBlurEvent = true; - setTimeout(function () { if (cm.state.delayingBlurEvent) { - cm.state.delayingBlurEvent = false; - if (cm.state.focused) { onBlur(cm); } - } }, 100); - } - - function onFocus(cm, e) { - if (cm.state.delayingBlurEvent && !cm.state.draggingText) { cm.state.delayingBlurEvent = false; } - - if (cm.options.readOnly == "nocursor") { return } - if (!cm.state.focused) { - signal(cm, "focus", cm, e); - cm.state.focused = true; - addClass(cm.display.wrapper, "CodeMirror-focused"); - // This test prevents this from firing when a context - // menu is closed (since the input reset would kill the - // select-all detection hack) - if (!cm.curOp && cm.display.selForContextMenu != cm.doc.sel) { - cm.display.input.reset(); - if (webkit) { setTimeout(function () { return cm.display.input.reset(true); }, 20); } // Issue #1730 - } - cm.display.input.receivedFocus(); - } - restartBlink(cm); - } - function onBlur(cm, e) { - if (cm.state.delayingBlurEvent) { return } - - if (cm.state.focused) { - signal(cm, "blur", cm, e); - cm.state.focused = false; - rmClass(cm.display.wrapper, "CodeMirror-focused"); - } - clearInterval(cm.display.blinker); - setTimeout(function () { if (!cm.state.focused) { cm.display.shift = false; } }, 150); - } - - // Read the actual heights of the rendered lines, and update their - // stored heights to match. - function updateHeightsInViewport(cm) { - var display = cm.display; - var prevBottom = display.lineDiv.offsetTop; - var viewTop = Math.max(0, display.scroller.getBoundingClientRect().top); - var oldHeight = display.lineDiv.getBoundingClientRect().top; - var mustScroll = 0; - for (var i = 0; i < display.view.length; i++) { - var cur = display.view[i], wrapping = cm.options.lineWrapping; - var height = (void 0), width = 0; - if (cur.hidden) { continue } - oldHeight += cur.line.height; - if (ie && ie_version < 8) { - var bot = cur.node.offsetTop + cur.node.offsetHeight; - height = bot - prevBottom; - prevBottom = bot; - } else { - var box = cur.node.getBoundingClientRect(); - height = box.bottom - box.top; - // Check that lines don't extend past the right of the current - // editor width - if (!wrapping && cur.text.firstChild) - { width = cur.text.firstChild.getBoundingClientRect().right - box.left - 1; } - } - var diff = cur.line.height - height; - if (diff > .005 || diff < -.005) { - if (oldHeight < viewTop) { mustScroll -= diff; } - updateLineHeight(cur.line, height); - updateWidgetHeight(cur.line); - if (cur.rest) { for (var j = 0; j < cur.rest.length; j++) - { updateWidgetHeight(cur.rest[j]); } } - } - if (width > cm.display.sizerWidth) { - var chWidth = Math.ceil(width / charWidth(cm.display)); - if (chWidth > cm.display.maxLineLength) { - cm.display.maxLineLength = chWidth; - cm.display.maxLine = cur.line; - cm.display.maxLineChanged = true; - } - } - } - if (Math.abs(mustScroll) > 2) { display.scroller.scrollTop += mustScroll; } - } - - // Read and store the height of line widgets associated with the - // given line. - function updateWidgetHeight(line) { - if (line.widgets) { for (var i = 0; i < line.widgets.length; ++i) { - var w = line.widgets[i], parent = w.node.parentNode; - if (parent) { w.height = parent.offsetHeight; } - } } - } - - // Compute the lines that are visible in a given viewport (defaults - // the the current scroll position). viewport may contain top, - // height, and ensure (see op.scrollToPos) properties. - function visibleLines(display, doc, viewport) { - var top = viewport && viewport.top != null ? Math.max(0, viewport.top) : display.scroller.scrollTop; - top = Math.floor(top - paddingTop(display)); - var bottom = viewport && viewport.bottom != null ? viewport.bottom : top + display.wrapper.clientHeight; - - var from = lineAtHeight(doc, top), to = lineAtHeight(doc, bottom); - // Ensure is a {from: {line, ch}, to: {line, ch}} object, and - // forces those lines into the viewport (if possible). - if (viewport && viewport.ensure) { - var ensureFrom = viewport.ensure.from.line, ensureTo = viewport.ensure.to.line; - if (ensureFrom < from) { - from = ensureFrom; - to = lineAtHeight(doc, heightAtLine(getLine(doc, ensureFrom)) + display.wrapper.clientHeight); - } else if (Math.min(ensureTo, doc.lastLine()) >= to) { - from = lineAtHeight(doc, heightAtLine(getLine(doc, ensureTo)) - display.wrapper.clientHeight); - to = ensureTo; - } - } - return {from: from, to: Math.max(to, from + 1)} - } - - // SCROLLING THINGS INTO VIEW - - // If an editor sits on the top or bottom of the window, partially - // scrolled out of view, this ensures that the cursor is visible. - function maybeScrollWindow(cm, rect) { - if (signalDOMEvent(cm, "scrollCursorIntoView")) { return } - - var display = cm.display, box = display.sizer.getBoundingClientRect(), doScroll = null; - if (rect.top + box.top < 0) { doScroll = true; } - else if (rect.bottom + box.top > (window.innerHeight || document.documentElement.clientHeight)) { doScroll = false; } - if (doScroll != null && !phantom) { - var scrollNode = elt("div", "\u200b", null, ("position: absolute;\n top: " + (rect.top - display.viewOffset - paddingTop(cm.display)) + "px;\n height: " + (rect.bottom - rect.top + scrollGap(cm) + display.barHeight) + "px;\n left: " + (rect.left) + "px; width: " + (Math.max(2, rect.right - rect.left)) + "px;")); - cm.display.lineSpace.appendChild(scrollNode); - scrollNode.scrollIntoView(doScroll); - cm.display.lineSpace.removeChild(scrollNode); - } - } - - // Scroll a given position into view (immediately), verifying that - // it actually became visible (as line heights are accurately - // measured, the position of something may 'drift' during drawing). - function scrollPosIntoView(cm, pos, end, margin) { - if (margin == null) { margin = 0; } - var rect; - if (!cm.options.lineWrapping && pos == end) { - // Set pos and end to the cursor positions around the character pos sticks to - // If pos.sticky == "before", that is around pos.ch - 1, otherwise around pos.ch - // If pos == Pos(_, 0, "before"), pos and end are unchanged - end = pos.sticky == "before" ? Pos(pos.line, pos.ch + 1, "before") : pos; - pos = pos.ch ? Pos(pos.line, pos.sticky == "before" ? pos.ch - 1 : pos.ch, "after") : pos; - } - for (var limit = 0; limit < 5; limit++) { - var changed = false; - var coords = cursorCoords(cm, pos); - var endCoords = !end || end == pos ? coords : cursorCoords(cm, end); - rect = {left: Math.min(coords.left, endCoords.left), - top: Math.min(coords.top, endCoords.top) - margin, - right: Math.max(coords.left, endCoords.left), - bottom: Math.max(coords.bottom, endCoords.bottom) + margin}; - var scrollPos = calculateScrollPos(cm, rect); - var startTop = cm.doc.scrollTop, startLeft = cm.doc.scrollLeft; - if (scrollPos.scrollTop != null) { - updateScrollTop(cm, scrollPos.scrollTop); - if (Math.abs(cm.doc.scrollTop - startTop) > 1) { changed = true; } - } - if (scrollPos.scrollLeft != null) { - setScrollLeft(cm, scrollPos.scrollLeft); - if (Math.abs(cm.doc.scrollLeft - startLeft) > 1) { changed = true; } - } - if (!changed) { break } - } - return rect - } - - // Scroll a given set of coordinates into view (immediately). - function scrollIntoView(cm, rect) { - var scrollPos = calculateScrollPos(cm, rect); - if (scrollPos.scrollTop != null) { updateScrollTop(cm, scrollPos.scrollTop); } - if (scrollPos.scrollLeft != null) { setScrollLeft(cm, scrollPos.scrollLeft); } - } - - // Calculate a new scroll position needed to scroll the given - // rectangle into view. Returns an object with scrollTop and - // scrollLeft properties. When these are undefined, the - // vertical/horizontal position does not need to be adjusted. - function calculateScrollPos(cm, rect) { - var display = cm.display, snapMargin = textHeight(cm.display); - if (rect.top < 0) { rect.top = 0; } - var screentop = cm.curOp && cm.curOp.scrollTop != null ? cm.curOp.scrollTop : display.scroller.scrollTop; - var screen = displayHeight(cm), result = {}; - if (rect.bottom - rect.top > screen) { rect.bottom = rect.top + screen; } - var docBottom = cm.doc.height + paddingVert(display); - var atTop = rect.top < snapMargin, atBottom = rect.bottom > docBottom - snapMargin; - if (rect.top < screentop) { - result.scrollTop = atTop ? 0 : rect.top; - } else if (rect.bottom > screentop + screen) { - var newTop = Math.min(rect.top, (atBottom ? docBottom : rect.bottom) - screen); - if (newTop != screentop) { result.scrollTop = newTop; } - } - - var gutterSpace = cm.options.fixedGutter ? 0 : display.gutters.offsetWidth; - var screenleft = cm.curOp && cm.curOp.scrollLeft != null ? cm.curOp.scrollLeft : display.scroller.scrollLeft - gutterSpace; - var screenw = displayWidth(cm) - display.gutters.offsetWidth; - var tooWide = rect.right - rect.left > screenw; - if (tooWide) { rect.right = rect.left + screenw; } - if (rect.left < 10) - { result.scrollLeft = 0; } - else if (rect.left < screenleft) - { result.scrollLeft = Math.max(0, rect.left + gutterSpace - (tooWide ? 0 : 10)); } - else if (rect.right > screenw + screenleft - 3) - { result.scrollLeft = rect.right + (tooWide ? 0 : 10) - screenw; } - return result - } - - // Store a relative adjustment to the scroll position in the current - // operation (to be applied when the operation finishes). - function addToScrollTop(cm, top) { - if (top == null) { return } - resolveScrollToPos(cm); - cm.curOp.scrollTop = (cm.curOp.scrollTop == null ? cm.doc.scrollTop : cm.curOp.scrollTop) + top; - } - - // Make sure that at the end of the operation the current cursor is - // shown. - function ensureCursorVisible(cm) { - resolveScrollToPos(cm); - var cur = cm.getCursor(); - cm.curOp.scrollToPos = {from: cur, to: cur, margin: cm.options.cursorScrollMargin}; - } - - function scrollToCoords(cm, x, y) { - if (x != null || y != null) { resolveScrollToPos(cm); } - if (x != null) { cm.curOp.scrollLeft = x; } - if (y != null) { cm.curOp.scrollTop = y; } - } - - function scrollToRange(cm, range) { - resolveScrollToPos(cm); - cm.curOp.scrollToPos = range; - } - - // When an operation has its scrollToPos property set, and another - // scroll action is applied before the end of the operation, this - // 'simulates' scrolling that position into view in a cheap way, so - // that the effect of intermediate scroll commands is not ignored. - function resolveScrollToPos(cm) { - var range = cm.curOp.scrollToPos; - if (range) { - cm.curOp.scrollToPos = null; - var from = estimateCoords(cm, range.from), to = estimateCoords(cm, range.to); - scrollToCoordsRange(cm, from, to, range.margin); - } - } - - function scrollToCoordsRange(cm, from, to, margin) { - var sPos = calculateScrollPos(cm, { - left: Math.min(from.left, to.left), - top: Math.min(from.top, to.top) - margin, - right: Math.max(from.right, to.right), - bottom: Math.max(from.bottom, to.bottom) + margin - }); - scrollToCoords(cm, sPos.scrollLeft, sPos.scrollTop); - } - - // Sync the scrollable area and scrollbars, ensure the viewport - // covers the visible area. - function updateScrollTop(cm, val) { - if (Math.abs(cm.doc.scrollTop - val) < 2) { return } - if (!gecko) { updateDisplaySimple(cm, {top: val}); } - setScrollTop(cm, val, true); - if (gecko) { updateDisplaySimple(cm); } - startWorker(cm, 100); - } - - function setScrollTop(cm, val, forceScroll) { - val = Math.max(0, Math.min(cm.display.scroller.scrollHeight - cm.display.scroller.clientHeight, val)); - if (cm.display.scroller.scrollTop == val && !forceScroll) { return } - cm.doc.scrollTop = val; - cm.display.scrollbars.setScrollTop(val); - if (cm.display.scroller.scrollTop != val) { cm.display.scroller.scrollTop = val; } - } - - // Sync scroller and scrollbar, ensure the gutter elements are - // aligned. - function setScrollLeft(cm, val, isScroller, forceScroll) { - val = Math.max(0, Math.min(val, cm.display.scroller.scrollWidth - cm.display.scroller.clientWidth)); - if ((isScroller ? val == cm.doc.scrollLeft : Math.abs(cm.doc.scrollLeft - val) < 2) && !forceScroll) { return } - cm.doc.scrollLeft = val; - alignHorizontally(cm); - if (cm.display.scroller.scrollLeft != val) { cm.display.scroller.scrollLeft = val; } - cm.display.scrollbars.setScrollLeft(val); - } - - // SCROLLBARS - - // Prepare DOM reads needed to update the scrollbars. Done in one - // shot to minimize update/measure roundtrips. - function measureForScrollbars(cm) { - var d = cm.display, gutterW = d.gutters.offsetWidth; - var docH = Math.round(cm.doc.height + paddingVert(cm.display)); - return { - clientHeight: d.scroller.clientHeight, - viewHeight: d.wrapper.clientHeight, - scrollWidth: d.scroller.scrollWidth, clientWidth: d.scroller.clientWidth, - viewWidth: d.wrapper.clientWidth, - barLeft: cm.options.fixedGutter ? gutterW : 0, - docHeight: docH, - scrollHeight: docH + scrollGap(cm) + d.barHeight, - nativeBarWidth: d.nativeBarWidth, - gutterWidth: gutterW - } - } - - var NativeScrollbars = function(place, scroll, cm) { - this.cm = cm; - var vert = this.vert = elt("div", [elt("div", null, null, "min-width: 1px")], "CodeMirror-vscrollbar"); - var horiz = this.horiz = elt("div", [elt("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar"); - vert.tabIndex = horiz.tabIndex = -1; - place(vert); place(horiz); - - on(vert, "scroll", function () { - if (vert.clientHeight) { scroll(vert.scrollTop, "vertical"); } - }); - on(horiz, "scroll", function () { - if (horiz.clientWidth) { scroll(horiz.scrollLeft, "horizontal"); } - }); - - this.checkedZeroWidth = false; - // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8). - if (ie && ie_version < 8) { this.horiz.style.minHeight = this.vert.style.minWidth = "18px"; } - }; - - NativeScrollbars.prototype.update = function (measure) { - var needsH = measure.scrollWidth > measure.clientWidth + 1; - var needsV = measure.scrollHeight > measure.clientHeight + 1; - var sWidth = measure.nativeBarWidth; - - if (needsV) { - this.vert.style.display = "block"; - this.vert.style.bottom = needsH ? sWidth + "px" : "0"; - var totalHeight = measure.viewHeight - (needsH ? sWidth : 0); - // A bug in IE8 can cause this value to be negative, so guard it. - this.vert.firstChild.style.height = - Math.max(0, measure.scrollHeight - measure.clientHeight + totalHeight) + "px"; - } else { - this.vert.scrollTop = 0; - this.vert.style.display = ""; - this.vert.firstChild.style.height = "0"; - } - - if (needsH) { - this.horiz.style.display = "block"; - this.horiz.style.right = needsV ? sWidth + "px" : "0"; - this.horiz.style.left = measure.barLeft + "px"; - var totalWidth = measure.viewWidth - measure.barLeft - (needsV ? sWidth : 0); - this.horiz.firstChild.style.width = - Math.max(0, measure.scrollWidth - measure.clientWidth + totalWidth) + "px"; - } else { - this.horiz.style.display = ""; - this.horiz.firstChild.style.width = "0"; - } - - if (!this.checkedZeroWidth && measure.clientHeight > 0) { - if (sWidth == 0) { this.zeroWidthHack(); } - this.checkedZeroWidth = true; - } - - return {right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0} - }; - - NativeScrollbars.prototype.setScrollLeft = function (pos) { - if (this.horiz.scrollLeft != pos) { this.horiz.scrollLeft = pos; } - if (this.disableHoriz) { this.enableZeroWidthBar(this.horiz, this.disableHoriz, "horiz"); } - }; - - NativeScrollbars.prototype.setScrollTop = function (pos) { - if (this.vert.scrollTop != pos) { this.vert.scrollTop = pos; } - if (this.disableVert) { this.enableZeroWidthBar(this.vert, this.disableVert, "vert"); } - }; - - NativeScrollbars.prototype.zeroWidthHack = function () { - var w = mac && !mac_geMountainLion ? "12px" : "18px"; - this.horiz.style.height = this.vert.style.width = w; - this.horiz.style.pointerEvents = this.vert.style.pointerEvents = "none"; - this.disableHoriz = new Delayed; - this.disableVert = new Delayed; - }; - - NativeScrollbars.prototype.enableZeroWidthBar = function (bar, delay, type) { - bar.style.pointerEvents = "auto"; - function maybeDisable() { - // To find out whether the scrollbar is still visible, we - // check whether the element under the pixel in the bottom - // right corner of the scrollbar box is the scrollbar box - // itself (when the bar is still visible) or its filler child - // (when the bar is hidden). If it is still visible, we keep - // it enabled, if it's hidden, we disable pointer events. - var box = bar.getBoundingClientRect(); - var elt = type == "vert" ? document.elementFromPoint(box.right - 1, (box.top + box.bottom) / 2) - : document.elementFromPoint((box.right + box.left) / 2, box.bottom - 1); - if (elt != bar) { bar.style.pointerEvents = "none"; } - else { delay.set(1000, maybeDisable); } - } - delay.set(1000, maybeDisable); - }; - - NativeScrollbars.prototype.clear = function () { - var parent = this.horiz.parentNode; - parent.removeChild(this.horiz); - parent.removeChild(this.vert); - }; - - var NullScrollbars = function () {}; - - NullScrollbars.prototype.update = function () { return {bottom: 0, right: 0} }; - NullScrollbars.prototype.setScrollLeft = function () {}; - NullScrollbars.prototype.setScrollTop = function () {}; - NullScrollbars.prototype.clear = function () {}; - - function updateScrollbars(cm, measure) { - if (!measure) { measure = measureForScrollbars(cm); } - var startWidth = cm.display.barWidth, startHeight = cm.display.barHeight; - updateScrollbarsInner(cm, measure); - for (var i = 0; i < 4 && startWidth != cm.display.barWidth || startHeight != cm.display.barHeight; i++) { - if (startWidth != cm.display.barWidth && cm.options.lineWrapping) - { updateHeightsInViewport(cm); } - updateScrollbarsInner(cm, measureForScrollbars(cm)); - startWidth = cm.display.barWidth; startHeight = cm.display.barHeight; - } - } - - // Re-synchronize the fake scrollbars with the actual size of the - // content. - function updateScrollbarsInner(cm, measure) { - var d = cm.display; - var sizes = d.scrollbars.update(measure); - - d.sizer.style.paddingRight = (d.barWidth = sizes.right) + "px"; - d.sizer.style.paddingBottom = (d.barHeight = sizes.bottom) + "px"; - d.heightForcer.style.borderBottom = sizes.bottom + "px solid transparent"; - - if (sizes.right && sizes.bottom) { - d.scrollbarFiller.style.display = "block"; - d.scrollbarFiller.style.height = sizes.bottom + "px"; - d.scrollbarFiller.style.width = sizes.right + "px"; - } else { d.scrollbarFiller.style.display = ""; } - if (sizes.bottom && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutter) { - d.gutterFiller.style.display = "block"; - d.gutterFiller.style.height = sizes.bottom + "px"; - d.gutterFiller.style.width = measure.gutterWidth + "px"; - } else { d.gutterFiller.style.display = ""; } - } - - var scrollbarModel = {"native": NativeScrollbars, "null": NullScrollbars}; - - function initScrollbars(cm) { - if (cm.display.scrollbars) { - cm.display.scrollbars.clear(); - if (cm.display.scrollbars.addClass) - { rmClass(cm.display.wrapper, cm.display.scrollbars.addClass); } - } - - cm.display.scrollbars = new scrollbarModel[cm.options.scrollbarStyle](function (node) { - cm.display.wrapper.insertBefore(node, cm.display.scrollbarFiller); - // Prevent clicks in the scrollbars from killing focus - on(node, "mousedown", function () { - if (cm.state.focused) { setTimeout(function () { return cm.display.input.focus(); }, 0); } - }); - node.setAttribute("cm-not-content", "true"); - }, function (pos, axis) { - if (axis == "horizontal") { setScrollLeft(cm, pos); } - else { updateScrollTop(cm, pos); } - }, cm); - if (cm.display.scrollbars.addClass) - { addClass(cm.display.wrapper, cm.display.scrollbars.addClass); } - } - - // Operations are used to wrap a series of changes to the editor - // state in such a way that each change won't have to update the - // cursor and display (which would be awkward, slow, and - // error-prone). Instead, display updates are batched and then all - // combined and executed at once. - - var nextOpId = 0; - // Start a new operation. - function startOperation(cm) { - cm.curOp = { - cm: cm, - viewChanged: false, // Flag that indicates that lines might need to be redrawn - startHeight: cm.doc.height, // Used to detect need to update scrollbar - forceUpdate: false, // Used to force a redraw - updateInput: 0, // Whether to reset the input textarea - typing: false, // Whether this reset should be careful to leave existing text (for compositing) - changeObjs: null, // Accumulated changes, for firing change events - cursorActivityHandlers: null, // Set of handlers to fire cursorActivity on - cursorActivityCalled: 0, // Tracks which cursorActivity handlers have been called already - selectionChanged: false, // Whether the selection needs to be redrawn - updateMaxLine: false, // Set when the widest line needs to be determined anew - scrollLeft: null, scrollTop: null, // Intermediate scroll position, not pushed to DOM yet - scrollToPos: null, // Used to scroll to a specific position - focus: false, - id: ++nextOpId, // Unique ID - markArrays: null // Used by addMarkedSpan - }; - pushOperation(cm.curOp); - } - - // Finish an operation, updating the display and signalling delayed events - function endOperation(cm) { - var op = cm.curOp; - if (op) { finishOperation(op, function (group) { - for (var i = 0; i < group.ops.length; i++) - { group.ops[i].cm.curOp = null; } - endOperations(group); - }); } - } - - // The DOM updates done when an operation finishes are batched so - // that the minimum number of relayouts are required. - function endOperations(group) { - var ops = group.ops; - for (var i = 0; i < ops.length; i++) // Read DOM - { endOperation_R1(ops[i]); } - for (var i$1 = 0; i$1 < ops.length; i$1++) // Write DOM (maybe) - { endOperation_W1(ops[i$1]); } - for (var i$2 = 0; i$2 < ops.length; i$2++) // Read DOM - { endOperation_R2(ops[i$2]); } - for (var i$3 = 0; i$3 < ops.length; i$3++) // Write DOM (maybe) - { endOperation_W2(ops[i$3]); } - for (var i$4 = 0; i$4 < ops.length; i$4++) // Read DOM - { endOperation_finish(ops[i$4]); } - } - - function endOperation_R1(op) { - var cm = op.cm, display = cm.display; - maybeClipScrollbars(cm); - if (op.updateMaxLine) { findMaxLine(cm); } - - op.mustUpdate = op.viewChanged || op.forceUpdate || op.scrollTop != null || - op.scrollToPos && (op.scrollToPos.from.line < display.viewFrom || - op.scrollToPos.to.line >= display.viewTo) || - display.maxLineChanged && cm.options.lineWrapping; - op.update = op.mustUpdate && - new DisplayUpdate(cm, op.mustUpdate && {top: op.scrollTop, ensure: op.scrollToPos}, op.forceUpdate); - } - - function endOperation_W1(op) { - op.updatedDisplay = op.mustUpdate && updateDisplayIfNeeded(op.cm, op.update); - } - - function endOperation_R2(op) { - var cm = op.cm, display = cm.display; - if (op.updatedDisplay) { updateHeightsInViewport(cm); } - - op.barMeasure = measureForScrollbars(cm); - - // If the max line changed since it was last measured, measure it, - // and ensure the document's width matches it. - // updateDisplay_W2 will use these properties to do the actual resizing - if (display.maxLineChanged && !cm.options.lineWrapping) { - op.adjustWidthTo = measureChar(cm, display.maxLine, display.maxLine.text.length).left + 3; - cm.display.sizerWidth = op.adjustWidthTo; - op.barMeasure.scrollWidth = - Math.max(display.scroller.clientWidth, display.sizer.offsetLeft + op.adjustWidthTo + scrollGap(cm) + cm.display.barWidth); - op.maxScrollLeft = Math.max(0, display.sizer.offsetLeft + op.adjustWidthTo - displayWidth(cm)); - } - - if (op.updatedDisplay || op.selectionChanged) - { op.preparedSelection = display.input.prepareSelection(); } - } - - function endOperation_W2(op) { - var cm = op.cm; - - if (op.adjustWidthTo != null) { - cm.display.sizer.style.minWidth = op.adjustWidthTo + "px"; - if (op.maxScrollLeft < cm.doc.scrollLeft) - { setScrollLeft(cm, Math.min(cm.display.scroller.scrollLeft, op.maxScrollLeft), true); } - cm.display.maxLineChanged = false; - } - - var takeFocus = op.focus && op.focus == activeElt(); - if (op.preparedSelection) - { cm.display.input.showSelection(op.preparedSelection, takeFocus); } - if (op.updatedDisplay || op.startHeight != cm.doc.height) - { updateScrollbars(cm, op.barMeasure); } - if (op.updatedDisplay) - { setDocumentHeight(cm, op.barMeasure); } - - if (op.selectionChanged) { restartBlink(cm); } - - if (cm.state.focused && op.updateInput) - { cm.display.input.reset(op.typing); } - if (takeFocus) { ensureFocus(op.cm); } - } - - function endOperation_finish(op) { - var cm = op.cm, display = cm.display, doc = cm.doc; - - if (op.updatedDisplay) { postUpdateDisplay(cm, op.update); } - - // Abort mouse wheel delta measurement, when scrolling explicitly - if (display.wheelStartX != null && (op.scrollTop != null || op.scrollLeft != null || op.scrollToPos)) - { display.wheelStartX = display.wheelStartY = null; } - - // Propagate the scroll position to the actual DOM scroller - if (op.scrollTop != null) { setScrollTop(cm, op.scrollTop, op.forceScroll); } - - if (op.scrollLeft != null) { setScrollLeft(cm, op.scrollLeft, true, true); } - // If we need to scroll a specific position into view, do so. - if (op.scrollToPos) { - var rect = scrollPosIntoView(cm, clipPos(doc, op.scrollToPos.from), - clipPos(doc, op.scrollToPos.to), op.scrollToPos.margin); - maybeScrollWindow(cm, rect); - } - - // Fire events for markers that are hidden/unidden by editing or - // undoing - var hidden = op.maybeHiddenMarkers, unhidden = op.maybeUnhiddenMarkers; - if (hidden) { for (var i = 0; i < hidden.length; ++i) - { if (!hidden[i].lines.length) { signal(hidden[i], "hide"); } } } - if (unhidden) { for (var i$1 = 0; i$1 < unhidden.length; ++i$1) - { if (unhidden[i$1].lines.length) { signal(unhidden[i$1], "unhide"); } } } - - if (display.wrapper.offsetHeight) - { doc.scrollTop = cm.display.scroller.scrollTop; } - - // Fire change events, and delayed event handlers - if (op.changeObjs) - { signal(cm, "changes", cm, op.changeObjs); } - if (op.update) - { op.update.finish(); } - } - - // Run the given function in an operation - function runInOp(cm, f) { - if (cm.curOp) { return f() } - startOperation(cm); - try { return f() } - finally { endOperation(cm); } - } - // Wraps a function in an operation. Returns the wrapped function. - function operation(cm, f) { - return function() { - if (cm.curOp) { return f.apply(cm, arguments) } - startOperation(cm); - try { return f.apply(cm, arguments) } - finally { endOperation(cm); } - } - } - // Used to add methods to editor and doc instances, wrapping them in - // operations. - function methodOp(f) { - return function() { - if (this.curOp) { return f.apply(this, arguments) } - startOperation(this); - try { return f.apply(this, arguments) } - finally { endOperation(this); } - } - } - function docMethodOp(f) { - return function() { - var cm = this.cm; - if (!cm || cm.curOp) { return f.apply(this, arguments) } - startOperation(cm); - try { return f.apply(this, arguments) } - finally { endOperation(cm); } - } - } - - // HIGHLIGHT WORKER - - function startWorker(cm, time) { - if (cm.doc.highlightFrontier < cm.display.viewTo) - { cm.state.highlight.set(time, bind(highlightWorker, cm)); } - } - - function highlightWorker(cm) { - var doc = cm.doc; - if (doc.highlightFrontier >= cm.display.viewTo) { return } - var end = +new Date + cm.options.workTime; - var context = getContextBefore(cm, doc.highlightFrontier); - var changedLines = []; - - doc.iter(context.line, Math.min(doc.first + doc.size, cm.display.viewTo + 500), function (line) { - if (context.line >= cm.display.viewFrom) { // Visible - var oldStyles = line.styles; - var resetState = line.text.length > cm.options.maxHighlightLength ? copyState(doc.mode, context.state) : null; - var highlighted = highlightLine(cm, line, context, true); - if (resetState) { context.state = resetState; } - line.styles = highlighted.styles; - var oldCls = line.styleClasses, newCls = highlighted.classes; - if (newCls) { line.styleClasses = newCls; } - else if (oldCls) { line.styleClasses = null; } - var ischange = !oldStyles || oldStyles.length != line.styles.length || - oldCls != newCls && (!oldCls || !newCls || oldCls.bgClass != newCls.bgClass || oldCls.textClass != newCls.textClass); - for (var i = 0; !ischange && i < oldStyles.length; ++i) { ischange = oldStyles[i] != line.styles[i]; } - if (ischange) { changedLines.push(context.line); } - line.stateAfter = context.save(); - context.nextLine(); - } else { - if (line.text.length <= cm.options.maxHighlightLength) - { processLine(cm, line.text, context); } - line.stateAfter = context.line % 5 == 0 ? context.save() : null; - context.nextLine(); - } - if (+new Date > end) { - startWorker(cm, cm.options.workDelay); - return true - } - }); - doc.highlightFrontier = context.line; - doc.modeFrontier = Math.max(doc.modeFrontier, context.line); - if (changedLines.length) { runInOp(cm, function () { - for (var i = 0; i < changedLines.length; i++) - { regLineChange(cm, changedLines[i], "text"); } - }); } - } - - // DISPLAY DRAWING - - var DisplayUpdate = function(cm, viewport, force) { - var display = cm.display; - - this.viewport = viewport; - // Store some values that we'll need later (but don't want to force a relayout for) - this.visible = visibleLines(display, cm.doc, viewport); - this.editorIsHidden = !display.wrapper.offsetWidth; - this.wrapperHeight = display.wrapper.clientHeight; - this.wrapperWidth = display.wrapper.clientWidth; - this.oldDisplayWidth = displayWidth(cm); - this.force = force; - this.dims = getDimensions(cm); - this.events = []; - }; - - DisplayUpdate.prototype.signal = function (emitter, type) { - if (hasHandler(emitter, type)) - { this.events.push(arguments); } - }; - DisplayUpdate.prototype.finish = function () { - for (var i = 0; i < this.events.length; i++) - { signal.apply(null, this.events[i]); } - }; - - function maybeClipScrollbars(cm) { - var display = cm.display; - if (!display.scrollbarsClipped && display.scroller.offsetWidth) { - display.nativeBarWidth = display.scroller.offsetWidth - display.scroller.clientWidth; - display.heightForcer.style.height = scrollGap(cm) + "px"; - display.sizer.style.marginBottom = -display.nativeBarWidth + "px"; - display.sizer.style.borderRightWidth = scrollGap(cm) + "px"; - display.scrollbarsClipped = true; - } - } - - function selectionSnapshot(cm) { - if (cm.hasFocus()) { return null } - var active = activeElt(); - if (!active || !contains(cm.display.lineDiv, active)) { return null } - var result = {activeElt: active}; - if (window.getSelection) { - var sel = window.getSelection(); - if (sel.anchorNode && sel.extend && contains(cm.display.lineDiv, sel.anchorNode)) { - result.anchorNode = sel.anchorNode; - result.anchorOffset = sel.anchorOffset; - result.focusNode = sel.focusNode; - result.focusOffset = sel.focusOffset; - } - } - return result - } - - function restoreSelection(snapshot) { - if (!snapshot || !snapshot.activeElt || snapshot.activeElt == activeElt()) { return } - snapshot.activeElt.focus(); - if (!/^(INPUT|TEXTAREA)$/.test(snapshot.activeElt.nodeName) && - snapshot.anchorNode && contains(document.body, snapshot.anchorNode) && contains(document.body, snapshot.focusNode)) { - var sel = window.getSelection(), range = document.createRange(); - range.setEnd(snapshot.anchorNode, snapshot.anchorOffset); - range.collapse(false); - sel.removeAllRanges(); - sel.addRange(range); - sel.extend(snapshot.focusNode, snapshot.focusOffset); - } - } - - // Does the actual updating of the line display. Bails out - // (returning false) when there is nothing to be done and forced is - // false. - function updateDisplayIfNeeded(cm, update) { - var display = cm.display, doc = cm.doc; - - if (update.editorIsHidden) { - resetView(cm); - return false - } - - // Bail out if the visible area is already rendered and nothing changed. - if (!update.force && - update.visible.from >= display.viewFrom && update.visible.to <= display.viewTo && - (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo) && - display.renderedView == display.view && countDirtyView(cm) == 0) - { return false } - - if (maybeUpdateLineNumberWidth(cm)) { - resetView(cm); - update.dims = getDimensions(cm); - } - - // Compute a suitable new viewport (from & to) - var end = doc.first + doc.size; - var from = Math.max(update.visible.from - cm.options.viewportMargin, doc.first); - var to = Math.min(end, update.visible.to + cm.options.viewportMargin); - if (display.viewFrom < from && from - display.viewFrom < 20) { from = Math.max(doc.first, display.viewFrom); } - if (display.viewTo > to && display.viewTo - to < 20) { to = Math.min(end, display.viewTo); } - if (sawCollapsedSpans) { - from = visualLineNo(cm.doc, from); - to = visualLineEndNo(cm.doc, to); - } - - var different = from != display.viewFrom || to != display.viewTo || - display.lastWrapHeight != update.wrapperHeight || display.lastWrapWidth != update.wrapperWidth; - adjustView(cm, from, to); - - display.viewOffset = heightAtLine(getLine(cm.doc, display.viewFrom)); - // Position the mover div to align with the current scroll position - cm.display.mover.style.top = display.viewOffset + "px"; - - var toUpdate = countDirtyView(cm); - if (!different && toUpdate == 0 && !update.force && display.renderedView == display.view && - (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo)) - { return false } - - // For big changes, we hide the enclosing element during the - // update, since that speeds up the operations on most browsers. - var selSnapshot = selectionSnapshot(cm); - if (toUpdate > 4) { display.lineDiv.style.display = "none"; } - patchDisplay(cm, display.updateLineNumbers, update.dims); - if (toUpdate > 4) { display.lineDiv.style.display = ""; } - display.renderedView = display.view; - // There might have been a widget with a focused element that got - // hidden or updated, if so re-focus it. - restoreSelection(selSnapshot); - - // Prevent selection and cursors from interfering with the scroll - // width and height. - removeChildren(display.cursorDiv); - removeChildren(display.selectionDiv); - display.gutters.style.height = display.sizer.style.minHeight = 0; - - if (different) { - display.lastWrapHeight = update.wrapperHeight; - display.lastWrapWidth = update.wrapperWidth; - startWorker(cm, 400); - } - - display.updateLineNumbers = null; - - return true - } - - function postUpdateDisplay(cm, update) { - var viewport = update.viewport; - - for (var first = true;; first = false) { - if (!first || !cm.options.lineWrapping || update.oldDisplayWidth == displayWidth(cm)) { - // Clip forced viewport to actual scrollable area. - if (viewport && viewport.top != null) - { viewport = {top: Math.min(cm.doc.height + paddingVert(cm.display) - displayHeight(cm), viewport.top)}; } - // Updated line heights might result in the drawn area not - // actually covering the viewport. Keep looping until it does. - update.visible = visibleLines(cm.display, cm.doc, viewport); - if (update.visible.from >= cm.display.viewFrom && update.visible.to <= cm.display.viewTo) - { break } - } else if (first) { - update.visible = visibleLines(cm.display, cm.doc, viewport); - } - if (!updateDisplayIfNeeded(cm, update)) { break } - updateHeightsInViewport(cm); - var barMeasure = measureForScrollbars(cm); - updateSelection(cm); - updateScrollbars(cm, barMeasure); - setDocumentHeight(cm, barMeasure); - update.force = false; - } - - update.signal(cm, "update", cm); - if (cm.display.viewFrom != cm.display.reportedViewFrom || cm.display.viewTo != cm.display.reportedViewTo) { - update.signal(cm, "viewportChange", cm, cm.display.viewFrom, cm.display.viewTo); - cm.display.reportedViewFrom = cm.display.viewFrom; cm.display.reportedViewTo = cm.display.viewTo; - } - } - - function updateDisplaySimple(cm, viewport) { - var update = new DisplayUpdate(cm, viewport); - if (updateDisplayIfNeeded(cm, update)) { - updateHeightsInViewport(cm); - postUpdateDisplay(cm, update); - var barMeasure = measureForScrollbars(cm); - updateSelection(cm); - updateScrollbars(cm, barMeasure); - setDocumentHeight(cm, barMeasure); - update.finish(); - } - } - - // Sync the actual display DOM structure with display.view, removing - // nodes for lines that are no longer in view, and creating the ones - // that are not there yet, and updating the ones that are out of - // date. - function patchDisplay(cm, updateNumbersFrom, dims) { - var display = cm.display, lineNumbers = cm.options.lineNumbers; - var container = display.lineDiv, cur = container.firstChild; - - function rm(node) { - var next = node.nextSibling; - // Works around a throw-scroll bug in OS X Webkit - if (webkit && mac && cm.display.currentWheelTarget == node) - { node.style.display = "none"; } - else - { node.parentNode.removeChild(node); } - return next - } - - var view = display.view, lineN = display.viewFrom; - // Loop over the elements in the view, syncing cur (the DOM nodes - // in display.lineDiv) with the view as we go. - for (var i = 0; i < view.length; i++) { - var lineView = view[i]; - if (lineView.hidden) ; else if (!lineView.node || lineView.node.parentNode != container) { // Not drawn yet - var node = buildLineElement(cm, lineView, lineN, dims); - container.insertBefore(node, cur); - } else { // Already drawn - while (cur != lineView.node) { cur = rm(cur); } - var updateNumber = lineNumbers && updateNumbersFrom != null && - updateNumbersFrom <= lineN && lineView.lineNumber; - if (lineView.changes) { - if (indexOf(lineView.changes, "gutter") > -1) { updateNumber = false; } - updateLineForChanges(cm, lineView, lineN, dims); - } - if (updateNumber) { - removeChildren(lineView.lineNumber); - lineView.lineNumber.appendChild(document.createTextNode(lineNumberFor(cm.options, lineN))); - } - cur = lineView.node.nextSibling; - } - lineN += lineView.size; - } - while (cur) { cur = rm(cur); } - } - - function updateGutterSpace(display) { - var width = display.gutters.offsetWidth; - display.sizer.style.marginLeft = width + "px"; - // Send an event to consumers responding to changes in gutter width. - signalLater(display, "gutterChanged", display); - } - - function setDocumentHeight(cm, measure) { - cm.display.sizer.style.minHeight = measure.docHeight + "px"; - cm.display.heightForcer.style.top = measure.docHeight + "px"; - cm.display.gutters.style.height = (measure.docHeight + cm.display.barHeight + scrollGap(cm)) + "px"; - } - - // Re-align line numbers and gutter marks to compensate for - // horizontal scrolling. - function alignHorizontally(cm) { - var display = cm.display, view = display.view; - if (!display.alignWidgets && (!display.gutters.firstChild || !cm.options.fixedGutter)) { return } - var comp = compensateForHScroll(display) - display.scroller.scrollLeft + cm.doc.scrollLeft; - var gutterW = display.gutters.offsetWidth, left = comp + "px"; - for (var i = 0; i < view.length; i++) { if (!view[i].hidden) { - if (cm.options.fixedGutter) { - if (view[i].gutter) - { view[i].gutter.style.left = left; } - if (view[i].gutterBackground) - { view[i].gutterBackground.style.left = left; } - } - var align = view[i].alignable; - if (align) { for (var j = 0; j < align.length; j++) - { align[j].style.left = left; } } - } } - if (cm.options.fixedGutter) - { display.gutters.style.left = (comp + gutterW) + "px"; } - } - - // Used to ensure that the line number gutter is still the right - // size for the current document size. Returns true when an update - // is needed. - function maybeUpdateLineNumberWidth(cm) { - if (!cm.options.lineNumbers) { return false } - var doc = cm.doc, last = lineNumberFor(cm.options, doc.first + doc.size - 1), display = cm.display; - if (last.length != display.lineNumChars) { - var test = display.measure.appendChild(elt("div", [elt("div", last)], - "CodeMirror-linenumber CodeMirror-gutter-elt")); - var innerW = test.firstChild.offsetWidth, padding = test.offsetWidth - innerW; - display.lineGutter.style.width = ""; - display.lineNumInnerWidth = Math.max(innerW, display.lineGutter.offsetWidth - padding) + 1; - display.lineNumWidth = display.lineNumInnerWidth + padding; - display.lineNumChars = display.lineNumInnerWidth ? last.length : -1; - display.lineGutter.style.width = display.lineNumWidth + "px"; - updateGutterSpace(cm.display); - return true - } - return false - } - - function getGutters(gutters, lineNumbers) { - var result = [], sawLineNumbers = false; - for (var i = 0; i < gutters.length; i++) { - var name = gutters[i], style = null; - if (typeof name != "string") { style = name.style; name = name.className; } - if (name == "CodeMirror-linenumbers") { - if (!lineNumbers) { continue } - else { sawLineNumbers = true; } - } - result.push({className: name, style: style}); - } - if (lineNumbers && !sawLineNumbers) { result.push({className: "CodeMirror-linenumbers", style: null}); } - return result - } - - // Rebuild the gutter elements, ensure the margin to the left of the - // code matches their width. - function renderGutters(display) { - var gutters = display.gutters, specs = display.gutterSpecs; - removeChildren(gutters); - display.lineGutter = null; - for (var i = 0; i < specs.length; ++i) { - var ref = specs[i]; - var className = ref.className; - var style = ref.style; - var gElt = gutters.appendChild(elt("div", null, "CodeMirror-gutter " + className)); - if (style) { gElt.style.cssText = style; } - if (className == "CodeMirror-linenumbers") { - display.lineGutter = gElt; - gElt.style.width = (display.lineNumWidth || 1) + "px"; - } - } - gutters.style.display = specs.length ? "" : "none"; - updateGutterSpace(display); - } - - function updateGutters(cm) { - renderGutters(cm.display); - regChange(cm); - alignHorizontally(cm); - } - - // The display handles the DOM integration, both for input reading - // and content drawing. It holds references to DOM nodes and - // display-related state. - - function Display(place, doc, input, options) { - var d = this; - this.input = input; - - // Covers bottom-right square when both scrollbars are present. - d.scrollbarFiller = elt("div", null, "CodeMirror-scrollbar-filler"); - d.scrollbarFiller.setAttribute("cm-not-content", "true"); - // Covers bottom of gutter when coverGutterNextToScrollbar is on - // and h scrollbar is present. - d.gutterFiller = elt("div", null, "CodeMirror-gutter-filler"); - d.gutterFiller.setAttribute("cm-not-content", "true"); - // Will contain the actual code, positioned to cover the viewport. - d.lineDiv = eltP("div", null, "CodeMirror-code"); - // Elements are added to these to represent selection and cursors. - d.selectionDiv = elt("div", null, null, "position: relative; z-index: 1"); - d.cursorDiv = elt("div", null, "CodeMirror-cursors"); - // A visibility: hidden element used to find the size of things. - d.measure = elt("div", null, "CodeMirror-measure"); - // When lines outside of the viewport are measured, they are drawn in this. - d.lineMeasure = elt("div", null, "CodeMirror-measure"); - // Wraps everything that needs to exist inside the vertically-padded coordinate system - d.lineSpace = eltP("div", [d.measure, d.lineMeasure, d.selectionDiv, d.cursorDiv, d.lineDiv], - null, "position: relative; outline: none"); - var lines = eltP("div", [d.lineSpace], "CodeMirror-lines"); - // Moved around its parent to cover visible view. - d.mover = elt("div", [lines], null, "position: relative"); - // Set to the height of the document, allowing scrolling. - d.sizer = elt("div", [d.mover], "CodeMirror-sizer"); - d.sizerWidth = null; - // Behavior of elts with overflow: auto and padding is - // inconsistent across browsers. This is used to ensure the - // scrollable area is big enough. - d.heightForcer = elt("div", null, null, "position: absolute; height: " + scrollerGap + "px; width: 1px;"); - // Will contain the gutters, if any. - d.gutters = elt("div", null, "CodeMirror-gutters"); - d.lineGutter = null; - // Actual scrollable element. - d.scroller = elt("div", [d.sizer, d.heightForcer, d.gutters], "CodeMirror-scroll"); - d.scroller.setAttribute("tabIndex", "-1"); - // The element in which the editor lives. - d.wrapper = elt("div", [d.scrollbarFiller, d.gutterFiller, d.scroller], "CodeMirror"); - - // This attribute is respected by automatic translation systems such as Google Translate, - // and may also be respected by tools used by human translators. - d.wrapper.setAttribute('translate', 'no'); - - // Work around IE7 z-index bug (not perfect, hence IE7 not really being supported) - if (ie && ie_version < 8) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0; } - if (!webkit && !(gecko && mobile)) { d.scroller.draggable = true; } - - if (place) { - if (place.appendChild) { place.appendChild(d.wrapper); } - else { place(d.wrapper); } - } - - // Current rendered range (may be bigger than the view window). - d.viewFrom = d.viewTo = doc.first; - d.reportedViewFrom = d.reportedViewTo = doc.first; - // Information about the rendered lines. - d.view = []; - d.renderedView = null; - // Holds info about a single rendered line when it was rendered - // for measurement, while not in view. - d.externalMeasured = null; - // Empty space (in pixels) above the view - d.viewOffset = 0; - d.lastWrapHeight = d.lastWrapWidth = 0; - d.updateLineNumbers = null; - - d.nativeBarWidth = d.barHeight = d.barWidth = 0; - d.scrollbarsClipped = false; - - // Used to only resize the line number gutter when necessary (when - // the amount of lines crosses a boundary that makes its width change) - d.lineNumWidth = d.lineNumInnerWidth = d.lineNumChars = null; - // Set to true when a non-horizontal-scrolling line widget is - // added. As an optimization, line widget aligning is skipped when - // this is false. - d.alignWidgets = false; - - d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null; - - // Tracks the maximum line length so that the horizontal scrollbar - // can be kept static when scrolling. - d.maxLine = null; - d.maxLineLength = 0; - d.maxLineChanged = false; - - // Used for measuring wheel scrolling granularity - d.wheelDX = d.wheelDY = d.wheelStartX = d.wheelStartY = null; - - // True when shift is held down. - d.shift = false; - - // Used to track whether anything happened since the context menu - // was opened. - d.selForContextMenu = null; - - d.activeTouch = null; - - d.gutterSpecs = getGutters(options.gutters, options.lineNumbers); - renderGutters(d); - - input.init(d); - } - - // Since the delta values reported on mouse wheel events are - // unstandardized between browsers and even browser versions, and - // generally horribly unpredictable, this code starts by measuring - // the scroll effect that the first few mouse wheel events have, - // and, from that, detects the way it can convert deltas to pixel - // offsets afterwards. - // - // The reason we want to know the amount a wheel event will scroll - // is that it gives us a chance to update the display before the - // actual scrolling happens, reducing flickering. - - var wheelSamples = 0, wheelPixelsPerUnit = null; - // Fill in a browser-detected starting value on browsers where we - // know one. These don't have to be accurate -- the result of them - // being wrong would just be a slight flicker on the first wheel - // scroll (if it is large enough). - if (ie) { wheelPixelsPerUnit = -.53; } - else if (gecko) { wheelPixelsPerUnit = 15; } - else if (chrome) { wheelPixelsPerUnit = -.7; } - else if (safari) { wheelPixelsPerUnit = -1/3; } - - function wheelEventDelta(e) { - var dx = e.wheelDeltaX, dy = e.wheelDeltaY; - if (dx == null && e.detail && e.axis == e.HORIZONTAL_AXIS) { dx = e.detail; } - if (dy == null && e.detail && e.axis == e.VERTICAL_AXIS) { dy = e.detail; } - else if (dy == null) { dy = e.wheelDelta; } - return {x: dx, y: dy} - } - function wheelEventPixels(e) { - var delta = wheelEventDelta(e); - delta.x *= wheelPixelsPerUnit; - delta.y *= wheelPixelsPerUnit; - return delta - } - - function onScrollWheel(cm, e) { - var delta = wheelEventDelta(e), dx = delta.x, dy = delta.y; - var pixelsPerUnit = wheelPixelsPerUnit; - if (e.deltaMode === 0) { - dx = e.deltaX; - dy = e.deltaY; - pixelsPerUnit = 1; - } - - var display = cm.display, scroll = display.scroller; - // Quit if there's nothing to scroll here - var canScrollX = scroll.scrollWidth > scroll.clientWidth; - var canScrollY = scroll.scrollHeight > scroll.clientHeight; - if (!(dx && canScrollX || dy && canScrollY)) { return } - - // Webkit browsers on OS X abort momentum scrolls when the target - // of the scroll event is removed from the scrollable element. - // This hack (see related code in patchDisplay) makes sure the - // element is kept around. - if (dy && mac && webkit) { - outer: for (var cur = e.target, view = display.view; cur != scroll; cur = cur.parentNode) { - for (var i = 0; i < view.length; i++) { - if (view[i].node == cur) { - cm.display.currentWheelTarget = cur; - break outer - } - } - } - } - - // On some browsers, horizontal scrolling will cause redraws to - // happen before the gutter has been realigned, causing it to - // wriggle around in a most unseemly way. When we have an - // estimated pixels/delta value, we just handle horizontal - // scrolling entirely here. It'll be slightly off from native, but - // better than glitching out. - if (dx && !gecko && !presto && pixelsPerUnit != null) { - if (dy && canScrollY) - { updateScrollTop(cm, Math.max(0, scroll.scrollTop + dy * pixelsPerUnit)); } - setScrollLeft(cm, Math.max(0, scroll.scrollLeft + dx * pixelsPerUnit)); - // Only prevent default scrolling if vertical scrolling is - // actually possible. Otherwise, it causes vertical scroll - // jitter on OSX trackpads when deltaX is small and deltaY - // is large (issue #3579) - if (!dy || (dy && canScrollY)) - { e_preventDefault(e); } - display.wheelStartX = null; // Abort measurement, if in progress - return - } - - // 'Project' the visible viewport to cover the area that is being - // scrolled into view (if we know enough to estimate it). - if (dy && pixelsPerUnit != null) { - var pixels = dy * pixelsPerUnit; - var top = cm.doc.scrollTop, bot = top + display.wrapper.clientHeight; - if (pixels < 0) { top = Math.max(0, top + pixels - 50); } - else { bot = Math.min(cm.doc.height, bot + pixels + 50); } - updateDisplaySimple(cm, {top: top, bottom: bot}); - } - - if (wheelSamples < 20 && e.deltaMode !== 0) { - if (display.wheelStartX == null) { - display.wheelStartX = scroll.scrollLeft; display.wheelStartY = scroll.scrollTop; - display.wheelDX = dx; display.wheelDY = dy; - setTimeout(function () { - if (display.wheelStartX == null) { return } - var movedX = scroll.scrollLeft - display.wheelStartX; - var movedY = scroll.scrollTop - display.wheelStartY; - var sample = (movedY && display.wheelDY && movedY / display.wheelDY) || - (movedX && display.wheelDX && movedX / display.wheelDX); - display.wheelStartX = display.wheelStartY = null; - if (!sample) { return } - wheelPixelsPerUnit = (wheelPixelsPerUnit * wheelSamples + sample) / (wheelSamples + 1); - ++wheelSamples; - }, 200); - } else { - display.wheelDX += dx; display.wheelDY += dy; - } - } - } - - // Selection objects are immutable. A new one is created every time - // the selection changes. A selection is one or more non-overlapping - // (and non-touching) ranges, sorted, and an integer that indicates - // which one is the primary selection (the one that's scrolled into - // view, that getCursor returns, etc). - var Selection = function(ranges, primIndex) { - this.ranges = ranges; - this.primIndex = primIndex; - }; - - Selection.prototype.primary = function () { return this.ranges[this.primIndex] }; - - Selection.prototype.equals = function (other) { - if (other == this) { return true } - if (other.primIndex != this.primIndex || other.ranges.length != this.ranges.length) { return false } - for (var i = 0; i < this.ranges.length; i++) { - var here = this.ranges[i], there = other.ranges[i]; - if (!equalCursorPos(here.anchor, there.anchor) || !equalCursorPos(here.head, there.head)) { return false } - } - return true - }; - - Selection.prototype.deepCopy = function () { - var out = []; - for (var i = 0; i < this.ranges.length; i++) - { out[i] = new Range(copyPos(this.ranges[i].anchor), copyPos(this.ranges[i].head)); } - return new Selection(out, this.primIndex) - }; - - Selection.prototype.somethingSelected = function () { - for (var i = 0; i < this.ranges.length; i++) - { if (!this.ranges[i].empty()) { return true } } - return false - }; - - Selection.prototype.contains = function (pos, end) { - if (!end) { end = pos; } - for (var i = 0; i < this.ranges.length; i++) { - var range = this.ranges[i]; - if (cmp(end, range.from()) >= 0 && cmp(pos, range.to()) <= 0) - { return i } - } - return -1 - }; - - var Range = function(anchor, head) { - this.anchor = anchor; this.head = head; - }; - - Range.prototype.from = function () { return minPos(this.anchor, this.head) }; - Range.prototype.to = function () { return maxPos(this.anchor, this.head) }; - Range.prototype.empty = function () { return this.head.line == this.anchor.line && this.head.ch == this.anchor.ch }; - - // Take an unsorted, potentially overlapping set of ranges, and - // build a selection out of it. 'Consumes' ranges array (modifying - // it). - function normalizeSelection(cm, ranges, primIndex) { - var mayTouch = cm && cm.options.selectionsMayTouch; - var prim = ranges[primIndex]; - ranges.sort(function (a, b) { return cmp(a.from(), b.from()); }); - primIndex = indexOf(ranges, prim); - for (var i = 1; i < ranges.length; i++) { - var cur = ranges[i], prev = ranges[i - 1]; - var diff = cmp(prev.to(), cur.from()); - if (mayTouch && !cur.empty() ? diff > 0 : diff >= 0) { - var from = minPos(prev.from(), cur.from()), to = maxPos(prev.to(), cur.to()); - var inv = prev.empty() ? cur.from() == cur.head : prev.from() == prev.head; - if (i <= primIndex) { --primIndex; } - ranges.splice(--i, 2, new Range(inv ? to : from, inv ? from : to)); - } - } - return new Selection(ranges, primIndex) - } - - function simpleSelection(anchor, head) { - return new Selection([new Range(anchor, head || anchor)], 0) - } - - // Compute the position of the end of a change (its 'to' property - // refers to the pre-change end). - function changeEnd(change) { - if (!change.text) { return change.to } - return Pos(change.from.line + change.text.length - 1, - lst(change.text).length + (change.text.length == 1 ? change.from.ch : 0)) - } - - // Adjust a position to refer to the post-change position of the - // same text, or the end of the change if the change covers it. - function adjustForChange(pos, change) { - if (cmp(pos, change.from) < 0) { return pos } - if (cmp(pos, change.to) <= 0) { return changeEnd(change) } - - var line = pos.line + change.text.length - (change.to.line - change.from.line) - 1, ch = pos.ch; - if (pos.line == change.to.line) { ch += changeEnd(change).ch - change.to.ch; } - return Pos(line, ch) - } - - function computeSelAfterChange(doc, change) { - var out = []; - for (var i = 0; i < doc.sel.ranges.length; i++) { - var range = doc.sel.ranges[i]; - out.push(new Range(adjustForChange(range.anchor, change), - adjustForChange(range.head, change))); - } - return normalizeSelection(doc.cm, out, doc.sel.primIndex) - } - - function offsetPos(pos, old, nw) { - if (pos.line == old.line) - { return Pos(nw.line, pos.ch - old.ch + nw.ch) } - else - { return Pos(nw.line + (pos.line - old.line), pos.ch) } - } - - // Used by replaceSelections to allow moving the selection to the - // start or around the replaced test. Hint may be "start" or "around". - function computeReplacedSel(doc, changes, hint) { - var out = []; - var oldPrev = Pos(doc.first, 0), newPrev = oldPrev; - for (var i = 0; i < changes.length; i++) { - var change = changes[i]; - var from = offsetPos(change.from, oldPrev, newPrev); - var to = offsetPos(changeEnd(change), oldPrev, newPrev); - oldPrev = change.to; - newPrev = to; - if (hint == "around") { - var range = doc.sel.ranges[i], inv = cmp(range.head, range.anchor) < 0; - out[i] = new Range(inv ? to : from, inv ? from : to); - } else { - out[i] = new Range(from, from); - } - } - return new Selection(out, doc.sel.primIndex) - } - - // Used to get the editor into a consistent state again when options change. - - function loadMode(cm) { - cm.doc.mode = getMode(cm.options, cm.doc.modeOption); - resetModeState(cm); - } - - function resetModeState(cm) { - cm.doc.iter(function (line) { - if (line.stateAfter) { line.stateAfter = null; } - if (line.styles) { line.styles = null; } - }); - cm.doc.modeFrontier = cm.doc.highlightFrontier = cm.doc.first; - startWorker(cm, 100); - cm.state.modeGen++; - if (cm.curOp) { regChange(cm); } - } - - // DOCUMENT DATA STRUCTURE - - // By default, updates that start and end at the beginning of a line - // are treated specially, in order to make the association of line - // widgets and marker elements with the text behave more intuitive. - function isWholeLineUpdate(doc, change) { - return change.from.ch == 0 && change.to.ch == 0 && lst(change.text) == "" && - (!doc.cm || doc.cm.options.wholeLineUpdateBefore) - } - - // Perform a change on the document data structure. - function updateDoc(doc, change, markedSpans, estimateHeight) { - function spansFor(n) {return markedSpans ? markedSpans[n] : null} - function update(line, text, spans) { - updateLine(line, text, spans, estimateHeight); - signalLater(line, "change", line, change); - } - function linesFor(start, end) { - var result = []; - for (var i = start; i < end; ++i) - { result.push(new Line(text[i], spansFor(i), estimateHeight)); } - return result - } - - var from = change.from, to = change.to, text = change.text; - var firstLine = getLine(doc, from.line), lastLine = getLine(doc, to.line); - var lastText = lst(text), lastSpans = spansFor(text.length - 1), nlines = to.line - from.line; - - // Adjust the line structure - if (change.full) { - doc.insert(0, linesFor(0, text.length)); - doc.remove(text.length, doc.size - text.length); - } else if (isWholeLineUpdate(doc, change)) { - // This is a whole-line replace. Treated specially to make - // sure line objects move the way they are supposed to. - var added = linesFor(0, text.length - 1); - update(lastLine, lastLine.text, lastSpans); - if (nlines) { doc.remove(from.line, nlines); } - if (added.length) { doc.insert(from.line, added); } - } else if (firstLine == lastLine) { - if (text.length == 1) { - update(firstLine, firstLine.text.slice(0, from.ch) + lastText + firstLine.text.slice(to.ch), lastSpans); - } else { - var added$1 = linesFor(1, text.length - 1); - added$1.push(new Line(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight)); - update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0)); - doc.insert(from.line + 1, added$1); - } - } else if (text.length == 1) { - update(firstLine, firstLine.text.slice(0, from.ch) + text[0] + lastLine.text.slice(to.ch), spansFor(0)); - doc.remove(from.line + 1, nlines); - } else { - update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0)); - update(lastLine, lastText + lastLine.text.slice(to.ch), lastSpans); - var added$2 = linesFor(1, text.length - 1); - if (nlines > 1) { doc.remove(from.line + 1, nlines - 1); } - doc.insert(from.line + 1, added$2); - } - - signalLater(doc, "change", doc, change); - } - - // Call f for all linked documents. - function linkedDocs(doc, f, sharedHistOnly) { - function propagate(doc, skip, sharedHist) { - if (doc.linked) { for (var i = 0; i < doc.linked.length; ++i) { - var rel = doc.linked[i]; - if (rel.doc == skip) { continue } - var shared = sharedHist && rel.sharedHist; - if (sharedHistOnly && !shared) { continue } - f(rel.doc, shared); - propagate(rel.doc, doc, shared); - } } - } - propagate(doc, null, true); - } - - // Attach a document to an editor. - function attachDoc(cm, doc) { - if (doc.cm) { throw new Error("This document is already in use.") } - cm.doc = doc; - doc.cm = cm; - estimateLineHeights(cm); - loadMode(cm); - setDirectionClass(cm); - cm.options.direction = doc.direction; - if (!cm.options.lineWrapping) { findMaxLine(cm); } - cm.options.mode = doc.modeOption; - regChange(cm); - } - - function setDirectionClass(cm) { - (cm.doc.direction == "rtl" ? addClass : rmClass)(cm.display.lineDiv, "CodeMirror-rtl"); - } - - function directionChanged(cm) { - runInOp(cm, function () { - setDirectionClass(cm); - regChange(cm); - }); - } - - function History(prev) { - // Arrays of change events and selections. Doing something adds an - // event to done and clears undo. Undoing moves events from done - // to undone, redoing moves them in the other direction. - this.done = []; this.undone = []; - this.undoDepth = prev ? prev.undoDepth : Infinity; - // Used to track when changes can be merged into a single undo - // event - this.lastModTime = this.lastSelTime = 0; - this.lastOp = this.lastSelOp = null; - this.lastOrigin = this.lastSelOrigin = null; - // Used by the isClean() method - this.generation = this.maxGeneration = prev ? prev.maxGeneration : 1; - } - - // Create a history change event from an updateDoc-style change - // object. - function historyChangeFromChange(doc, change) { - var histChange = {from: copyPos(change.from), to: changeEnd(change), text: getBetween(doc, change.from, change.to)}; - attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1); - linkedDocs(doc, function (doc) { return attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1); }, true); - return histChange - } - - // Pop all selection events off the end of a history array. Stop at - // a change event. - function clearSelectionEvents(array) { - while (array.length) { - var last = lst(array); - if (last.ranges) { array.pop(); } - else { break } - } - } - - // Find the top change event in the history. Pop off selection - // events that are in the way. - function lastChangeEvent(hist, force) { - if (force) { - clearSelectionEvents(hist.done); - return lst(hist.done) - } else if (hist.done.length && !lst(hist.done).ranges) { - return lst(hist.done) - } else if (hist.done.length > 1 && !hist.done[hist.done.length - 2].ranges) { - hist.done.pop(); - return lst(hist.done) - } - } - - // Register a change in the history. Merges changes that are within - // a single operation, or are close together with an origin that - // allows merging (starting with "+") into a single event. - function addChangeToHistory(doc, change, selAfter, opId) { - var hist = doc.history; - hist.undone.length = 0; - var time = +new Date, cur; - var last; - - if ((hist.lastOp == opId || - hist.lastOrigin == change.origin && change.origin && - ((change.origin.charAt(0) == "+" && hist.lastModTime > time - (doc.cm ? doc.cm.options.historyEventDelay : 500)) || - change.origin.charAt(0) == "*")) && - (cur = lastChangeEvent(hist, hist.lastOp == opId))) { - // Merge this change into the last event - last = lst(cur.changes); - if (cmp(change.from, change.to) == 0 && cmp(change.from, last.to) == 0) { - // Optimized case for simple insertion -- don't want to add - // new changesets for every character typed - last.to = changeEnd(change); - } else { - // Add new sub-event - cur.changes.push(historyChangeFromChange(doc, change)); - } - } else { - // Can not be merged, start a new event. - var before = lst(hist.done); - if (!before || !before.ranges) - { pushSelectionToHistory(doc.sel, hist.done); } - cur = {changes: [historyChangeFromChange(doc, change)], - generation: hist.generation}; - hist.done.push(cur); - while (hist.done.length > hist.undoDepth) { - hist.done.shift(); - if (!hist.done[0].ranges) { hist.done.shift(); } - } - } - hist.done.push(selAfter); - hist.generation = ++hist.maxGeneration; - hist.lastModTime = hist.lastSelTime = time; - hist.lastOp = hist.lastSelOp = opId; - hist.lastOrigin = hist.lastSelOrigin = change.origin; - - if (!last) { signal(doc, "historyAdded"); } - } - - function selectionEventCanBeMerged(doc, origin, prev, sel) { - var ch = origin.charAt(0); - return ch == "*" || - ch == "+" && - prev.ranges.length == sel.ranges.length && - prev.somethingSelected() == sel.somethingSelected() && - new Date - doc.history.lastSelTime <= (doc.cm ? doc.cm.options.historyEventDelay : 500) - } - - // Called whenever the selection changes, sets the new selection as - // the pending selection in the history, and pushes the old pending - // selection into the 'done' array when it was significantly - // different (in number of selected ranges, emptiness, or time). - function addSelectionToHistory(doc, sel, opId, options) { - var hist = doc.history, origin = options && options.origin; - - // A new event is started when the previous origin does not match - // the current, or the origins don't allow matching. Origins - // starting with * are always merged, those starting with + are - // merged when similar and close together in time. - if (opId == hist.lastSelOp || - (origin && hist.lastSelOrigin == origin && - (hist.lastModTime == hist.lastSelTime && hist.lastOrigin == origin || - selectionEventCanBeMerged(doc, origin, lst(hist.done), sel)))) - { hist.done[hist.done.length - 1] = sel; } - else - { pushSelectionToHistory(sel, hist.done); } - - hist.lastSelTime = +new Date; - hist.lastSelOrigin = origin; - hist.lastSelOp = opId; - if (options && options.clearRedo !== false) - { clearSelectionEvents(hist.undone); } - } - - function pushSelectionToHistory(sel, dest) { - var top = lst(dest); - if (!(top && top.ranges && top.equals(sel))) - { dest.push(sel); } - } - - // Used to store marked span information in the history. - function attachLocalSpans(doc, change, from, to) { - var existing = change["spans_" + doc.id], n = 0; - doc.iter(Math.max(doc.first, from), Math.min(doc.first + doc.size, to), function (line) { - if (line.markedSpans) - { (existing || (existing = change["spans_" + doc.id] = {}))[n] = line.markedSpans; } - ++n; - }); - } - - // When un/re-doing restores text containing marked spans, those - // that have been explicitly cleared should not be restored. - function removeClearedSpans(spans) { - if (!spans) { return null } - var out; - for (var i = 0; i < spans.length; ++i) { - if (spans[i].marker.explicitlyCleared) { if (!out) { out = spans.slice(0, i); } } - else if (out) { out.push(spans[i]); } - } - return !out ? spans : out.length ? out : null - } - - // Retrieve and filter the old marked spans stored in a change event. - function getOldSpans(doc, change) { - var found = change["spans_" + doc.id]; - if (!found) { return null } - var nw = []; - for (var i = 0; i < change.text.length; ++i) - { nw.push(removeClearedSpans(found[i])); } - return nw - } - - // Used for un/re-doing changes from the history. Combines the - // result of computing the existing spans with the set of spans that - // existed in the history (so that deleting around a span and then - // undoing brings back the span). - function mergeOldSpans(doc, change) { - var old = getOldSpans(doc, change); - var stretched = stretchSpansOverChange(doc, change); - if (!old) { return stretched } - if (!stretched) { return old } - - for (var i = 0; i < old.length; ++i) { - var oldCur = old[i], stretchCur = stretched[i]; - if (oldCur && stretchCur) { - spans: for (var j = 0; j < stretchCur.length; ++j) { - var span = stretchCur[j]; - for (var k = 0; k < oldCur.length; ++k) - { if (oldCur[k].marker == span.marker) { continue spans } } - oldCur.push(span); - } - } else if (stretchCur) { - old[i] = stretchCur; - } - } - return old - } - - // Used both to provide a JSON-safe object in .getHistory, and, when - // detaching a document, to split the history in two - function copyHistoryArray(events, newGroup, instantiateSel) { - var copy = []; - for (var i = 0; i < events.length; ++i) { - var event = events[i]; - if (event.ranges) { - copy.push(instantiateSel ? Selection.prototype.deepCopy.call(event) : event); - continue - } - var changes = event.changes, newChanges = []; - copy.push({changes: newChanges}); - for (var j = 0; j < changes.length; ++j) { - var change = changes[j], m = (void 0); - newChanges.push({from: change.from, to: change.to, text: change.text}); - if (newGroup) { for (var prop in change) { if (m = prop.match(/^spans_(\d+)$/)) { - if (indexOf(newGroup, Number(m[1])) > -1) { - lst(newChanges)[prop] = change[prop]; - delete change[prop]; - } - } } } - } - } - return copy - } - - // The 'scroll' parameter given to many of these indicated whether - // the new cursor position should be scrolled into view after - // modifying the selection. - - // If shift is held or the extend flag is set, extends a range to - // include a given position (and optionally a second position). - // Otherwise, simply returns the range between the given positions. - // Used for cursor motion and such. - function extendRange(range, head, other, extend) { - if (extend) { - var anchor = range.anchor; - if (other) { - var posBefore = cmp(head, anchor) < 0; - if (posBefore != (cmp(other, anchor) < 0)) { - anchor = head; - head = other; - } else if (posBefore != (cmp(head, other) < 0)) { - head = other; - } - } - return new Range(anchor, head) - } else { - return new Range(other || head, head) - } - } - - // Extend the primary selection range, discard the rest. - function extendSelection(doc, head, other, options, extend) { - if (extend == null) { extend = doc.cm && (doc.cm.display.shift || doc.extend); } - setSelection(doc, new Selection([extendRange(doc.sel.primary(), head, other, extend)], 0), options); - } - - // Extend all selections (pos is an array of selections with length - // equal the number of selections) - function extendSelections(doc, heads, options) { - var out = []; - var extend = doc.cm && (doc.cm.display.shift || doc.extend); - for (var i = 0; i < doc.sel.ranges.length; i++) - { out[i] = extendRange(doc.sel.ranges[i], heads[i], null, extend); } - var newSel = normalizeSelection(doc.cm, out, doc.sel.primIndex); - setSelection(doc, newSel, options); - } - - // Updates a single range in the selection. - function replaceOneSelection(doc, i, range, options) { - var ranges = doc.sel.ranges.slice(0); - ranges[i] = range; - setSelection(doc, normalizeSelection(doc.cm, ranges, doc.sel.primIndex), options); - } - - // Reset the selection to a single range. - function setSimpleSelection(doc, anchor, head, options) { - setSelection(doc, simpleSelection(anchor, head), options); - } - - // Give beforeSelectionChange handlers a change to influence a - // selection update. - function filterSelectionChange(doc, sel, options) { - var obj = { - ranges: sel.ranges, - update: function(ranges) { - this.ranges = []; - for (var i = 0; i < ranges.length; i++) - { this.ranges[i] = new Range(clipPos(doc, ranges[i].anchor), - clipPos(doc, ranges[i].head)); } - }, - origin: options && options.origin - }; - signal(doc, "beforeSelectionChange", doc, obj); - if (doc.cm) { signal(doc.cm, "beforeSelectionChange", doc.cm, obj); } - if (obj.ranges != sel.ranges) { return normalizeSelection(doc.cm, obj.ranges, obj.ranges.length - 1) } - else { return sel } - } - - function setSelectionReplaceHistory(doc, sel, options) { - var done = doc.history.done, last = lst(done); - if (last && last.ranges) { - done[done.length - 1] = sel; - setSelectionNoUndo(doc, sel, options); - } else { - setSelection(doc, sel, options); - } - } - - // Set a new selection. - function setSelection(doc, sel, options) { - setSelectionNoUndo(doc, sel, options); - addSelectionToHistory(doc, doc.sel, doc.cm ? doc.cm.curOp.id : NaN, options); - } - - function setSelectionNoUndo(doc, sel, options) { - if (hasHandler(doc, "beforeSelectionChange") || doc.cm && hasHandler(doc.cm, "beforeSelectionChange")) - { sel = filterSelectionChange(doc, sel, options); } - - var bias = options && options.bias || - (cmp(sel.primary().head, doc.sel.primary().head) < 0 ? -1 : 1); - setSelectionInner(doc, skipAtomicInSelection(doc, sel, bias, true)); - - if (!(options && options.scroll === false) && doc.cm && doc.cm.getOption("readOnly") != "nocursor") - { ensureCursorVisible(doc.cm); } - } - - function setSelectionInner(doc, sel) { - if (sel.equals(doc.sel)) { return } - - doc.sel = sel; - - if (doc.cm) { - doc.cm.curOp.updateInput = 1; - doc.cm.curOp.selectionChanged = true; - signalCursorActivity(doc.cm); - } - signalLater(doc, "cursorActivity", doc); - } - - // Verify that the selection does not partially select any atomic - // marked ranges. - function reCheckSelection(doc) { - setSelectionInner(doc, skipAtomicInSelection(doc, doc.sel, null, false)); - } - - // Return a selection that does not partially select any atomic - // ranges. - function skipAtomicInSelection(doc, sel, bias, mayClear) { - var out; - for (var i = 0; i < sel.ranges.length; i++) { - var range = sel.ranges[i]; - var old = sel.ranges.length == doc.sel.ranges.length && doc.sel.ranges[i]; - var newAnchor = skipAtomic(doc, range.anchor, old && old.anchor, bias, mayClear); - var newHead = skipAtomic(doc, range.head, old && old.head, bias, mayClear); - if (out || newAnchor != range.anchor || newHead != range.head) { - if (!out) { out = sel.ranges.slice(0, i); } - out[i] = new Range(newAnchor, newHead); - } - } - return out ? normalizeSelection(doc.cm, out, sel.primIndex) : sel - } - - function skipAtomicInner(doc, pos, oldPos, dir, mayClear) { - var line = getLine(doc, pos.line); - if (line.markedSpans) { for (var i = 0; i < line.markedSpans.length; ++i) { - var sp = line.markedSpans[i], m = sp.marker; - - // Determine if we should prevent the cursor being placed to the left/right of an atomic marker - // Historically this was determined using the inclusiveLeft/Right option, but the new way to control it - // is with selectLeft/Right - var preventCursorLeft = ("selectLeft" in m) ? !m.selectLeft : m.inclusiveLeft; - var preventCursorRight = ("selectRight" in m) ? !m.selectRight : m.inclusiveRight; - - if ((sp.from == null || (preventCursorLeft ? sp.from <= pos.ch : sp.from < pos.ch)) && - (sp.to == null || (preventCursorRight ? sp.to >= pos.ch : sp.to > pos.ch))) { - if (mayClear) { - signal(m, "beforeCursorEnter"); - if (m.explicitlyCleared) { - if (!line.markedSpans) { break } - else {--i; continue} - } - } - if (!m.atomic) { continue } - - if (oldPos) { - var near = m.find(dir < 0 ? 1 : -1), diff = (void 0); - if (dir < 0 ? preventCursorRight : preventCursorLeft) - { near = movePos(doc, near, -dir, near && near.line == pos.line ? line : null); } - if (near && near.line == pos.line && (diff = cmp(near, oldPos)) && (dir < 0 ? diff < 0 : diff > 0)) - { return skipAtomicInner(doc, near, pos, dir, mayClear) } - } - - var far = m.find(dir < 0 ? -1 : 1); - if (dir < 0 ? preventCursorLeft : preventCursorRight) - { far = movePos(doc, far, dir, far.line == pos.line ? line : null); } - return far ? skipAtomicInner(doc, far, pos, dir, mayClear) : null - } - } } - return pos - } - - // Ensure a given position is not inside an atomic range. - function skipAtomic(doc, pos, oldPos, bias, mayClear) { - var dir = bias || 1; - var found = skipAtomicInner(doc, pos, oldPos, dir, mayClear) || - (!mayClear && skipAtomicInner(doc, pos, oldPos, dir, true)) || - skipAtomicInner(doc, pos, oldPos, -dir, mayClear) || - (!mayClear && skipAtomicInner(doc, pos, oldPos, -dir, true)); - if (!found) { - doc.cantEdit = true; - return Pos(doc.first, 0) - } - return found - } - - function movePos(doc, pos, dir, line) { - if (dir < 0 && pos.ch == 0) { - if (pos.line > doc.first) { return clipPos(doc, Pos(pos.line - 1)) } - else { return null } - } else if (dir > 0 && pos.ch == (line || getLine(doc, pos.line)).text.length) { - if (pos.line < doc.first + doc.size - 1) { return Pos(pos.line + 1, 0) } - else { return null } - } else { - return new Pos(pos.line, pos.ch + dir) - } - } - - function selectAll(cm) { - cm.setSelection(Pos(cm.firstLine(), 0), Pos(cm.lastLine()), sel_dontScroll); - } - - // UPDATING - - // Allow "beforeChange" event handlers to influence a change - function filterChange(doc, change, update) { - var obj = { - canceled: false, - from: change.from, - to: change.to, - text: change.text, - origin: change.origin, - cancel: function () { return obj.canceled = true; } - }; - if (update) { obj.update = function (from, to, text, origin) { - if (from) { obj.from = clipPos(doc, from); } - if (to) { obj.to = clipPos(doc, to); } - if (text) { obj.text = text; } - if (origin !== undefined) { obj.origin = origin; } - }; } - signal(doc, "beforeChange", doc, obj); - if (doc.cm) { signal(doc.cm, "beforeChange", doc.cm, obj); } - - if (obj.canceled) { - if (doc.cm) { doc.cm.curOp.updateInput = 2; } - return null - } - return {from: obj.from, to: obj.to, text: obj.text, origin: obj.origin} - } - - // Apply a change to a document, and add it to the document's - // history, and propagating it to all linked documents. - function makeChange(doc, change, ignoreReadOnly) { - if (doc.cm) { - if (!doc.cm.curOp) { return operation(doc.cm, makeChange)(doc, change, ignoreReadOnly) } - if (doc.cm.state.suppressEdits) { return } - } - - if (hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange")) { - change = filterChange(doc, change, true); - if (!change) { return } - } - - // Possibly split or suppress the update based on the presence - // of read-only spans in its range. - var split = sawReadOnlySpans && !ignoreReadOnly && removeReadOnlyRanges(doc, change.from, change.to); - if (split) { - for (var i = split.length - 1; i >= 0; --i) - { makeChangeInner(doc, {from: split[i].from, to: split[i].to, text: i ? [""] : change.text, origin: change.origin}); } - } else { - makeChangeInner(doc, change); - } - } - - function makeChangeInner(doc, change) { - if (change.text.length == 1 && change.text[0] == "" && cmp(change.from, change.to) == 0) { return } - var selAfter = computeSelAfterChange(doc, change); - addChangeToHistory(doc, change, selAfter, doc.cm ? doc.cm.curOp.id : NaN); - - makeChangeSingleDoc(doc, change, selAfter, stretchSpansOverChange(doc, change)); - var rebased = []; - - linkedDocs(doc, function (doc, sharedHist) { - if (!sharedHist && indexOf(rebased, doc.history) == -1) { - rebaseHist(doc.history, change); - rebased.push(doc.history); - } - makeChangeSingleDoc(doc, change, null, stretchSpansOverChange(doc, change)); - }); - } - - // Revert a change stored in a document's history. - function makeChangeFromHistory(doc, type, allowSelectionOnly) { - var suppress = doc.cm && doc.cm.state.suppressEdits; - if (suppress && !allowSelectionOnly) { return } - - var hist = doc.history, event, selAfter = doc.sel; - var source = type == "undo" ? hist.done : hist.undone, dest = type == "undo" ? hist.undone : hist.done; - - // Verify that there is a useable event (so that ctrl-z won't - // needlessly clear selection events) - var i = 0; - for (; i < source.length; i++) { - event = source[i]; - if (allowSelectionOnly ? event.ranges && !event.equals(doc.sel) : !event.ranges) - { break } - } - if (i == source.length) { return } - hist.lastOrigin = hist.lastSelOrigin = null; - - for (;;) { - event = source.pop(); - if (event.ranges) { - pushSelectionToHistory(event, dest); - if (allowSelectionOnly && !event.equals(doc.sel)) { - setSelection(doc, event, {clearRedo: false}); - return - } - selAfter = event; - } else if (suppress) { - source.push(event); - return - } else { break } - } - - // Build up a reverse change object to add to the opposite history - // stack (redo when undoing, and vice versa). - var antiChanges = []; - pushSelectionToHistory(selAfter, dest); - dest.push({changes: antiChanges, generation: hist.generation}); - hist.generation = event.generation || ++hist.maxGeneration; - - var filter = hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange"); - - var loop = function ( i ) { - var change = event.changes[i]; - change.origin = type; - if (filter && !filterChange(doc, change, false)) { - source.length = 0; - return {} - } - - antiChanges.push(historyChangeFromChange(doc, change)); - - var after = i ? computeSelAfterChange(doc, change) : lst(source); - makeChangeSingleDoc(doc, change, after, mergeOldSpans(doc, change)); - if (!i && doc.cm) { doc.cm.scrollIntoView({from: change.from, to: changeEnd(change)}); } - var rebased = []; - - // Propagate to the linked documents - linkedDocs(doc, function (doc, sharedHist) { - if (!sharedHist && indexOf(rebased, doc.history) == -1) { - rebaseHist(doc.history, change); - rebased.push(doc.history); - } - makeChangeSingleDoc(doc, change, null, mergeOldSpans(doc, change)); - }); - }; - - for (var i$1 = event.changes.length - 1; i$1 >= 0; --i$1) { - var returned = loop( i$1 ); - - if ( returned ) return returned.v; - } - } - - // Sub-views need their line numbers shifted when text is added - // above or below them in the parent document. - function shiftDoc(doc, distance) { - if (distance == 0) { return } - doc.first += distance; - doc.sel = new Selection(map(doc.sel.ranges, function (range) { return new Range( - Pos(range.anchor.line + distance, range.anchor.ch), - Pos(range.head.line + distance, range.head.ch) - ); }), doc.sel.primIndex); - if (doc.cm) { - regChange(doc.cm, doc.first, doc.first - distance, distance); - for (var d = doc.cm.display, l = d.viewFrom; l < d.viewTo; l++) - { regLineChange(doc.cm, l, "gutter"); } - } - } - - // More lower-level change function, handling only a single document - // (not linked ones). - function makeChangeSingleDoc(doc, change, selAfter, spans) { - if (doc.cm && !doc.cm.curOp) - { return operation(doc.cm, makeChangeSingleDoc)(doc, change, selAfter, spans) } - - if (change.to.line < doc.first) { - shiftDoc(doc, change.text.length - 1 - (change.to.line - change.from.line)); - return - } - if (change.from.line > doc.lastLine()) { return } - - // Clip the change to the size of this doc - if (change.from.line < doc.first) { - var shift = change.text.length - 1 - (doc.first - change.from.line); - shiftDoc(doc, shift); - change = {from: Pos(doc.first, 0), to: Pos(change.to.line + shift, change.to.ch), - text: [lst(change.text)], origin: change.origin}; - } - var last = doc.lastLine(); - if (change.to.line > last) { - change = {from: change.from, to: Pos(last, getLine(doc, last).text.length), - text: [change.text[0]], origin: change.origin}; - } - - change.removed = getBetween(doc, change.from, change.to); - - if (!selAfter) { selAfter = computeSelAfterChange(doc, change); } - if (doc.cm) { makeChangeSingleDocInEditor(doc.cm, change, spans); } - else { updateDoc(doc, change, spans); } - setSelectionNoUndo(doc, selAfter, sel_dontScroll); - - if (doc.cantEdit && skipAtomic(doc, Pos(doc.firstLine(), 0))) - { doc.cantEdit = false; } - } - - // Handle the interaction of a change to a document with the editor - // that this document is part of. - function makeChangeSingleDocInEditor(cm, change, spans) { - var doc = cm.doc, display = cm.display, from = change.from, to = change.to; - - var recomputeMaxLength = false, checkWidthStart = from.line; - if (!cm.options.lineWrapping) { - checkWidthStart = lineNo(visualLine(getLine(doc, from.line))); - doc.iter(checkWidthStart, to.line + 1, function (line) { - if (line == display.maxLine) { - recomputeMaxLength = true; - return true - } - }); - } - - if (doc.sel.contains(change.from, change.to) > -1) - { signalCursorActivity(cm); } - - updateDoc(doc, change, spans, estimateHeight(cm)); - - if (!cm.options.lineWrapping) { - doc.iter(checkWidthStart, from.line + change.text.length, function (line) { - var len = lineLength(line); - if (len > display.maxLineLength) { - display.maxLine = line; - display.maxLineLength = len; - display.maxLineChanged = true; - recomputeMaxLength = false; - } - }); - if (recomputeMaxLength) { cm.curOp.updateMaxLine = true; } - } - - retreatFrontier(doc, from.line); - startWorker(cm, 400); - - var lendiff = change.text.length - (to.line - from.line) - 1; - // Remember that these lines changed, for updating the display - if (change.full) - { regChange(cm); } - else if (from.line == to.line && change.text.length == 1 && !isWholeLineUpdate(cm.doc, change)) - { regLineChange(cm, from.line, "text"); } - else - { regChange(cm, from.line, to.line + 1, lendiff); } - - var changesHandler = hasHandler(cm, "changes"), changeHandler = hasHandler(cm, "change"); - if (changeHandler || changesHandler) { - var obj = { - from: from, to: to, - text: change.text, - removed: change.removed, - origin: change.origin - }; - if (changeHandler) { signalLater(cm, "change", cm, obj); } - if (changesHandler) { (cm.curOp.changeObjs || (cm.curOp.changeObjs = [])).push(obj); } - } - cm.display.selForContextMenu = null; - } - - function replaceRange(doc, code, from, to, origin) { - var assign; - - if (!to) { to = from; } - if (cmp(to, from) < 0) { (assign = [to, from], from = assign[0], to = assign[1]); } - if (typeof code == "string") { code = doc.splitLines(code); } - makeChange(doc, {from: from, to: to, text: code, origin: origin}); - } - - // Rebasing/resetting history to deal with externally-sourced changes - - function rebaseHistSelSingle(pos, from, to, diff) { - if (to < pos.line) { - pos.line += diff; - } else if (from < pos.line) { - pos.line = from; - pos.ch = 0; - } - } - - // Tries to rebase an array of history events given a change in the - // document. If the change touches the same lines as the event, the - // event, and everything 'behind' it, is discarded. If the change is - // before the event, the event's positions are updated. Uses a - // copy-on-write scheme for the positions, to avoid having to - // reallocate them all on every rebase, but also avoid problems with - // shared position objects being unsafely updated. - function rebaseHistArray(array, from, to, diff) { - for (var i = 0; i < array.length; ++i) { - var sub = array[i], ok = true; - if (sub.ranges) { - if (!sub.copied) { sub = array[i] = sub.deepCopy(); sub.copied = true; } - for (var j = 0; j < sub.ranges.length; j++) { - rebaseHistSelSingle(sub.ranges[j].anchor, from, to, diff); - rebaseHistSelSingle(sub.ranges[j].head, from, to, diff); - } - continue - } - for (var j$1 = 0; j$1 < sub.changes.length; ++j$1) { - var cur = sub.changes[j$1]; - if (to < cur.from.line) { - cur.from = Pos(cur.from.line + diff, cur.from.ch); - cur.to = Pos(cur.to.line + diff, cur.to.ch); - } else if (from <= cur.to.line) { - ok = false; - break - } - } - if (!ok) { - array.splice(0, i + 1); - i = 0; - } - } - } - - function rebaseHist(hist, change) { - var from = change.from.line, to = change.to.line, diff = change.text.length - (to - from) - 1; - rebaseHistArray(hist.done, from, to, diff); - rebaseHistArray(hist.undone, from, to, diff); - } - - // Utility for applying a change to a line by handle or number, - // returning the number and optionally registering the line as - // changed. - function changeLine(doc, handle, changeType, op) { - var no = handle, line = handle; - if (typeof handle == "number") { line = getLine(doc, clipLine(doc, handle)); } - else { no = lineNo(handle); } - if (no == null) { return null } - if (op(line, no) && doc.cm) { regLineChange(doc.cm, no, changeType); } - return line - } - - // The document is represented as a BTree consisting of leaves, with - // chunk of lines in them, and branches, with up to ten leaves or - // other branch nodes below them. The top node is always a branch - // node, and is the document object itself (meaning it has - // additional methods and properties). - // - // All nodes have parent links. The tree is used both to go from - // line numbers to line objects, and to go from objects to numbers. - // It also indexes by height, and is used to convert between height - // and line object, and to find the total height of the document. - // - // See also http://marijnhaverbeke.nl/blog/codemirror-line-tree.html - - function LeafChunk(lines) { - this.lines = lines; - this.parent = null; - var height = 0; - for (var i = 0; i < lines.length; ++i) { - lines[i].parent = this; - height += lines[i].height; - } - this.height = height; - } - - LeafChunk.prototype = { - chunkSize: function() { return this.lines.length }, - - // Remove the n lines at offset 'at'. - removeInner: function(at, n) { - for (var i = at, e = at + n; i < e; ++i) { - var line = this.lines[i]; - this.height -= line.height; - cleanUpLine(line); - signalLater(line, "delete"); - } - this.lines.splice(at, n); - }, - - // Helper used to collapse a small branch into a single leaf. - collapse: function(lines) { - lines.push.apply(lines, this.lines); - }, - - // Insert the given array of lines at offset 'at', count them as - // having the given height. - insertInner: function(at, lines, height) { - this.height += height; - this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at)); - for (var i = 0; i < lines.length; ++i) { lines[i].parent = this; } - }, - - // Used to iterate over a part of the tree. - iterN: function(at, n, op) { - for (var e = at + n; at < e; ++at) - { if (op(this.lines[at])) { return true } } - } - }; - - function BranchChunk(children) { - this.children = children; - var size = 0, height = 0; - for (var i = 0; i < children.length; ++i) { - var ch = children[i]; - size += ch.chunkSize(); height += ch.height; - ch.parent = this; - } - this.size = size; - this.height = height; - this.parent = null; - } - - BranchChunk.prototype = { - chunkSize: function() { return this.size }, - - removeInner: function(at, n) { - this.size -= n; - for (var i = 0; i < this.children.length; ++i) { - var child = this.children[i], sz = child.chunkSize(); - if (at < sz) { - var rm = Math.min(n, sz - at), oldHeight = child.height; - child.removeInner(at, rm); - this.height -= oldHeight - child.height; - if (sz == rm) { this.children.splice(i--, 1); child.parent = null; } - if ((n -= rm) == 0) { break } - at = 0; - } else { at -= sz; } - } - // If the result is smaller than 25 lines, ensure that it is a - // single leaf node. - if (this.size - n < 25 && - (this.children.length > 1 || !(this.children[0] instanceof LeafChunk))) { - var lines = []; - this.collapse(lines); - this.children = [new LeafChunk(lines)]; - this.children[0].parent = this; - } - }, - - collapse: function(lines) { - for (var i = 0; i < this.children.length; ++i) { this.children[i].collapse(lines); } - }, - - insertInner: function(at, lines, height) { - this.size += lines.length; - this.height += height; - for (var i = 0; i < this.children.length; ++i) { - var child = this.children[i], sz = child.chunkSize(); - if (at <= sz) { - child.insertInner(at, lines, height); - if (child.lines && child.lines.length > 50) { - // To avoid memory thrashing when child.lines is huge (e.g. first view of a large file), it's never spliced. - // Instead, small slices are taken. They're taken in order because sequential memory accesses are fastest. - var remaining = child.lines.length % 25 + 25; - for (var pos = remaining; pos < child.lines.length;) { - var leaf = new LeafChunk(child.lines.slice(pos, pos += 25)); - child.height -= leaf.height; - this.children.splice(++i, 0, leaf); - leaf.parent = this; - } - child.lines = child.lines.slice(0, remaining); - this.maybeSpill(); - } - break - } - at -= sz; - } - }, - - // When a node has grown, check whether it should be split. - maybeSpill: function() { - if (this.children.length <= 10) { return } - var me = this; - do { - var spilled = me.children.splice(me.children.length - 5, 5); - var sibling = new BranchChunk(spilled); - if (!me.parent) { // Become the parent node - var copy = new BranchChunk(me.children); - copy.parent = me; - me.children = [copy, sibling]; - me = copy; - } else { - me.size -= sibling.size; - me.height -= sibling.height; - var myIndex = indexOf(me.parent.children, me); - me.parent.children.splice(myIndex + 1, 0, sibling); - } - sibling.parent = me.parent; - } while (me.children.length > 10) - me.parent.maybeSpill(); - }, - - iterN: function(at, n, op) { - for (var i = 0; i < this.children.length; ++i) { - var child = this.children[i], sz = child.chunkSize(); - if (at < sz) { - var used = Math.min(n, sz - at); - if (child.iterN(at, used, op)) { return true } - if ((n -= used) == 0) { break } - at = 0; - } else { at -= sz; } - } - } - }; - - // Line widgets are block elements displayed above or below a line. - - var LineWidget = function(doc, node, options) { - if (options) { for (var opt in options) { if (options.hasOwnProperty(opt)) - { this[opt] = options[opt]; } } } - this.doc = doc; - this.node = node; - }; - - LineWidget.prototype.clear = function () { - var cm = this.doc.cm, ws = this.line.widgets, line = this.line, no = lineNo(line); - if (no == null || !ws) { return } - for (var i = 0; i < ws.length; ++i) { if (ws[i] == this) { ws.splice(i--, 1); } } - if (!ws.length) { line.widgets = null; } - var height = widgetHeight(this); - updateLineHeight(line, Math.max(0, line.height - height)); - if (cm) { - runInOp(cm, function () { - adjustScrollWhenAboveVisible(cm, line, -height); - regLineChange(cm, no, "widget"); - }); - signalLater(cm, "lineWidgetCleared", cm, this, no); - } - }; - - LineWidget.prototype.changed = function () { - var this$1 = this; - - var oldH = this.height, cm = this.doc.cm, line = this.line; - this.height = null; - var diff = widgetHeight(this) - oldH; - if (!diff) { return } - if (!lineIsHidden(this.doc, line)) { updateLineHeight(line, line.height + diff); } - if (cm) { - runInOp(cm, function () { - cm.curOp.forceUpdate = true; - adjustScrollWhenAboveVisible(cm, line, diff); - signalLater(cm, "lineWidgetChanged", cm, this$1, lineNo(line)); - }); - } - }; - eventMixin(LineWidget); - - function adjustScrollWhenAboveVisible(cm, line, diff) { - if (heightAtLine(line) < ((cm.curOp && cm.curOp.scrollTop) || cm.doc.scrollTop)) - { addToScrollTop(cm, diff); } - } - - function addLineWidget(doc, handle, node, options) { - var widget = new LineWidget(doc, node, options); - var cm = doc.cm; - if (cm && widget.noHScroll) { cm.display.alignWidgets = true; } - changeLine(doc, handle, "widget", function (line) { - var widgets = line.widgets || (line.widgets = []); - if (widget.insertAt == null) { widgets.push(widget); } - else { widgets.splice(Math.min(widgets.length, Math.max(0, widget.insertAt)), 0, widget); } - widget.line = line; - if (cm && !lineIsHidden(doc, line)) { - var aboveVisible = heightAtLine(line) < doc.scrollTop; - updateLineHeight(line, line.height + widgetHeight(widget)); - if (aboveVisible) { addToScrollTop(cm, widget.height); } - cm.curOp.forceUpdate = true; - } - return true - }); - if (cm) { signalLater(cm, "lineWidgetAdded", cm, widget, typeof handle == "number" ? handle : lineNo(handle)); } - return widget - } - - // TEXTMARKERS - - // Created with markText and setBookmark methods. A TextMarker is a - // handle that can be used to clear or find a marked position in the - // document. Line objects hold arrays (markedSpans) containing - // {from, to, marker} object pointing to such marker objects, and - // indicating that such a marker is present on that line. Multiple - // lines may point to the same marker when it spans across lines. - // The spans will have null for their from/to properties when the - // marker continues beyond the start/end of the line. Markers have - // links back to the lines they currently touch. - - // Collapsed markers have unique ids, in order to be able to order - // them, which is needed for uniquely determining an outer marker - // when they overlap (they may nest, but not partially overlap). - var nextMarkerId = 0; - - var TextMarker = function(doc, type) { - this.lines = []; - this.type = type; - this.doc = doc; - this.id = ++nextMarkerId; - }; - - // Clear the marker. - TextMarker.prototype.clear = function () { - if (this.explicitlyCleared) { return } - var cm = this.doc.cm, withOp = cm && !cm.curOp; - if (withOp) { startOperation(cm); } - if (hasHandler(this, "clear")) { - var found = this.find(); - if (found) { signalLater(this, "clear", found.from, found.to); } - } - var min = null, max = null; - for (var i = 0; i < this.lines.length; ++i) { - var line = this.lines[i]; - var span = getMarkedSpanFor(line.markedSpans, this); - if (cm && !this.collapsed) { regLineChange(cm, lineNo(line), "text"); } - else if (cm) { - if (span.to != null) { max = lineNo(line); } - if (span.from != null) { min = lineNo(line); } - } - line.markedSpans = removeMarkedSpan(line.markedSpans, span); - if (span.from == null && this.collapsed && !lineIsHidden(this.doc, line) && cm) - { updateLineHeight(line, textHeight(cm.display)); } - } - if (cm && this.collapsed && !cm.options.lineWrapping) { for (var i$1 = 0; i$1 < this.lines.length; ++i$1) { - var visual = visualLine(this.lines[i$1]), len = lineLength(visual); - if (len > cm.display.maxLineLength) { - cm.display.maxLine = visual; - cm.display.maxLineLength = len; - cm.display.maxLineChanged = true; - } - } } - - if (min != null && cm && this.collapsed) { regChange(cm, min, max + 1); } - this.lines.length = 0; - this.explicitlyCleared = true; - if (this.atomic && this.doc.cantEdit) { - this.doc.cantEdit = false; - if (cm) { reCheckSelection(cm.doc); } - } - if (cm) { signalLater(cm, "markerCleared", cm, this, min, max); } - if (withOp) { endOperation(cm); } - if (this.parent) { this.parent.clear(); } - }; - - // Find the position of the marker in the document. Returns a {from, - // to} object by default. Side can be passed to get a specific side - // -- 0 (both), -1 (left), or 1 (right). When lineObj is true, the - // Pos objects returned contain a line object, rather than a line - // number (used to prevent looking up the same line twice). - TextMarker.prototype.find = function (side, lineObj) { - if (side == null && this.type == "bookmark") { side = 1; } - var from, to; - for (var i = 0; i < this.lines.length; ++i) { - var line = this.lines[i]; - var span = getMarkedSpanFor(line.markedSpans, this); - if (span.from != null) { - from = Pos(lineObj ? line : lineNo(line), span.from); - if (side == -1) { return from } - } - if (span.to != null) { - to = Pos(lineObj ? line : lineNo(line), span.to); - if (side == 1) { return to } - } - } - return from && {from: from, to: to} - }; - - // Signals that the marker's widget changed, and surrounding layout - // should be recomputed. - TextMarker.prototype.changed = function () { - var this$1 = this; - - var pos = this.find(-1, true), widget = this, cm = this.doc.cm; - if (!pos || !cm) { return } - runInOp(cm, function () { - var line = pos.line, lineN = lineNo(pos.line); - var view = findViewForLine(cm, lineN); - if (view) { - clearLineMeasurementCacheFor(view); - cm.curOp.selectionChanged = cm.curOp.forceUpdate = true; - } - cm.curOp.updateMaxLine = true; - if (!lineIsHidden(widget.doc, line) && widget.height != null) { - var oldHeight = widget.height; - widget.height = null; - var dHeight = widgetHeight(widget) - oldHeight; - if (dHeight) - { updateLineHeight(line, line.height + dHeight); } - } - signalLater(cm, "markerChanged", cm, this$1); - }); - }; - - TextMarker.prototype.attachLine = function (line) { - if (!this.lines.length && this.doc.cm) { - var op = this.doc.cm.curOp; - if (!op.maybeHiddenMarkers || indexOf(op.maybeHiddenMarkers, this) == -1) - { (op.maybeUnhiddenMarkers || (op.maybeUnhiddenMarkers = [])).push(this); } - } - this.lines.push(line); - }; - - TextMarker.prototype.detachLine = function (line) { - this.lines.splice(indexOf(this.lines, line), 1); - if (!this.lines.length && this.doc.cm) { - var op = this.doc.cm.curOp - ;(op.maybeHiddenMarkers || (op.maybeHiddenMarkers = [])).push(this); - } - }; - eventMixin(TextMarker); - - // Create a marker, wire it up to the right lines, and - function markText(doc, from, to, options, type) { - // Shared markers (across linked documents) are handled separately - // (markTextShared will call out to this again, once per - // document). - if (options && options.shared) { return markTextShared(doc, from, to, options, type) } - // Ensure we are in an operation. - if (doc.cm && !doc.cm.curOp) { return operation(doc.cm, markText)(doc, from, to, options, type) } - - var marker = new TextMarker(doc, type), diff = cmp(from, to); - if (options) { copyObj(options, marker, false); } - // Don't connect empty markers unless clearWhenEmpty is false - if (diff > 0 || diff == 0 && marker.clearWhenEmpty !== false) - { return marker } - if (marker.replacedWith) { - // Showing up as a widget implies collapsed (widget replaces text) - marker.collapsed = true; - marker.widgetNode = eltP("span", [marker.replacedWith], "CodeMirror-widget"); - if (!options.handleMouseEvents) { marker.widgetNode.setAttribute("cm-ignore-events", "true"); } - if (options.insertLeft) { marker.widgetNode.insertLeft = true; } - } - if (marker.collapsed) { - if (conflictingCollapsedRange(doc, from.line, from, to, marker) || - from.line != to.line && conflictingCollapsedRange(doc, to.line, from, to, marker)) - { throw new Error("Inserting collapsed marker partially overlapping an existing one") } - seeCollapsedSpans(); - } - - if (marker.addToHistory) - { addChangeToHistory(doc, {from: from, to: to, origin: "markText"}, doc.sel, NaN); } - - var curLine = from.line, cm = doc.cm, updateMaxLine; - doc.iter(curLine, to.line + 1, function (line) { - if (cm && marker.collapsed && !cm.options.lineWrapping && visualLine(line) == cm.display.maxLine) - { updateMaxLine = true; } - if (marker.collapsed && curLine != from.line) { updateLineHeight(line, 0); } - addMarkedSpan(line, new MarkedSpan(marker, - curLine == from.line ? from.ch : null, - curLine == to.line ? to.ch : null), doc.cm && doc.cm.curOp); - ++curLine; - }); - // lineIsHidden depends on the presence of the spans, so needs a second pass - if (marker.collapsed) { doc.iter(from.line, to.line + 1, function (line) { - if (lineIsHidden(doc, line)) { updateLineHeight(line, 0); } - }); } - - if (marker.clearOnEnter) { on(marker, "beforeCursorEnter", function () { return marker.clear(); }); } - - if (marker.readOnly) { - seeReadOnlySpans(); - if (doc.history.done.length || doc.history.undone.length) - { doc.clearHistory(); } - } - if (marker.collapsed) { - marker.id = ++nextMarkerId; - marker.atomic = true; - } - if (cm) { - // Sync editor state - if (updateMaxLine) { cm.curOp.updateMaxLine = true; } - if (marker.collapsed) - { regChange(cm, from.line, to.line + 1); } - else if (marker.className || marker.startStyle || marker.endStyle || marker.css || - marker.attributes || marker.title) - { for (var i = from.line; i <= to.line; i++) { regLineChange(cm, i, "text"); } } - if (marker.atomic) { reCheckSelection(cm.doc); } - signalLater(cm, "markerAdded", cm, marker); - } - return marker - } - - // SHARED TEXTMARKERS - - // A shared marker spans multiple linked documents. It is - // implemented as a meta-marker-object controlling multiple normal - // markers. - var SharedTextMarker = function(markers, primary) { - this.markers = markers; - this.primary = primary; - for (var i = 0; i < markers.length; ++i) - { markers[i].parent = this; } - }; - - SharedTextMarker.prototype.clear = function () { - if (this.explicitlyCleared) { return } - this.explicitlyCleared = true; - for (var i = 0; i < this.markers.length; ++i) - { this.markers[i].clear(); } - signalLater(this, "clear"); - }; - - SharedTextMarker.prototype.find = function (side, lineObj) { - return this.primary.find(side, lineObj) - }; - eventMixin(SharedTextMarker); - - function markTextShared(doc, from, to, options, type) { - options = copyObj(options); - options.shared = false; - var markers = [markText(doc, from, to, options, type)], primary = markers[0]; - var widget = options.widgetNode; - linkedDocs(doc, function (doc) { - if (widget) { options.widgetNode = widget.cloneNode(true); } - markers.push(markText(doc, clipPos(doc, from), clipPos(doc, to), options, type)); - for (var i = 0; i < doc.linked.length; ++i) - { if (doc.linked[i].isParent) { return } } - primary = lst(markers); - }); - return new SharedTextMarker(markers, primary) - } - - function findSharedMarkers(doc) { - return doc.findMarks(Pos(doc.first, 0), doc.clipPos(Pos(doc.lastLine())), function (m) { return m.parent; }) - } - - function copySharedMarkers(doc, markers) { - for (var i = 0; i < markers.length; i++) { - var marker = markers[i], pos = marker.find(); - var mFrom = doc.clipPos(pos.from), mTo = doc.clipPos(pos.to); - if (cmp(mFrom, mTo)) { - var subMark = markText(doc, mFrom, mTo, marker.primary, marker.primary.type); - marker.markers.push(subMark); - subMark.parent = marker; - } - } - } - - function detachSharedMarkers(markers) { - var loop = function ( i ) { - var marker = markers[i], linked = [marker.primary.doc]; - linkedDocs(marker.primary.doc, function (d) { return linked.push(d); }); - for (var j = 0; j < marker.markers.length; j++) { - var subMarker = marker.markers[j]; - if (indexOf(linked, subMarker.doc) == -1) { - subMarker.parent = null; - marker.markers.splice(j--, 1); - } - } - }; - - for (var i = 0; i < markers.length; i++) loop( i ); - } - - var nextDocId = 0; - var Doc = function(text, mode, firstLine, lineSep, direction) { - if (!(this instanceof Doc)) { return new Doc(text, mode, firstLine, lineSep, direction) } - if (firstLine == null) { firstLine = 0; } - - BranchChunk.call(this, [new LeafChunk([new Line("", null)])]); - this.first = firstLine; - this.scrollTop = this.scrollLeft = 0; - this.cantEdit = false; - this.cleanGeneration = 1; - this.modeFrontier = this.highlightFrontier = firstLine; - var start = Pos(firstLine, 0); - this.sel = simpleSelection(start); - this.history = new History(null); - this.id = ++nextDocId; - this.modeOption = mode; - this.lineSep = lineSep; - this.direction = (direction == "rtl") ? "rtl" : "ltr"; - this.extend = false; - - if (typeof text == "string") { text = this.splitLines(text); } - updateDoc(this, {from: start, to: start, text: text}); - setSelection(this, simpleSelection(start), sel_dontScroll); - }; - - Doc.prototype = createObj(BranchChunk.prototype, { - constructor: Doc, - // Iterate over the document. Supports two forms -- with only one - // argument, it calls that for each line in the document. With - // three, it iterates over the range given by the first two (with - // the second being non-inclusive). - iter: function(from, to, op) { - if (op) { this.iterN(from - this.first, to - from, op); } - else { this.iterN(this.first, this.first + this.size, from); } - }, - - // Non-public interface for adding and removing lines. - insert: function(at, lines) { - var height = 0; - for (var i = 0; i < lines.length; ++i) { height += lines[i].height; } - this.insertInner(at - this.first, lines, height); - }, - remove: function(at, n) { this.removeInner(at - this.first, n); }, - - // From here, the methods are part of the public interface. Most - // are also available from CodeMirror (editor) instances. - - getValue: function(lineSep) { - var lines = getLines(this, this.first, this.first + this.size); - if (lineSep === false) { return lines } - return lines.join(lineSep || this.lineSeparator()) - }, - setValue: docMethodOp(function(code) { - var top = Pos(this.first, 0), last = this.first + this.size - 1; - makeChange(this, {from: top, to: Pos(last, getLine(this, last).text.length), - text: this.splitLines(code), origin: "setValue", full: true}, true); - if (this.cm) { scrollToCoords(this.cm, 0, 0); } - setSelection(this, simpleSelection(top), sel_dontScroll); - }), - replaceRange: function(code, from, to, origin) { - from = clipPos(this, from); - to = to ? clipPos(this, to) : from; - replaceRange(this, code, from, to, origin); - }, - getRange: function(from, to, lineSep) { - var lines = getBetween(this, clipPos(this, from), clipPos(this, to)); - if (lineSep === false) { return lines } - if (lineSep === '') { return lines.join('') } - return lines.join(lineSep || this.lineSeparator()) - }, - - getLine: function(line) {var l = this.getLineHandle(line); return l && l.text}, - - getLineHandle: function(line) {if (isLine(this, line)) { return getLine(this, line) }}, - getLineNumber: function(line) {return lineNo(line)}, - - getLineHandleVisualStart: function(line) { - if (typeof line == "number") { line = getLine(this, line); } - return visualLine(line) - }, - - lineCount: function() {return this.size}, - firstLine: function() {return this.first}, - lastLine: function() {return this.first + this.size - 1}, - - clipPos: function(pos) {return clipPos(this, pos)}, - - getCursor: function(start) { - var range = this.sel.primary(), pos; - if (start == null || start == "head") { pos = range.head; } - else if (start == "anchor") { pos = range.anchor; } - else if (start == "end" || start == "to" || start === false) { pos = range.to(); } - else { pos = range.from(); } - return pos - }, - listSelections: function() { return this.sel.ranges }, - somethingSelected: function() {return this.sel.somethingSelected()}, - - setCursor: docMethodOp(function(line, ch, options) { - setSimpleSelection(this, clipPos(this, typeof line == "number" ? Pos(line, ch || 0) : line), null, options); - }), - setSelection: docMethodOp(function(anchor, head, options) { - setSimpleSelection(this, clipPos(this, anchor), clipPos(this, head || anchor), options); - }), - extendSelection: docMethodOp(function(head, other, options) { - extendSelection(this, clipPos(this, head), other && clipPos(this, other), options); - }), - extendSelections: docMethodOp(function(heads, options) { - extendSelections(this, clipPosArray(this, heads), options); - }), - extendSelectionsBy: docMethodOp(function(f, options) { - var heads = map(this.sel.ranges, f); - extendSelections(this, clipPosArray(this, heads), options); - }), - setSelections: docMethodOp(function(ranges, primary, options) { - if (!ranges.length) { return } - var out = []; - for (var i = 0; i < ranges.length; i++) - { out[i] = new Range(clipPos(this, ranges[i].anchor), - clipPos(this, ranges[i].head || ranges[i].anchor)); } - if (primary == null) { primary = Math.min(ranges.length - 1, this.sel.primIndex); } - setSelection(this, normalizeSelection(this.cm, out, primary), options); - }), - addSelection: docMethodOp(function(anchor, head, options) { - var ranges = this.sel.ranges.slice(0); - ranges.push(new Range(clipPos(this, anchor), clipPos(this, head || anchor))); - setSelection(this, normalizeSelection(this.cm, ranges, ranges.length - 1), options); - }), - - getSelection: function(lineSep) { - var ranges = this.sel.ranges, lines; - for (var i = 0; i < ranges.length; i++) { - var sel = getBetween(this, ranges[i].from(), ranges[i].to()); - lines = lines ? lines.concat(sel) : sel; - } - if (lineSep === false) { return lines } - else { return lines.join(lineSep || this.lineSeparator()) } - }, - getSelections: function(lineSep) { - var parts = [], ranges = this.sel.ranges; - for (var i = 0; i < ranges.length; i++) { - var sel = getBetween(this, ranges[i].from(), ranges[i].to()); - if (lineSep !== false) { sel = sel.join(lineSep || this.lineSeparator()); } - parts[i] = sel; - } - return parts - }, - replaceSelection: function(code, collapse, origin) { - var dup = []; - for (var i = 0; i < this.sel.ranges.length; i++) - { dup[i] = code; } - this.replaceSelections(dup, collapse, origin || "+input"); - }, - replaceSelections: docMethodOp(function(code, collapse, origin) { - var changes = [], sel = this.sel; - for (var i = 0; i < sel.ranges.length; i++) { - var range = sel.ranges[i]; - changes[i] = {from: range.from(), to: range.to(), text: this.splitLines(code[i]), origin: origin}; - } - var newSel = collapse && collapse != "end" && computeReplacedSel(this, changes, collapse); - for (var i$1 = changes.length - 1; i$1 >= 0; i$1--) - { makeChange(this, changes[i$1]); } - if (newSel) { setSelectionReplaceHistory(this, newSel); } - else if (this.cm) { ensureCursorVisible(this.cm); } - }), - undo: docMethodOp(function() {makeChangeFromHistory(this, "undo");}), - redo: docMethodOp(function() {makeChangeFromHistory(this, "redo");}), - undoSelection: docMethodOp(function() {makeChangeFromHistory(this, "undo", true);}), - redoSelection: docMethodOp(function() {makeChangeFromHistory(this, "redo", true);}), - - setExtending: function(val) {this.extend = val;}, - getExtending: function() {return this.extend}, - - historySize: function() { - var hist = this.history, done = 0, undone = 0; - for (var i = 0; i < hist.done.length; i++) { if (!hist.done[i].ranges) { ++done; } } - for (var i$1 = 0; i$1 < hist.undone.length; i$1++) { if (!hist.undone[i$1].ranges) { ++undone; } } - return {undo: done, redo: undone} - }, - clearHistory: function() { - var this$1 = this; - - this.history = new History(this.history); - linkedDocs(this, function (doc) { return doc.history = this$1.history; }, true); - }, - - markClean: function() { - this.cleanGeneration = this.changeGeneration(true); - }, - changeGeneration: function(forceSplit) { - if (forceSplit) - { this.history.lastOp = this.history.lastSelOp = this.history.lastOrigin = null; } - return this.history.generation - }, - isClean: function (gen) { - return this.history.generation == (gen || this.cleanGeneration) - }, - - getHistory: function() { - return {done: copyHistoryArray(this.history.done), - undone: copyHistoryArray(this.history.undone)} - }, - setHistory: function(histData) { - var hist = this.history = new History(this.history); - hist.done = copyHistoryArray(histData.done.slice(0), null, true); - hist.undone = copyHistoryArray(histData.undone.slice(0), null, true); - }, - - setGutterMarker: docMethodOp(function(line, gutterID, value) { - return changeLine(this, line, "gutter", function (line) { - var markers = line.gutterMarkers || (line.gutterMarkers = {}); - markers[gutterID] = value; - if (!value && isEmpty(markers)) { line.gutterMarkers = null; } - return true - }) - }), - - clearGutter: docMethodOp(function(gutterID) { - var this$1 = this; - - this.iter(function (line) { - if (line.gutterMarkers && line.gutterMarkers[gutterID]) { - changeLine(this$1, line, "gutter", function () { - line.gutterMarkers[gutterID] = null; - if (isEmpty(line.gutterMarkers)) { line.gutterMarkers = null; } - return true - }); - } - }); - }), - - lineInfo: function(line) { - var n; - if (typeof line == "number") { - if (!isLine(this, line)) { return null } - n = line; - line = getLine(this, line); - if (!line) { return null } - } else { - n = lineNo(line); - if (n == null) { return null } - } - return {line: n, handle: line, text: line.text, gutterMarkers: line.gutterMarkers, - textClass: line.textClass, bgClass: line.bgClass, wrapClass: line.wrapClass, - widgets: line.widgets} - }, - - addLineClass: docMethodOp(function(handle, where, cls) { - return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function (line) { - var prop = where == "text" ? "textClass" - : where == "background" ? "bgClass" - : where == "gutter" ? "gutterClass" : "wrapClass"; - if (!line[prop]) { line[prop] = cls; } - else if (classTest(cls).test(line[prop])) { return false } - else { line[prop] += " " + cls; } - return true - }) - }), - removeLineClass: docMethodOp(function(handle, where, cls) { - return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function (line) { - var prop = where == "text" ? "textClass" - : where == "background" ? "bgClass" - : where == "gutter" ? "gutterClass" : "wrapClass"; - var cur = line[prop]; - if (!cur) { return false } - else if (cls == null) { line[prop] = null; } - else { - var found = cur.match(classTest(cls)); - if (!found) { return false } - var end = found.index + found[0].length; - line[prop] = cur.slice(0, found.index) + (!found.index || end == cur.length ? "" : " ") + cur.slice(end) || null; - } - return true - }) - }), - - addLineWidget: docMethodOp(function(handle, node, options) { - return addLineWidget(this, handle, node, options) - }), - removeLineWidget: function(widget) { widget.clear(); }, - - markText: function(from, to, options) { - return markText(this, clipPos(this, from), clipPos(this, to), options, options && options.type || "range") - }, - setBookmark: function(pos, options) { - var realOpts = {replacedWith: options && (options.nodeType == null ? options.widget : options), - insertLeft: options && options.insertLeft, - clearWhenEmpty: false, shared: options && options.shared, - handleMouseEvents: options && options.handleMouseEvents}; - pos = clipPos(this, pos); - return markText(this, pos, pos, realOpts, "bookmark") - }, - findMarksAt: function(pos) { - pos = clipPos(this, pos); - var markers = [], spans = getLine(this, pos.line).markedSpans; - if (spans) { for (var i = 0; i < spans.length; ++i) { - var span = spans[i]; - if ((span.from == null || span.from <= pos.ch) && - (span.to == null || span.to >= pos.ch)) - { markers.push(span.marker.parent || span.marker); } - } } - return markers - }, - findMarks: function(from, to, filter) { - from = clipPos(this, from); to = clipPos(this, to); - var found = [], lineNo = from.line; - this.iter(from.line, to.line + 1, function (line) { - var spans = line.markedSpans; - if (spans) { for (var i = 0; i < spans.length; i++) { - var span = spans[i]; - if (!(span.to != null && lineNo == from.line && from.ch >= span.to || - span.from == null && lineNo != from.line || - span.from != null && lineNo == to.line && span.from >= to.ch) && - (!filter || filter(span.marker))) - { found.push(span.marker.parent || span.marker); } - } } - ++lineNo; - }); - return found - }, - getAllMarks: function() { - var markers = []; - this.iter(function (line) { - var sps = line.markedSpans; - if (sps) { for (var i = 0; i < sps.length; ++i) - { if (sps[i].from != null) { markers.push(sps[i].marker); } } } - }); - return markers - }, - - posFromIndex: function(off) { - var ch, lineNo = this.first, sepSize = this.lineSeparator().length; - this.iter(function (line) { - var sz = line.text.length + sepSize; - if (sz > off) { ch = off; return true } - off -= sz; - ++lineNo; - }); - return clipPos(this, Pos(lineNo, ch)) - }, - indexFromPos: function (coords) { - coords = clipPos(this, coords); - var index = coords.ch; - if (coords.line < this.first || coords.ch < 0) { return 0 } - var sepSize = this.lineSeparator().length; - this.iter(this.first, coords.line, function (line) { // iter aborts when callback returns a truthy value - index += line.text.length + sepSize; - }); - return index - }, - - copy: function(copyHistory) { - var doc = new Doc(getLines(this, this.first, this.first + this.size), - this.modeOption, this.first, this.lineSep, this.direction); - doc.scrollTop = this.scrollTop; doc.scrollLeft = this.scrollLeft; - doc.sel = this.sel; - doc.extend = false; - if (copyHistory) { - doc.history.undoDepth = this.history.undoDepth; - doc.setHistory(this.getHistory()); - } - return doc - }, - - linkedDoc: function(options) { - if (!options) { options = {}; } - var from = this.first, to = this.first + this.size; - if (options.from != null && options.from > from) { from = options.from; } - if (options.to != null && options.to < to) { to = options.to; } - var copy = new Doc(getLines(this, from, to), options.mode || this.modeOption, from, this.lineSep, this.direction); - if (options.sharedHist) { copy.history = this.history - ; }(this.linked || (this.linked = [])).push({doc: copy, sharedHist: options.sharedHist}); - copy.linked = [{doc: this, isParent: true, sharedHist: options.sharedHist}]; - copySharedMarkers(copy, findSharedMarkers(this)); - return copy - }, - unlinkDoc: function(other) { - if (other instanceof CodeMirror) { other = other.doc; } - if (this.linked) { for (var i = 0; i < this.linked.length; ++i) { - var link = this.linked[i]; - if (link.doc != other) { continue } - this.linked.splice(i, 1); - other.unlinkDoc(this); - detachSharedMarkers(findSharedMarkers(this)); - break - } } - // If the histories were shared, split them again - if (other.history == this.history) { - var splitIds = [other.id]; - linkedDocs(other, function (doc) { return splitIds.push(doc.id); }, true); - other.history = new History(null); - other.history.done = copyHistoryArray(this.history.done, splitIds); - other.history.undone = copyHistoryArray(this.history.undone, splitIds); - } - }, - iterLinkedDocs: function(f) {linkedDocs(this, f);}, - - getMode: function() {return this.mode}, - getEditor: function() {return this.cm}, - - splitLines: function(str) { - if (this.lineSep) { return str.split(this.lineSep) } - return splitLinesAuto(str) - }, - lineSeparator: function() { return this.lineSep || "\n" }, - - setDirection: docMethodOp(function (dir) { - if (dir != "rtl") { dir = "ltr"; } - if (dir == this.direction) { return } - this.direction = dir; - this.iter(function (line) { return line.order = null; }); - if (this.cm) { directionChanged(this.cm); } - }) - }); - - // Public alias. - Doc.prototype.eachLine = Doc.prototype.iter; - - // Kludge to work around strange IE behavior where it'll sometimes - // re-fire a series of drag-related events right after the drop (#1551) - var lastDrop = 0; - - function onDrop(e) { - var cm = this; - clearDragCursor(cm); - if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) - { return } - e_preventDefault(e); - if (ie) { lastDrop = +new Date; } - var pos = posFromMouse(cm, e, true), files = e.dataTransfer.files; - if (!pos || cm.isReadOnly()) { return } - // Might be a file drop, in which case we simply extract the text - // and insert it. - if (files && files.length && window.FileReader && window.File) { - var n = files.length, text = Array(n), read = 0; - var markAsReadAndPasteIfAllFilesAreRead = function () { - if (++read == n) { - operation(cm, function () { - pos = clipPos(cm.doc, pos); - var change = {from: pos, to: pos, - text: cm.doc.splitLines( - text.filter(function (t) { return t != null; }).join(cm.doc.lineSeparator())), - origin: "paste"}; - makeChange(cm.doc, change); - setSelectionReplaceHistory(cm.doc, simpleSelection(clipPos(cm.doc, pos), clipPos(cm.doc, changeEnd(change)))); - })(); - } - }; - var readTextFromFile = function (file, i) { - if (cm.options.allowDropFileTypes && - indexOf(cm.options.allowDropFileTypes, file.type) == -1) { - markAsReadAndPasteIfAllFilesAreRead(); - return - } - var reader = new FileReader; - reader.onerror = function () { return markAsReadAndPasteIfAllFilesAreRead(); }; - reader.onload = function () { - var content = reader.result; - if (/[\x00-\x08\x0e-\x1f]{2}/.test(content)) { - markAsReadAndPasteIfAllFilesAreRead(); - return - } - text[i] = content; - markAsReadAndPasteIfAllFilesAreRead(); - }; - reader.readAsText(file); - }; - for (var i = 0; i < files.length; i++) { readTextFromFile(files[i], i); } - } else { // Normal drop - // Don't do a replace if the drop happened inside of the selected text. - if (cm.state.draggingText && cm.doc.sel.contains(pos) > -1) { - cm.state.draggingText(e); - // Ensure the editor is re-focused - setTimeout(function () { return cm.display.input.focus(); }, 20); - return - } - try { - var text$1 = e.dataTransfer.getData("Text"); - if (text$1) { - var selected; - if (cm.state.draggingText && !cm.state.draggingText.copy) - { selected = cm.listSelections(); } - setSelectionNoUndo(cm.doc, simpleSelection(pos, pos)); - if (selected) { for (var i$1 = 0; i$1 < selected.length; ++i$1) - { replaceRange(cm.doc, "", selected[i$1].anchor, selected[i$1].head, "drag"); } } - cm.replaceSelection(text$1, "around", "paste"); - cm.display.input.focus(); - } - } - catch(e$1){} - } - } - - function onDragStart(cm, e) { - if (ie && (!cm.state.draggingText || +new Date - lastDrop < 100)) { e_stop(e); return } - if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) { return } - - e.dataTransfer.setData("Text", cm.getSelection()); - e.dataTransfer.effectAllowed = "copyMove"; - - // Use dummy image instead of default browsers image. - // Recent Safari (~6.0.2) have a tendency to segfault when this happens, so we don't do it there. - if (e.dataTransfer.setDragImage && !safari) { - var img = elt("img", null, null, "position: fixed; left: 0; top: 0;"); - img.src = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="; - if (presto) { - img.width = img.height = 1; - cm.display.wrapper.appendChild(img); - // Force a relayout, or Opera won't use our image for some obscure reason - img._top = img.offsetTop; - } - e.dataTransfer.setDragImage(img, 0, 0); - if (presto) { img.parentNode.removeChild(img); } - } - } - - function onDragOver(cm, e) { - var pos = posFromMouse(cm, e); - if (!pos) { return } - var frag = document.createDocumentFragment(); - drawSelectionCursor(cm, pos, frag); - if (!cm.display.dragCursor) { - cm.display.dragCursor = elt("div", null, "CodeMirror-cursors CodeMirror-dragcursors"); - cm.display.lineSpace.insertBefore(cm.display.dragCursor, cm.display.cursorDiv); - } - removeChildrenAndAdd(cm.display.dragCursor, frag); - } - - function clearDragCursor(cm) { - if (cm.display.dragCursor) { - cm.display.lineSpace.removeChild(cm.display.dragCursor); - cm.display.dragCursor = null; - } - } - - // These must be handled carefully, because naively registering a - // handler for each editor will cause the editors to never be - // garbage collected. - - function forEachCodeMirror(f) { - if (!document.getElementsByClassName) { return } - var byClass = document.getElementsByClassName("CodeMirror"), editors = []; - for (var i = 0; i < byClass.length; i++) { - var cm = byClass[i].CodeMirror; - if (cm) { editors.push(cm); } - } - if (editors.length) { editors[0].operation(function () { - for (var i = 0; i < editors.length; i++) { f(editors[i]); } - }); } - } - - var globalsRegistered = false; - function ensureGlobalHandlers() { - if (globalsRegistered) { return } - registerGlobalHandlers(); - globalsRegistered = true; - } - function registerGlobalHandlers() { - // When the window resizes, we need to refresh active editors. - var resizeTimer; - on(window, "resize", function () { - if (resizeTimer == null) { resizeTimer = setTimeout(function () { - resizeTimer = null; - forEachCodeMirror(onResize); - }, 100); } - }); - // When the window loses focus, we want to show the editor as blurred - on(window, "blur", function () { return forEachCodeMirror(onBlur); }); - } - // Called when the window resizes - function onResize(cm) { - var d = cm.display; - // Might be a text scaling operation, clear size caches. - d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null; - d.scrollbarsClipped = false; - cm.setSize(); - } - - var keyNames = { - 3: "Pause", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt", - 19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End", - 36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert", - 46: "Delete", 59: ";", 61: "=", 91: "Mod", 92: "Mod", 93: "Mod", - 106: "*", 107: "=", 109: "-", 110: ".", 111: "/", 145: "ScrollLock", - 173: "-", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\", - 221: "]", 222: "'", 224: "Mod", 63232: "Up", 63233: "Down", 63234: "Left", 63235: "Right", 63272: "Delete", - 63273: "Home", 63275: "End", 63276: "PageUp", 63277: "PageDown", 63302: "Insert" - }; - - // Number keys - for (var i = 0; i < 10; i++) { keyNames[i + 48] = keyNames[i + 96] = String(i); } - // Alphabetic keys - for (var i$1 = 65; i$1 <= 90; i$1++) { keyNames[i$1] = String.fromCharCode(i$1); } - // Function keys - for (var i$2 = 1; i$2 <= 12; i$2++) { keyNames[i$2 + 111] = keyNames[i$2 + 63235] = "F" + i$2; } - - var keyMap = {}; - - keyMap.basic = { - "Left": "goCharLeft", "Right": "goCharRight", "Up": "goLineUp", "Down": "goLineDown", - "End": "goLineEnd", "Home": "goLineStartSmart", "PageUp": "goPageUp", "PageDown": "goPageDown", - "Delete": "delCharAfter", "Backspace": "delCharBefore", "Shift-Backspace": "delCharBefore", - "Tab": "defaultTab", "Shift-Tab": "indentAuto", - "Enter": "newlineAndIndent", "Insert": "toggleOverwrite", - "Esc": "singleSelection" - }; - // Note that the save and find-related commands aren't defined by - // default. User code or addons can define them. Unknown commands - // are simply ignored. - keyMap.pcDefault = { - "Ctrl-A": "selectAll", "Ctrl-D": "deleteLine", "Ctrl-Z": "undo", "Shift-Ctrl-Z": "redo", "Ctrl-Y": "redo", - "Ctrl-Home": "goDocStart", "Ctrl-End": "goDocEnd", "Ctrl-Up": "goLineUp", "Ctrl-Down": "goLineDown", - "Ctrl-Left": "goGroupLeft", "Ctrl-Right": "goGroupRight", "Alt-Left": "goLineStart", "Alt-Right": "goLineEnd", - "Ctrl-Backspace": "delGroupBefore", "Ctrl-Delete": "delGroupAfter", "Ctrl-S": "save", "Ctrl-F": "find", - "Ctrl-G": "findNext", "Shift-Ctrl-G": "findPrev", "Shift-Ctrl-F": "replace", "Shift-Ctrl-R": "replaceAll", - "Ctrl-[": "indentLess", "Ctrl-]": "indentMore", - "Ctrl-U": "undoSelection", "Shift-Ctrl-U": "redoSelection", "Alt-U": "redoSelection", - "fallthrough": "basic" - }; - // Very basic readline/emacs-style bindings, which are standard on Mac. - keyMap.emacsy = { - "Ctrl-F": "goCharRight", "Ctrl-B": "goCharLeft", "Ctrl-P": "goLineUp", "Ctrl-N": "goLineDown", - "Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd", "Ctrl-V": "goPageDown", "Shift-Ctrl-V": "goPageUp", - "Ctrl-D": "delCharAfter", "Ctrl-H": "delCharBefore", "Alt-Backspace": "delWordBefore", "Ctrl-K": "killLine", - "Ctrl-T": "transposeChars", "Ctrl-O": "openLine" - }; - keyMap.macDefault = { - "Cmd-A": "selectAll", "Cmd-D": "deleteLine", "Cmd-Z": "undo", "Shift-Cmd-Z": "redo", "Cmd-Y": "redo", - "Cmd-Home": "goDocStart", "Cmd-Up": "goDocStart", "Cmd-End": "goDocEnd", "Cmd-Down": "goDocEnd", "Alt-Left": "goGroupLeft", - "Alt-Right": "goGroupRight", "Cmd-Left": "goLineLeft", "Cmd-Right": "goLineRight", "Alt-Backspace": "delGroupBefore", - "Ctrl-Alt-Backspace": "delGroupAfter", "Alt-Delete": "delGroupAfter", "Cmd-S": "save", "Cmd-F": "find", - "Cmd-G": "findNext", "Shift-Cmd-G": "findPrev", "Cmd-Alt-F": "replace", "Shift-Cmd-Alt-F": "replaceAll", - "Cmd-[": "indentLess", "Cmd-]": "indentMore", "Cmd-Backspace": "delWrappedLineLeft", "Cmd-Delete": "delWrappedLineRight", - "Cmd-U": "undoSelection", "Shift-Cmd-U": "redoSelection", "Ctrl-Up": "goDocStart", "Ctrl-Down": "goDocEnd", - "fallthrough": ["basic", "emacsy"] - }; - keyMap["default"] = mac ? keyMap.macDefault : keyMap.pcDefault; - - // KEYMAP DISPATCH - - function normalizeKeyName(name) { - var parts = name.split(/-(?!$)/); - name = parts[parts.length - 1]; - var alt, ctrl, shift, cmd; - for (var i = 0; i < parts.length - 1; i++) { - var mod = parts[i]; - if (/^(cmd|meta|m)$/i.test(mod)) { cmd = true; } - else if (/^a(lt)?$/i.test(mod)) { alt = true; } - else if (/^(c|ctrl|control)$/i.test(mod)) { ctrl = true; } - else if (/^s(hift)?$/i.test(mod)) { shift = true; } - else { throw new Error("Unrecognized modifier name: " + mod) } - } - if (alt) { name = "Alt-" + name; } - if (ctrl) { name = "Ctrl-" + name; } - if (cmd) { name = "Cmd-" + name; } - if (shift) { name = "Shift-" + name; } - return name - } - - // This is a kludge to keep keymaps mostly working as raw objects - // (backwards compatibility) while at the same time support features - // like normalization and multi-stroke key bindings. It compiles a - // new normalized keymap, and then updates the old object to reflect - // this. - function normalizeKeyMap(keymap) { - var copy = {}; - for (var keyname in keymap) { if (keymap.hasOwnProperty(keyname)) { - var value = keymap[keyname]; - if (/^(name|fallthrough|(de|at)tach)$/.test(keyname)) { continue } - if (value == "...") { delete keymap[keyname]; continue } - - var keys = map(keyname.split(" "), normalizeKeyName); - for (var i = 0; i < keys.length; i++) { - var val = (void 0), name = (void 0); - if (i == keys.length - 1) { - name = keys.join(" "); - val = value; - } else { - name = keys.slice(0, i + 1).join(" "); - val = "..."; - } - var prev = copy[name]; - if (!prev) { copy[name] = val; } - else if (prev != val) { throw new Error("Inconsistent bindings for " + name) } - } - delete keymap[keyname]; - } } - for (var prop in copy) { keymap[prop] = copy[prop]; } - return keymap - } - - function lookupKey(key, map, handle, context) { - map = getKeyMap(map); - var found = map.call ? map.call(key, context) : map[key]; - if (found === false) { return "nothing" } - if (found === "...") { return "multi" } - if (found != null && handle(found)) { return "handled" } - - if (map.fallthrough) { - if (Object.prototype.toString.call(map.fallthrough) != "[object Array]") - { return lookupKey(key, map.fallthrough, handle, context) } - for (var i = 0; i < map.fallthrough.length; i++) { - var result = lookupKey(key, map.fallthrough[i], handle, context); - if (result) { return result } - } - } - } - - // Modifier key presses don't count as 'real' key presses for the - // purpose of keymap fallthrough. - function isModifierKey(value) { - var name = typeof value == "string" ? value : keyNames[value.keyCode]; - return name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod" - } - - function addModifierNames(name, event, noShift) { - var base = name; - if (event.altKey && base != "Alt") { name = "Alt-" + name; } - if ((flipCtrlCmd ? event.metaKey : event.ctrlKey) && base != "Ctrl") { name = "Ctrl-" + name; } - if ((flipCtrlCmd ? event.ctrlKey : event.metaKey) && base != "Mod") { name = "Cmd-" + name; } - if (!noShift && event.shiftKey && base != "Shift") { name = "Shift-" + name; } - return name - } - - // Look up the name of a key as indicated by an event object. - function keyName(event, noShift) { - if (presto && event.keyCode == 34 && event["char"]) { return false } - var name = keyNames[event.keyCode]; - if (name == null || event.altGraphKey) { return false } - // Ctrl-ScrollLock has keyCode 3, same as Ctrl-Pause, - // so we'll use event.code when available (Chrome 48+, FF 38+, Safari 10.1+) - if (event.keyCode == 3 && event.code) { name = event.code; } - return addModifierNames(name, event, noShift) - } - - function getKeyMap(val) { - return typeof val == "string" ? keyMap[val] : val - } - - // Helper for deleting text near the selection(s), used to implement - // backspace, delete, and similar functionality. - function deleteNearSelection(cm, compute) { - var ranges = cm.doc.sel.ranges, kill = []; - // Build up a set of ranges to kill first, merging overlapping - // ranges. - for (var i = 0; i < ranges.length; i++) { - var toKill = compute(ranges[i]); - while (kill.length && cmp(toKill.from, lst(kill).to) <= 0) { - var replaced = kill.pop(); - if (cmp(replaced.from, toKill.from) < 0) { - toKill.from = replaced.from; - break - } - } - kill.push(toKill); - } - // Next, remove those actual ranges. - runInOp(cm, function () { - for (var i = kill.length - 1; i >= 0; i--) - { replaceRange(cm.doc, "", kill[i].from, kill[i].to, "+delete"); } - ensureCursorVisible(cm); - }); - } - - function moveCharLogically(line, ch, dir) { - var target = skipExtendingChars(line.text, ch + dir, dir); - return target < 0 || target > line.text.length ? null : target - } - - function moveLogically(line, start, dir) { - var ch = moveCharLogically(line, start.ch, dir); - return ch == null ? null : new Pos(start.line, ch, dir < 0 ? "after" : "before") - } - - function endOfLine(visually, cm, lineObj, lineNo, dir) { - if (visually) { - if (cm.doc.direction == "rtl") { dir = -dir; } - var order = getOrder(lineObj, cm.doc.direction); - if (order) { - var part = dir < 0 ? lst(order) : order[0]; - var moveInStorageOrder = (dir < 0) == (part.level == 1); - var sticky = moveInStorageOrder ? "after" : "before"; - var ch; - // With a wrapped rtl chunk (possibly spanning multiple bidi parts), - // it could be that the last bidi part is not on the last visual line, - // since visual lines contain content order-consecutive chunks. - // Thus, in rtl, we are looking for the first (content-order) character - // in the rtl chunk that is on the last line (that is, the same line - // as the last (content-order) character). - if (part.level > 0 || cm.doc.direction == "rtl") { - var prep = prepareMeasureForLine(cm, lineObj); - ch = dir < 0 ? lineObj.text.length - 1 : 0; - var targetTop = measureCharPrepared(cm, prep, ch).top; - ch = findFirst(function (ch) { return measureCharPrepared(cm, prep, ch).top == targetTop; }, (dir < 0) == (part.level == 1) ? part.from : part.to - 1, ch); - if (sticky == "before") { ch = moveCharLogically(lineObj, ch, 1); } - } else { ch = dir < 0 ? part.to : part.from; } - return new Pos(lineNo, ch, sticky) - } - } - return new Pos(lineNo, dir < 0 ? lineObj.text.length : 0, dir < 0 ? "before" : "after") - } - - function moveVisually(cm, line, start, dir) { - var bidi = getOrder(line, cm.doc.direction); - if (!bidi) { return moveLogically(line, start, dir) } - if (start.ch >= line.text.length) { - start.ch = line.text.length; - start.sticky = "before"; - } else if (start.ch <= 0) { - start.ch = 0; - start.sticky = "after"; - } - var partPos = getBidiPartAt(bidi, start.ch, start.sticky), part = bidi[partPos]; - if (cm.doc.direction == "ltr" && part.level % 2 == 0 && (dir > 0 ? part.to > start.ch : part.from < start.ch)) { - // Case 1: We move within an ltr part in an ltr editor. Even with wrapped lines, - // nothing interesting happens. - return moveLogically(line, start, dir) - } - - var mv = function (pos, dir) { return moveCharLogically(line, pos instanceof Pos ? pos.ch : pos, dir); }; - var prep; - var getWrappedLineExtent = function (ch) { - if (!cm.options.lineWrapping) { return {begin: 0, end: line.text.length} } - prep = prep || prepareMeasureForLine(cm, line); - return wrappedLineExtentChar(cm, line, prep, ch) - }; - var wrappedLineExtent = getWrappedLineExtent(start.sticky == "before" ? mv(start, -1) : start.ch); - - if (cm.doc.direction == "rtl" || part.level == 1) { - var moveInStorageOrder = (part.level == 1) == (dir < 0); - var ch = mv(start, moveInStorageOrder ? 1 : -1); - if (ch != null && (!moveInStorageOrder ? ch >= part.from && ch >= wrappedLineExtent.begin : ch <= part.to && ch <= wrappedLineExtent.end)) { - // Case 2: We move within an rtl part or in an rtl editor on the same visual line - var sticky = moveInStorageOrder ? "before" : "after"; - return new Pos(start.line, ch, sticky) - } - } - - // Case 3: Could not move within this bidi part in this visual line, so leave - // the current bidi part - - var searchInVisualLine = function (partPos, dir, wrappedLineExtent) { - var getRes = function (ch, moveInStorageOrder) { return moveInStorageOrder - ? new Pos(start.line, mv(ch, 1), "before") - : new Pos(start.line, ch, "after"); }; - - for (; partPos >= 0 && partPos < bidi.length; partPos += dir) { - var part = bidi[partPos]; - var moveInStorageOrder = (dir > 0) == (part.level != 1); - var ch = moveInStorageOrder ? wrappedLineExtent.begin : mv(wrappedLineExtent.end, -1); - if (part.from <= ch && ch < part.to) { return getRes(ch, moveInStorageOrder) } - ch = moveInStorageOrder ? part.from : mv(part.to, -1); - if (wrappedLineExtent.begin <= ch && ch < wrappedLineExtent.end) { return getRes(ch, moveInStorageOrder) } - } - }; - - // Case 3a: Look for other bidi parts on the same visual line - var res = searchInVisualLine(partPos + dir, dir, wrappedLineExtent); - if (res) { return res } - - // Case 3b: Look for other bidi parts on the next visual line - var nextCh = dir > 0 ? wrappedLineExtent.end : mv(wrappedLineExtent.begin, -1); - if (nextCh != null && !(dir > 0 && nextCh == line.text.length)) { - res = searchInVisualLine(dir > 0 ? 0 : bidi.length - 1, dir, getWrappedLineExtent(nextCh)); - if (res) { return res } - } - - // Case 4: Nowhere to move - return null - } - - // Commands are parameter-less actions that can be performed on an - // editor, mostly used for keybindings. - var commands = { - selectAll: selectAll, - singleSelection: function (cm) { return cm.setSelection(cm.getCursor("anchor"), cm.getCursor("head"), sel_dontScroll); }, - killLine: function (cm) { return deleteNearSelection(cm, function (range) { - if (range.empty()) { - var len = getLine(cm.doc, range.head.line).text.length; - if (range.head.ch == len && range.head.line < cm.lastLine()) - { return {from: range.head, to: Pos(range.head.line + 1, 0)} } - else - { return {from: range.head, to: Pos(range.head.line, len)} } - } else { - return {from: range.from(), to: range.to()} - } - }); }, - deleteLine: function (cm) { return deleteNearSelection(cm, function (range) { return ({ - from: Pos(range.from().line, 0), - to: clipPos(cm.doc, Pos(range.to().line + 1, 0)) - }); }); }, - delLineLeft: function (cm) { return deleteNearSelection(cm, function (range) { return ({ - from: Pos(range.from().line, 0), to: range.from() - }); }); }, - delWrappedLineLeft: function (cm) { return deleteNearSelection(cm, function (range) { - var top = cm.charCoords(range.head, "div").top + 5; - var leftPos = cm.coordsChar({left: 0, top: top}, "div"); - return {from: leftPos, to: range.from()} - }); }, - delWrappedLineRight: function (cm) { return deleteNearSelection(cm, function (range) { - var top = cm.charCoords(range.head, "div").top + 5; - var rightPos = cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div"); - return {from: range.from(), to: rightPos } - }); }, - undo: function (cm) { return cm.undo(); }, - redo: function (cm) { return cm.redo(); }, - undoSelection: function (cm) { return cm.undoSelection(); }, - redoSelection: function (cm) { return cm.redoSelection(); }, - goDocStart: function (cm) { return cm.extendSelection(Pos(cm.firstLine(), 0)); }, - goDocEnd: function (cm) { return cm.extendSelection(Pos(cm.lastLine())); }, - goLineStart: function (cm) { return cm.extendSelectionsBy(function (range) { return lineStart(cm, range.head.line); }, - {origin: "+move", bias: 1} - ); }, - goLineStartSmart: function (cm) { return cm.extendSelectionsBy(function (range) { return lineStartSmart(cm, range.head); }, - {origin: "+move", bias: 1} - ); }, - goLineEnd: function (cm) { return cm.extendSelectionsBy(function (range) { return lineEnd(cm, range.head.line); }, - {origin: "+move", bias: -1} - ); }, - goLineRight: function (cm) { return cm.extendSelectionsBy(function (range) { - var top = cm.cursorCoords(range.head, "div").top + 5; - return cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div") - }, sel_move); }, - goLineLeft: function (cm) { return cm.extendSelectionsBy(function (range) { - var top = cm.cursorCoords(range.head, "div").top + 5; - return cm.coordsChar({left: 0, top: top}, "div") - }, sel_move); }, - goLineLeftSmart: function (cm) { return cm.extendSelectionsBy(function (range) { - var top = cm.cursorCoords(range.head, "div").top + 5; - var pos = cm.coordsChar({left: 0, top: top}, "div"); - if (pos.ch < cm.getLine(pos.line).search(/\S/)) { return lineStartSmart(cm, range.head) } - return pos - }, sel_move); }, - goLineUp: function (cm) { return cm.moveV(-1, "line"); }, - goLineDown: function (cm) { return cm.moveV(1, "line"); }, - goPageUp: function (cm) { return cm.moveV(-1, "page"); }, - goPageDown: function (cm) { return cm.moveV(1, "page"); }, - goCharLeft: function (cm) { return cm.moveH(-1, "char"); }, - goCharRight: function (cm) { return cm.moveH(1, "char"); }, - goColumnLeft: function (cm) { return cm.moveH(-1, "column"); }, - goColumnRight: function (cm) { return cm.moveH(1, "column"); }, - goWordLeft: function (cm) { return cm.moveH(-1, "word"); }, - goGroupRight: function (cm) { return cm.moveH(1, "group"); }, - goGroupLeft: function (cm) { return cm.moveH(-1, "group"); }, - goWordRight: function (cm) { return cm.moveH(1, "word"); }, - delCharBefore: function (cm) { return cm.deleteH(-1, "codepoint"); }, - delCharAfter: function (cm) { return cm.deleteH(1, "char"); }, - delWordBefore: function (cm) { return cm.deleteH(-1, "word"); }, - delWordAfter: function (cm) { return cm.deleteH(1, "word"); }, - delGroupBefore: function (cm) { return cm.deleteH(-1, "group"); }, - delGroupAfter: function (cm) { return cm.deleteH(1, "group"); }, - indentAuto: function (cm) { return cm.indentSelection("smart"); }, - indentMore: function (cm) { return cm.indentSelection("add"); }, - indentLess: function (cm) { return cm.indentSelection("subtract"); }, - insertTab: function (cm) { return cm.replaceSelection("\t"); }, - insertSoftTab: function (cm) { - var spaces = [], ranges = cm.listSelections(), tabSize = cm.options.tabSize; - for (var i = 0; i < ranges.length; i++) { - var pos = ranges[i].from(); - var col = countColumn(cm.getLine(pos.line), pos.ch, tabSize); - spaces.push(spaceStr(tabSize - col % tabSize)); - } - cm.replaceSelections(spaces); - }, - defaultTab: function (cm) { - if (cm.somethingSelected()) { cm.indentSelection("add"); } - else { cm.execCommand("insertTab"); } - }, - // Swap the two chars left and right of each selection's head. - // Move cursor behind the two swapped characters afterwards. - // - // Doesn't consider line feeds a character. - // Doesn't scan more than one line above to find a character. - // Doesn't do anything on an empty line. - // Doesn't do anything with non-empty selections. - transposeChars: function (cm) { return runInOp(cm, function () { - var ranges = cm.listSelections(), newSel = []; - for (var i = 0; i < ranges.length; i++) { - if (!ranges[i].empty()) { continue } - var cur = ranges[i].head, line = getLine(cm.doc, cur.line).text; - if (line) { - if (cur.ch == line.length) { cur = new Pos(cur.line, cur.ch - 1); } - if (cur.ch > 0) { - cur = new Pos(cur.line, cur.ch + 1); - cm.replaceRange(line.charAt(cur.ch - 1) + line.charAt(cur.ch - 2), - Pos(cur.line, cur.ch - 2), cur, "+transpose"); - } else if (cur.line > cm.doc.first) { - var prev = getLine(cm.doc, cur.line - 1).text; - if (prev) { - cur = new Pos(cur.line, 1); - cm.replaceRange(line.charAt(0) + cm.doc.lineSeparator() + - prev.charAt(prev.length - 1), - Pos(cur.line - 1, prev.length - 1), cur, "+transpose"); - } - } - } - newSel.push(new Range(cur, cur)); - } - cm.setSelections(newSel); - }); }, - newlineAndIndent: function (cm) { return runInOp(cm, function () { - var sels = cm.listSelections(); - for (var i = sels.length - 1; i >= 0; i--) - { cm.replaceRange(cm.doc.lineSeparator(), sels[i].anchor, sels[i].head, "+input"); } - sels = cm.listSelections(); - for (var i$1 = 0; i$1 < sels.length; i$1++) - { cm.indentLine(sels[i$1].from().line, null, true); } - ensureCursorVisible(cm); - }); }, - openLine: function (cm) { return cm.replaceSelection("\n", "start"); }, - toggleOverwrite: function (cm) { return cm.toggleOverwrite(); } - }; - - - function lineStart(cm, lineN) { - var line = getLine(cm.doc, lineN); - var visual = visualLine(line); - if (visual != line) { lineN = lineNo(visual); } - return endOfLine(true, cm, visual, lineN, 1) - } - function lineEnd(cm, lineN) { - var line = getLine(cm.doc, lineN); - var visual = visualLineEnd(line); - if (visual != line) { lineN = lineNo(visual); } - return endOfLine(true, cm, line, lineN, -1) - } - function lineStartSmart(cm, pos) { - var start = lineStart(cm, pos.line); - var line = getLine(cm.doc, start.line); - var order = getOrder(line, cm.doc.direction); - if (!order || order[0].level == 0) { - var firstNonWS = Math.max(start.ch, line.text.search(/\S/)); - var inWS = pos.line == start.line && pos.ch <= firstNonWS && pos.ch; - return Pos(start.line, inWS ? 0 : firstNonWS, start.sticky) - } - return start - } - - // Run a handler that was bound to a key. - function doHandleBinding(cm, bound, dropShift) { - if (typeof bound == "string") { - bound = commands[bound]; - if (!bound) { return false } - } - // Ensure previous input has been read, so that the handler sees a - // consistent view of the document - cm.display.input.ensurePolled(); - var prevShift = cm.display.shift, done = false; - try { - if (cm.isReadOnly()) { cm.state.suppressEdits = true; } - if (dropShift) { cm.display.shift = false; } - done = bound(cm) != Pass; - } finally { - cm.display.shift = prevShift; - cm.state.suppressEdits = false; - } - return done - } - - function lookupKeyForEditor(cm, name, handle) { - for (var i = 0; i < cm.state.keyMaps.length; i++) { - var result = lookupKey(name, cm.state.keyMaps[i], handle, cm); - if (result) { return result } - } - return (cm.options.extraKeys && lookupKey(name, cm.options.extraKeys, handle, cm)) - || lookupKey(name, cm.options.keyMap, handle, cm) - } - - // Note that, despite the name, this function is also used to check - // for bound mouse clicks. - - var stopSeq = new Delayed; - - function dispatchKey(cm, name, e, handle) { - var seq = cm.state.keySeq; - if (seq) { - if (isModifierKey(name)) { return "handled" } - if (/\'$/.test(name)) - { cm.state.keySeq = null; } - else - { stopSeq.set(50, function () { - if (cm.state.keySeq == seq) { - cm.state.keySeq = null; - cm.display.input.reset(); - } - }); } - if (dispatchKeyInner(cm, seq + " " + name, e, handle)) { return true } - } - return dispatchKeyInner(cm, name, e, handle) - } - - function dispatchKeyInner(cm, name, e, handle) { - var result = lookupKeyForEditor(cm, name, handle); - - if (result == "multi") - { cm.state.keySeq = name; } - if (result == "handled") - { signalLater(cm, "keyHandled", cm, name, e); } - - if (result == "handled" || result == "multi") { - e_preventDefault(e); - restartBlink(cm); - } - - return !!result - } - - // Handle a key from the keydown event. - function handleKeyBinding(cm, e) { - var name = keyName(e, true); - if (!name) { return false } - - if (e.shiftKey && !cm.state.keySeq) { - // First try to resolve full name (including 'Shift-'). Failing - // that, see if there is a cursor-motion command (starting with - // 'go') bound to the keyname without 'Shift-'. - return dispatchKey(cm, "Shift-" + name, e, function (b) { return doHandleBinding(cm, b, true); }) - || dispatchKey(cm, name, e, function (b) { - if (typeof b == "string" ? /^go[A-Z]/.test(b) : b.motion) - { return doHandleBinding(cm, b) } - }) - } else { - return dispatchKey(cm, name, e, function (b) { return doHandleBinding(cm, b); }) - } - } - - // Handle a key from the keypress event - function handleCharBinding(cm, e, ch) { - return dispatchKey(cm, "'" + ch + "'", e, function (b) { return doHandleBinding(cm, b, true); }) - } - - var lastStoppedKey = null; - function onKeyDown(e) { - var cm = this; - if (e.target && e.target != cm.display.input.getField()) { return } - cm.curOp.focus = activeElt(); - if (signalDOMEvent(cm, e)) { return } - // IE does strange things with escape. - if (ie && ie_version < 11 && e.keyCode == 27) { e.returnValue = false; } - var code = e.keyCode; - cm.display.shift = code == 16 || e.shiftKey; - var handled = handleKeyBinding(cm, e); - if (presto) { - lastStoppedKey = handled ? code : null; - // Opera has no cut event... we try to at least catch the key combo - if (!handled && code == 88 && !hasCopyEvent && (mac ? e.metaKey : e.ctrlKey)) - { cm.replaceSelection("", null, "cut"); } - } - if (gecko && !mac && !handled && code == 46 && e.shiftKey && !e.ctrlKey && document.execCommand) - { document.execCommand("cut"); } - - // Turn mouse into crosshair when Alt is held on Mac. - if (code == 18 && !/\bCodeMirror-crosshair\b/.test(cm.display.lineDiv.className)) - { showCrossHair(cm); } - } - - function showCrossHair(cm) { - var lineDiv = cm.display.lineDiv; - addClass(lineDiv, "CodeMirror-crosshair"); - - function up(e) { - if (e.keyCode == 18 || !e.altKey) { - rmClass(lineDiv, "CodeMirror-crosshair"); - off(document, "keyup", up); - off(document, "mouseover", up); - } - } - on(document, "keyup", up); - on(document, "mouseover", up); - } - - function onKeyUp(e) { - if (e.keyCode == 16) { this.doc.sel.shift = false; } - signalDOMEvent(this, e); - } - - function onKeyPress(e) { - var cm = this; - if (e.target && e.target != cm.display.input.getField()) { return } - if (eventInWidget(cm.display, e) || signalDOMEvent(cm, e) || e.ctrlKey && !e.altKey || mac && e.metaKey) { return } - var keyCode = e.keyCode, charCode = e.charCode; - if (presto && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return} - if ((presto && (!e.which || e.which < 10)) && handleKeyBinding(cm, e)) { return } - var ch = String.fromCharCode(charCode == null ? keyCode : charCode); - // Some browsers fire keypress events for backspace - if (ch == "\x08") { return } - if (handleCharBinding(cm, e, ch)) { return } - cm.display.input.onKeyPress(e); - } - - var DOUBLECLICK_DELAY = 400; - - var PastClick = function(time, pos, button) { - this.time = time; - this.pos = pos; - this.button = button; - }; - - PastClick.prototype.compare = function (time, pos, button) { - return this.time + DOUBLECLICK_DELAY > time && - cmp(pos, this.pos) == 0 && button == this.button - }; - - var lastClick, lastDoubleClick; - function clickRepeat(pos, button) { - var now = +new Date; - if (lastDoubleClick && lastDoubleClick.compare(now, pos, button)) { - lastClick = lastDoubleClick = null; - return "triple" - } else if (lastClick && lastClick.compare(now, pos, button)) { - lastDoubleClick = new PastClick(now, pos, button); - lastClick = null; - return "double" - } else { - lastClick = new PastClick(now, pos, button); - lastDoubleClick = null; - return "single" - } - } - - // A mouse down can be a single click, double click, triple click, - // start of selection drag, start of text drag, new cursor - // (ctrl-click), rectangle drag (alt-drag), or xwin - // middle-click-paste. Or it might be a click on something we should - // not interfere with, such as a scrollbar or widget. - function onMouseDown(e) { - var cm = this, display = cm.display; - if (signalDOMEvent(cm, e) || display.activeTouch && display.input.supportsTouch()) { return } - display.input.ensurePolled(); - display.shift = e.shiftKey; - - if (eventInWidget(display, e)) { - if (!webkit) { - // Briefly turn off draggability, to allow widgets to do - // normal dragging things. - display.scroller.draggable = false; - setTimeout(function () { return display.scroller.draggable = true; }, 100); - } - return - } - if (clickInGutter(cm, e)) { return } - var pos = posFromMouse(cm, e), button = e_button(e), repeat = pos ? clickRepeat(pos, button) : "single"; - window.focus(); - - // #3261: make sure, that we're not starting a second selection - if (button == 1 && cm.state.selectingText) - { cm.state.selectingText(e); } - - if (pos && handleMappedButton(cm, button, pos, repeat, e)) { return } - - if (button == 1) { - if (pos) { leftButtonDown(cm, pos, repeat, e); } - else if (e_target(e) == display.scroller) { e_preventDefault(e); } - } else if (button == 2) { - if (pos) { extendSelection(cm.doc, pos); } - setTimeout(function () { return display.input.focus(); }, 20); - } else if (button == 3) { - if (captureRightClick) { cm.display.input.onContextMenu(e); } - else { delayBlurEvent(cm); } - } - } - - function handleMappedButton(cm, button, pos, repeat, event) { - var name = "Click"; - if (repeat == "double") { name = "Double" + name; } - else if (repeat == "triple") { name = "Triple" + name; } - name = (button == 1 ? "Left" : button == 2 ? "Middle" : "Right") + name; - - return dispatchKey(cm, addModifierNames(name, event), event, function (bound) { - if (typeof bound == "string") { bound = commands[bound]; } - if (!bound) { return false } - var done = false; - try { - if (cm.isReadOnly()) { cm.state.suppressEdits = true; } - done = bound(cm, pos) != Pass; - } finally { - cm.state.suppressEdits = false; - } - return done - }) - } - - function configureMouse(cm, repeat, event) { - var option = cm.getOption("configureMouse"); - var value = option ? option(cm, repeat, event) : {}; - if (value.unit == null) { - var rect = chromeOS ? event.shiftKey && event.metaKey : event.altKey; - value.unit = rect ? "rectangle" : repeat == "single" ? "char" : repeat == "double" ? "word" : "line"; - } - if (value.extend == null || cm.doc.extend) { value.extend = cm.doc.extend || event.shiftKey; } - if (value.addNew == null) { value.addNew = mac ? event.metaKey : event.ctrlKey; } - if (value.moveOnDrag == null) { value.moveOnDrag = !(mac ? event.altKey : event.ctrlKey); } - return value - } - - function leftButtonDown(cm, pos, repeat, event) { - if (ie) { setTimeout(bind(ensureFocus, cm), 0); } - else { cm.curOp.focus = activeElt(); } - - var behavior = configureMouse(cm, repeat, event); - - var sel = cm.doc.sel, contained; - if (cm.options.dragDrop && dragAndDrop && !cm.isReadOnly() && - repeat == "single" && (contained = sel.contains(pos)) > -1 && - (cmp((contained = sel.ranges[contained]).from(), pos) < 0 || pos.xRel > 0) && - (cmp(contained.to(), pos) > 0 || pos.xRel < 0)) - { leftButtonStartDrag(cm, event, pos, behavior); } - else - { leftButtonSelect(cm, event, pos, behavior); } - } - - // Start a text drag. When it ends, see if any dragging actually - // happen, and treat as a click if it didn't. - function leftButtonStartDrag(cm, event, pos, behavior) { - var display = cm.display, moved = false; - var dragEnd = operation(cm, function (e) { - if (webkit) { display.scroller.draggable = false; } - cm.state.draggingText = false; - if (cm.state.delayingBlurEvent) { - if (cm.hasFocus()) { cm.state.delayingBlurEvent = false; } - else { delayBlurEvent(cm); } - } - off(display.wrapper.ownerDocument, "mouseup", dragEnd); - off(display.wrapper.ownerDocument, "mousemove", mouseMove); - off(display.scroller, "dragstart", dragStart); - off(display.scroller, "drop", dragEnd); - if (!moved) { - e_preventDefault(e); - if (!behavior.addNew) - { extendSelection(cm.doc, pos, null, null, behavior.extend); } - // Work around unexplainable focus problem in IE9 (#2127) and Chrome (#3081) - if ((webkit && !safari) || ie && ie_version == 9) - { setTimeout(function () {display.wrapper.ownerDocument.body.focus({preventScroll: true}); display.input.focus();}, 20); } - else - { display.input.focus(); } - } - }); - var mouseMove = function(e2) { - moved = moved || Math.abs(event.clientX - e2.clientX) + Math.abs(event.clientY - e2.clientY) >= 10; - }; - var dragStart = function () { return moved = true; }; - // Let the drag handler handle this. - if (webkit) { display.scroller.draggable = true; } - cm.state.draggingText = dragEnd; - dragEnd.copy = !behavior.moveOnDrag; - on(display.wrapper.ownerDocument, "mouseup", dragEnd); - on(display.wrapper.ownerDocument, "mousemove", mouseMove); - on(display.scroller, "dragstart", dragStart); - on(display.scroller, "drop", dragEnd); - - cm.state.delayingBlurEvent = true; - setTimeout(function () { return display.input.focus(); }, 20); - // IE's approach to draggable - if (display.scroller.dragDrop) { display.scroller.dragDrop(); } - } - - function rangeForUnit(cm, pos, unit) { - if (unit == "char") { return new Range(pos, pos) } - if (unit == "word") { return cm.findWordAt(pos) } - if (unit == "line") { return new Range(Pos(pos.line, 0), clipPos(cm.doc, Pos(pos.line + 1, 0))) } - var result = unit(cm, pos); - return new Range(result.from, result.to) - } - - // Normal selection, as opposed to text dragging. - function leftButtonSelect(cm, event, start, behavior) { - if (ie) { delayBlurEvent(cm); } - var display = cm.display, doc = cm.doc; - e_preventDefault(event); - - var ourRange, ourIndex, startSel = doc.sel, ranges = startSel.ranges; - if (behavior.addNew && !behavior.extend) { - ourIndex = doc.sel.contains(start); - if (ourIndex > -1) - { ourRange = ranges[ourIndex]; } - else - { ourRange = new Range(start, start); } - } else { - ourRange = doc.sel.primary(); - ourIndex = doc.sel.primIndex; - } - - if (behavior.unit == "rectangle") { - if (!behavior.addNew) { ourRange = new Range(start, start); } - start = posFromMouse(cm, event, true, true); - ourIndex = -1; - } else { - var range = rangeForUnit(cm, start, behavior.unit); - if (behavior.extend) - { ourRange = extendRange(ourRange, range.anchor, range.head, behavior.extend); } - else - { ourRange = range; } - } - - if (!behavior.addNew) { - ourIndex = 0; - setSelection(doc, new Selection([ourRange], 0), sel_mouse); - startSel = doc.sel; - } else if (ourIndex == -1) { - ourIndex = ranges.length; - setSelection(doc, normalizeSelection(cm, ranges.concat([ourRange]), ourIndex), - {scroll: false, origin: "*mouse"}); - } else if (ranges.length > 1 && ranges[ourIndex].empty() && behavior.unit == "char" && !behavior.extend) { - setSelection(doc, normalizeSelection(cm, ranges.slice(0, ourIndex).concat(ranges.slice(ourIndex + 1)), 0), - {scroll: false, origin: "*mouse"}); - startSel = doc.sel; - } else { - replaceOneSelection(doc, ourIndex, ourRange, sel_mouse); - } - - var lastPos = start; - function extendTo(pos) { - if (cmp(lastPos, pos) == 0) { return } - lastPos = pos; - - if (behavior.unit == "rectangle") { - var ranges = [], tabSize = cm.options.tabSize; - var startCol = countColumn(getLine(doc, start.line).text, start.ch, tabSize); - var posCol = countColumn(getLine(doc, pos.line).text, pos.ch, tabSize); - var left = Math.min(startCol, posCol), right = Math.max(startCol, posCol); - for (var line = Math.min(start.line, pos.line), end = Math.min(cm.lastLine(), Math.max(start.line, pos.line)); - line <= end; line++) { - var text = getLine(doc, line).text, leftPos = findColumn(text, left, tabSize); - if (left == right) - { ranges.push(new Range(Pos(line, leftPos), Pos(line, leftPos))); } - else if (text.length > leftPos) - { ranges.push(new Range(Pos(line, leftPos), Pos(line, findColumn(text, right, tabSize)))); } - } - if (!ranges.length) { ranges.push(new Range(start, start)); } - setSelection(doc, normalizeSelection(cm, startSel.ranges.slice(0, ourIndex).concat(ranges), ourIndex), - {origin: "*mouse", scroll: false}); - cm.scrollIntoView(pos); - } else { - var oldRange = ourRange; - var range = rangeForUnit(cm, pos, behavior.unit); - var anchor = oldRange.anchor, head; - if (cmp(range.anchor, anchor) > 0) { - head = range.head; - anchor = minPos(oldRange.from(), range.anchor); - } else { - head = range.anchor; - anchor = maxPos(oldRange.to(), range.head); - } - var ranges$1 = startSel.ranges.slice(0); - ranges$1[ourIndex] = bidiSimplify(cm, new Range(clipPos(doc, anchor), head)); - setSelection(doc, normalizeSelection(cm, ranges$1, ourIndex), sel_mouse); - } - } - - var editorSize = display.wrapper.getBoundingClientRect(); - // Used to ensure timeout re-tries don't fire when another extend - // happened in the meantime (clearTimeout isn't reliable -- at - // least on Chrome, the timeouts still happen even when cleared, - // if the clear happens after their scheduled firing time). - var counter = 0; - - function extend(e) { - var curCount = ++counter; - var cur = posFromMouse(cm, e, true, behavior.unit == "rectangle"); - if (!cur) { return } - if (cmp(cur, lastPos) != 0) { - cm.curOp.focus = activeElt(); - extendTo(cur); - var visible = visibleLines(display, doc); - if (cur.line >= visible.to || cur.line < visible.from) - { setTimeout(operation(cm, function () {if (counter == curCount) { extend(e); }}), 150); } - } else { - var outside = e.clientY < editorSize.top ? -20 : e.clientY > editorSize.bottom ? 20 : 0; - if (outside) { setTimeout(operation(cm, function () { - if (counter != curCount) { return } - display.scroller.scrollTop += outside; - extend(e); - }), 50); } - } - } - - function done(e) { - cm.state.selectingText = false; - counter = Infinity; - // If e is null or undefined we interpret this as someone trying - // to explicitly cancel the selection rather than the user - // letting go of the mouse button. - if (e) { - e_preventDefault(e); - display.input.focus(); - } - off(display.wrapper.ownerDocument, "mousemove", move); - off(display.wrapper.ownerDocument, "mouseup", up); - doc.history.lastSelOrigin = null; - } - - var move = operation(cm, function (e) { - if (e.buttons === 0 || !e_button(e)) { done(e); } - else { extend(e); } - }); - var up = operation(cm, done); - cm.state.selectingText = up; - on(display.wrapper.ownerDocument, "mousemove", move); - on(display.wrapper.ownerDocument, "mouseup", up); - } - - // Used when mouse-selecting to adjust the anchor to the proper side - // of a bidi jump depending on the visual position of the head. - function bidiSimplify(cm, range) { - var anchor = range.anchor; - var head = range.head; - var anchorLine = getLine(cm.doc, anchor.line); - if (cmp(anchor, head) == 0 && anchor.sticky == head.sticky) { return range } - var order = getOrder(anchorLine); - if (!order) { return range } - var index = getBidiPartAt(order, anchor.ch, anchor.sticky), part = order[index]; - if (part.from != anchor.ch && part.to != anchor.ch) { return range } - var boundary = index + ((part.from == anchor.ch) == (part.level != 1) ? 0 : 1); - if (boundary == 0 || boundary == order.length) { return range } - - // Compute the relative visual position of the head compared to the - // anchor (<0 is to the left, >0 to the right) - var leftSide; - if (head.line != anchor.line) { - leftSide = (head.line - anchor.line) * (cm.doc.direction == "ltr" ? 1 : -1) > 0; - } else { - var headIndex = getBidiPartAt(order, head.ch, head.sticky); - var dir = headIndex - index || (head.ch - anchor.ch) * (part.level == 1 ? -1 : 1); - if (headIndex == boundary - 1 || headIndex == boundary) - { leftSide = dir < 0; } - else - { leftSide = dir > 0; } - } - - var usePart = order[boundary + (leftSide ? -1 : 0)]; - var from = leftSide == (usePart.level == 1); - var ch = from ? usePart.from : usePart.to, sticky = from ? "after" : "before"; - return anchor.ch == ch && anchor.sticky == sticky ? range : new Range(new Pos(anchor.line, ch, sticky), head) - } - - - // Determines whether an event happened in the gutter, and fires the - // handlers for the corresponding event. - function gutterEvent(cm, e, type, prevent) { - var mX, mY; - if (e.touches) { - mX = e.touches[0].clientX; - mY = e.touches[0].clientY; - } else { - try { mX = e.clientX; mY = e.clientY; } - catch(e$1) { return false } - } - if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) { return false } - if (prevent) { e_preventDefault(e); } - - var display = cm.display; - var lineBox = display.lineDiv.getBoundingClientRect(); - - if (mY > lineBox.bottom || !hasHandler(cm, type)) { return e_defaultPrevented(e) } - mY -= lineBox.top - display.viewOffset; - - for (var i = 0; i < cm.display.gutterSpecs.length; ++i) { - var g = display.gutters.childNodes[i]; - if (g && g.getBoundingClientRect().right >= mX) { - var line = lineAtHeight(cm.doc, mY); - var gutter = cm.display.gutterSpecs[i]; - signal(cm, type, cm, line, gutter.className, e); - return e_defaultPrevented(e) - } - } - } - - function clickInGutter(cm, e) { - return gutterEvent(cm, e, "gutterClick", true) - } - - // CONTEXT MENU HANDLING - - // To make the context menu work, we need to briefly unhide the - // textarea (making it as unobtrusive as possible) to let the - // right-click take effect on it. - function onContextMenu(cm, e) { - if (eventInWidget(cm.display, e) || contextMenuInGutter(cm, e)) { return } - if (signalDOMEvent(cm, e, "contextmenu")) { return } - if (!captureRightClick) { cm.display.input.onContextMenu(e); } - } - - function contextMenuInGutter(cm, e) { - if (!hasHandler(cm, "gutterContextMenu")) { return false } - return gutterEvent(cm, e, "gutterContextMenu", false) - } - - function themeChanged(cm) { - cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-s-\S+/g, "") + - cm.options.theme.replace(/(^|\s)\s*/g, " cm-s-"); - clearCaches(cm); - } - - var Init = {toString: function(){return "CodeMirror.Init"}}; - - var defaults = {}; - var optionHandlers = {}; - - function defineOptions(CodeMirror) { - var optionHandlers = CodeMirror.optionHandlers; - - function option(name, deflt, handle, notOnInit) { - CodeMirror.defaults[name] = deflt; - if (handle) { optionHandlers[name] = - notOnInit ? function (cm, val, old) {if (old != Init) { handle(cm, val, old); }} : handle; } - } - - CodeMirror.defineOption = option; - - // Passed to option handlers when there is no old value. - CodeMirror.Init = Init; - - // These two are, on init, called from the constructor because they - // have to be initialized before the editor can start at all. - option("value", "", function (cm, val) { return cm.setValue(val); }, true); - option("mode", null, function (cm, val) { - cm.doc.modeOption = val; - loadMode(cm); - }, true); - - option("indentUnit", 2, loadMode, true); - option("indentWithTabs", false); - option("smartIndent", true); - option("tabSize", 4, function (cm) { - resetModeState(cm); - clearCaches(cm); - regChange(cm); - }, true); - - option("lineSeparator", null, function (cm, val) { - cm.doc.lineSep = val; - if (!val) { return } - var newBreaks = [], lineNo = cm.doc.first; - cm.doc.iter(function (line) { - for (var pos = 0;;) { - var found = line.text.indexOf(val, pos); - if (found == -1) { break } - pos = found + val.length; - newBreaks.push(Pos(lineNo, found)); - } - lineNo++; - }); - for (var i = newBreaks.length - 1; i >= 0; i--) - { replaceRange(cm.doc, val, newBreaks[i], Pos(newBreaks[i].line, newBreaks[i].ch + val.length)); } - }); - option("specialChars", /[\u0000-\u001f\u007f-\u009f\u00ad\u061c\u200b\u200e\u200f\u2028\u2029\ufeff\ufff9-\ufffc]/g, function (cm, val, old) { - cm.state.specialChars = new RegExp(val.source + (val.test("\t") ? "" : "|\t"), "g"); - if (old != Init) { cm.refresh(); } - }); - option("specialCharPlaceholder", defaultSpecialCharPlaceholder, function (cm) { return cm.refresh(); }, true); - option("electricChars", true); - option("inputStyle", mobile ? "contenteditable" : "textarea", function () { - throw new Error("inputStyle can not (yet) be changed in a running editor") // FIXME - }, true); - option("spellcheck", false, function (cm, val) { return cm.getInputField().spellcheck = val; }, true); - option("autocorrect", false, function (cm, val) { return cm.getInputField().autocorrect = val; }, true); - option("autocapitalize", false, function (cm, val) { return cm.getInputField().autocapitalize = val; }, true); - option("rtlMoveVisually", !windows); - option("wholeLineUpdateBefore", true); - - option("theme", "default", function (cm) { - themeChanged(cm); - updateGutters(cm); - }, true); - option("keyMap", "default", function (cm, val, old) { - var next = getKeyMap(val); - var prev = old != Init && getKeyMap(old); - if (prev && prev.detach) { prev.detach(cm, next); } - if (next.attach) { next.attach(cm, prev || null); } - }); - option("extraKeys", null); - option("configureMouse", null); - - option("lineWrapping", false, wrappingChanged, true); - option("gutters", [], function (cm, val) { - cm.display.gutterSpecs = getGutters(val, cm.options.lineNumbers); - updateGutters(cm); - }, true); - option("fixedGutter", true, function (cm, val) { - cm.display.gutters.style.left = val ? compensateForHScroll(cm.display) + "px" : "0"; - cm.refresh(); - }, true); - option("coverGutterNextToScrollbar", false, function (cm) { return updateScrollbars(cm); }, true); - option("scrollbarStyle", "native", function (cm) { - initScrollbars(cm); - updateScrollbars(cm); - cm.display.scrollbars.setScrollTop(cm.doc.scrollTop); - cm.display.scrollbars.setScrollLeft(cm.doc.scrollLeft); - }, true); - option("lineNumbers", false, function (cm, val) { - cm.display.gutterSpecs = getGutters(cm.options.gutters, val); - updateGutters(cm); - }, true); - option("firstLineNumber", 1, updateGutters, true); - option("lineNumberFormatter", function (integer) { return integer; }, updateGutters, true); - option("showCursorWhenSelecting", false, updateSelection, true); - - option("resetSelectionOnContextMenu", true); - option("lineWiseCopyCut", true); - option("pasteLinesPerSelection", true); - option("selectionsMayTouch", false); - - option("readOnly", false, function (cm, val) { - if (val == "nocursor") { - onBlur(cm); - cm.display.input.blur(); - } - cm.display.input.readOnlyChanged(val); - }); - - option("screenReaderLabel", null, function (cm, val) { - val = (val === '') ? null : val; - cm.display.input.screenReaderLabelChanged(val); - }); - - option("disableInput", false, function (cm, val) {if (!val) { cm.display.input.reset(); }}, true); - option("dragDrop", true, dragDropChanged); - option("allowDropFileTypes", null); - - option("cursorBlinkRate", 530); - option("cursorScrollMargin", 0); - option("cursorHeight", 1, updateSelection, true); - option("singleCursorHeightPerLine", true, updateSelection, true); - option("workTime", 100); - option("workDelay", 100); - option("flattenSpans", true, resetModeState, true); - option("addModeClass", false, resetModeState, true); - option("pollInterval", 100); - option("undoDepth", 200, function (cm, val) { return cm.doc.history.undoDepth = val; }); - option("historyEventDelay", 1250); - option("viewportMargin", 10, function (cm) { return cm.refresh(); }, true); - option("maxHighlightLength", 10000, resetModeState, true); - option("moveInputWithCursor", true, function (cm, val) { - if (!val) { cm.display.input.resetPosition(); } - }); - - option("tabindex", null, function (cm, val) { return cm.display.input.getField().tabIndex = val || ""; }); - option("autofocus", null); - option("direction", "ltr", function (cm, val) { return cm.doc.setDirection(val); }, true); - option("phrases", null); - } - - function dragDropChanged(cm, value, old) { - var wasOn = old && old != Init; - if (!value != !wasOn) { - var funcs = cm.display.dragFunctions; - var toggle = value ? on : off; - toggle(cm.display.scroller, "dragstart", funcs.start); - toggle(cm.display.scroller, "dragenter", funcs.enter); - toggle(cm.display.scroller, "dragover", funcs.over); - toggle(cm.display.scroller, "dragleave", funcs.leave); - toggle(cm.display.scroller, "drop", funcs.drop); - } - } - - function wrappingChanged(cm) { - if (cm.options.lineWrapping) { - addClass(cm.display.wrapper, "CodeMirror-wrap"); - cm.display.sizer.style.minWidth = ""; - cm.display.sizerWidth = null; - } else { - rmClass(cm.display.wrapper, "CodeMirror-wrap"); - findMaxLine(cm); - } - estimateLineHeights(cm); - regChange(cm); - clearCaches(cm); - setTimeout(function () { return updateScrollbars(cm); }, 100); - } - - // A CodeMirror instance represents an editor. This is the object - // that user code is usually dealing with. - - function CodeMirror(place, options) { - var this$1 = this; - - if (!(this instanceof CodeMirror)) { return new CodeMirror(place, options) } - - this.options = options = options ? copyObj(options) : {}; - // Determine effective options based on given values and defaults. - copyObj(defaults, options, false); - - var doc = options.value; - if (typeof doc == "string") { doc = new Doc(doc, options.mode, null, options.lineSeparator, options.direction); } - else if (options.mode) { doc.modeOption = options.mode; } - this.doc = doc; - - var input = new CodeMirror.inputStyles[options.inputStyle](this); - var display = this.display = new Display(place, doc, input, options); - display.wrapper.CodeMirror = this; - themeChanged(this); - if (options.lineWrapping) - { this.display.wrapper.className += " CodeMirror-wrap"; } - initScrollbars(this); - - this.state = { - keyMaps: [], // stores maps added by addKeyMap - overlays: [], // highlighting overlays, as added by addOverlay - modeGen: 0, // bumped when mode/overlay changes, used to invalidate highlighting info - overwrite: false, - delayingBlurEvent: false, - focused: false, - suppressEdits: false, // used to disable editing during key handlers when in readOnly mode - pasteIncoming: -1, cutIncoming: -1, // help recognize paste/cut edits in input.poll - selectingText: false, - draggingText: false, - highlight: new Delayed(), // stores highlight worker timeout - keySeq: null, // Unfinished key sequence - specialChars: null - }; - - if (options.autofocus && !mobile) { display.input.focus(); } - - // Override magic textarea content restore that IE sometimes does - // on our hidden textarea on reload - if (ie && ie_version < 11) { setTimeout(function () { return this$1.display.input.reset(true); }, 20); } - - registerEventHandlers(this); - ensureGlobalHandlers(); - - startOperation(this); - this.curOp.forceUpdate = true; - attachDoc(this, doc); - - if ((options.autofocus && !mobile) || this.hasFocus()) - { setTimeout(function () { - if (this$1.hasFocus() && !this$1.state.focused) { onFocus(this$1); } - }, 20); } - else - { onBlur(this); } - - for (var opt in optionHandlers) { if (optionHandlers.hasOwnProperty(opt)) - { optionHandlers[opt](this, options[opt], Init); } } - maybeUpdateLineNumberWidth(this); - if (options.finishInit) { options.finishInit(this); } - for (var i = 0; i < initHooks.length; ++i) { initHooks[i](this); } - endOperation(this); - // Suppress optimizelegibility in Webkit, since it breaks text - // measuring on line wrapping boundaries. - if (webkit && options.lineWrapping && - getComputedStyle(display.lineDiv).textRendering == "optimizelegibility") - { display.lineDiv.style.textRendering = "auto"; } - } - - // The default configuration options. - CodeMirror.defaults = defaults; - // Functions to run when options are changed. - CodeMirror.optionHandlers = optionHandlers; - - // Attach the necessary event handlers when initializing the editor - function registerEventHandlers(cm) { - var d = cm.display; - on(d.scroller, "mousedown", operation(cm, onMouseDown)); - // Older IE's will not fire a second mousedown for a double click - if (ie && ie_version < 11) - { on(d.scroller, "dblclick", operation(cm, function (e) { - if (signalDOMEvent(cm, e)) { return } - var pos = posFromMouse(cm, e); - if (!pos || clickInGutter(cm, e) || eventInWidget(cm.display, e)) { return } - e_preventDefault(e); - var word = cm.findWordAt(pos); - extendSelection(cm.doc, word.anchor, word.head); - })); } - else - { on(d.scroller, "dblclick", function (e) { return signalDOMEvent(cm, e) || e_preventDefault(e); }); } - // Some browsers fire contextmenu *after* opening the menu, at - // which point we can't mess with it anymore. Context menu is - // handled in onMouseDown for these browsers. - on(d.scroller, "contextmenu", function (e) { return onContextMenu(cm, e); }); - on(d.input.getField(), "contextmenu", function (e) { - if (!d.scroller.contains(e.target)) { onContextMenu(cm, e); } - }); - - // Used to suppress mouse event handling when a touch happens - var touchFinished, prevTouch = {end: 0}; - function finishTouch() { - if (d.activeTouch) { - touchFinished = setTimeout(function () { return d.activeTouch = null; }, 1000); - prevTouch = d.activeTouch; - prevTouch.end = +new Date; - } - } - function isMouseLikeTouchEvent(e) { - if (e.touches.length != 1) { return false } - var touch = e.touches[0]; - return touch.radiusX <= 1 && touch.radiusY <= 1 - } - function farAway(touch, other) { - if (other.left == null) { return true } - var dx = other.left - touch.left, dy = other.top - touch.top; - return dx * dx + dy * dy > 20 * 20 - } - on(d.scroller, "touchstart", function (e) { - if (!signalDOMEvent(cm, e) && !isMouseLikeTouchEvent(e) && !clickInGutter(cm, e)) { - d.input.ensurePolled(); - clearTimeout(touchFinished); - var now = +new Date; - d.activeTouch = {start: now, moved: false, - prev: now - prevTouch.end <= 300 ? prevTouch : null}; - if (e.touches.length == 1) { - d.activeTouch.left = e.touches[0].pageX; - d.activeTouch.top = e.touches[0].pageY; - } - } - }); - on(d.scroller, "touchmove", function () { - if (d.activeTouch) { d.activeTouch.moved = true; } - }); - on(d.scroller, "touchend", function (e) { - var touch = d.activeTouch; - if (touch && !eventInWidget(d, e) && touch.left != null && - !touch.moved && new Date - touch.start < 300) { - var pos = cm.coordsChar(d.activeTouch, "page"), range; - if (!touch.prev || farAway(touch, touch.prev)) // Single tap - { range = new Range(pos, pos); } - else if (!touch.prev.prev || farAway(touch, touch.prev.prev)) // Double tap - { range = cm.findWordAt(pos); } - else // Triple tap - { range = new Range(Pos(pos.line, 0), clipPos(cm.doc, Pos(pos.line + 1, 0))); } - cm.setSelection(range.anchor, range.head); - cm.focus(); - e_preventDefault(e); - } - finishTouch(); - }); - on(d.scroller, "touchcancel", finishTouch); - - // Sync scrolling between fake scrollbars and real scrollable - // area, ensure viewport is updated when scrolling. - on(d.scroller, "scroll", function () { - if (d.scroller.clientHeight) { - updateScrollTop(cm, d.scroller.scrollTop); - setScrollLeft(cm, d.scroller.scrollLeft, true); - signal(cm, "scroll", cm); - } - }); - - // Listen to wheel events in order to try and update the viewport on time. - on(d.scroller, "mousewheel", function (e) { return onScrollWheel(cm, e); }); - on(d.scroller, "DOMMouseScroll", function (e) { return onScrollWheel(cm, e); }); - - // Prevent wrapper from ever scrolling - on(d.wrapper, "scroll", function () { return d.wrapper.scrollTop = d.wrapper.scrollLeft = 0; }); - - d.dragFunctions = { - enter: function (e) {if (!signalDOMEvent(cm, e)) { e_stop(e); }}, - over: function (e) {if (!signalDOMEvent(cm, e)) { onDragOver(cm, e); e_stop(e); }}, - start: function (e) { return onDragStart(cm, e); }, - drop: operation(cm, onDrop), - leave: function (e) {if (!signalDOMEvent(cm, e)) { clearDragCursor(cm); }} - }; - - var inp = d.input.getField(); - on(inp, "keyup", function (e) { return onKeyUp.call(cm, e); }); - on(inp, "keydown", operation(cm, onKeyDown)); - on(inp, "keypress", operation(cm, onKeyPress)); - on(inp, "focus", function (e) { return onFocus(cm, e); }); - on(inp, "blur", function (e) { return onBlur(cm, e); }); - } - - var initHooks = []; - CodeMirror.defineInitHook = function (f) { return initHooks.push(f); }; - - // Indent the given line. The how parameter can be "smart", - // "add"/null, "subtract", or "prev". When aggressive is false - // (typically set to true for forced single-line indents), empty - // lines are not indented, and places where the mode returns Pass - // are left alone. - function indentLine(cm, n, how, aggressive) { - var doc = cm.doc, state; - if (how == null) { how = "add"; } - if (how == "smart") { - // Fall back to "prev" when the mode doesn't have an indentation - // method. - if (!doc.mode.indent) { how = "prev"; } - else { state = getContextBefore(cm, n).state; } - } - - var tabSize = cm.options.tabSize; - var line = getLine(doc, n), curSpace = countColumn(line.text, null, tabSize); - if (line.stateAfter) { line.stateAfter = null; } - var curSpaceString = line.text.match(/^\s*/)[0], indentation; - if (!aggressive && !/\S/.test(line.text)) { - indentation = 0; - how = "not"; - } else if (how == "smart") { - indentation = doc.mode.indent(state, line.text.slice(curSpaceString.length), line.text); - if (indentation == Pass || indentation > 150) { - if (!aggressive) { return } - how = "prev"; - } - } - if (how == "prev") { - if (n > doc.first) { indentation = countColumn(getLine(doc, n-1).text, null, tabSize); } - else { indentation = 0; } - } else if (how == "add") { - indentation = curSpace + cm.options.indentUnit; - } else if (how == "subtract") { - indentation = curSpace - cm.options.indentUnit; - } else if (typeof how == "number") { - indentation = curSpace + how; - } - indentation = Math.max(0, indentation); - - var indentString = "", pos = 0; - if (cm.options.indentWithTabs) - { for (var i = Math.floor(indentation / tabSize); i; --i) {pos += tabSize; indentString += "\t";} } - if (pos < indentation) { indentString += spaceStr(indentation - pos); } - - if (indentString != curSpaceString) { - replaceRange(doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), "+input"); - line.stateAfter = null; - return true - } else { - // Ensure that, if the cursor was in the whitespace at the start - // of the line, it is moved to the end of that space. - for (var i$1 = 0; i$1 < doc.sel.ranges.length; i$1++) { - var range = doc.sel.ranges[i$1]; - if (range.head.line == n && range.head.ch < curSpaceString.length) { - var pos$1 = Pos(n, curSpaceString.length); - replaceOneSelection(doc, i$1, new Range(pos$1, pos$1)); - break - } - } - } - } - - // This will be set to a {lineWise: bool, text: [string]} object, so - // that, when pasting, we know what kind of selections the copied - // text was made out of. - var lastCopied = null; - - function setLastCopied(newLastCopied) { - lastCopied = newLastCopied; - } - - function applyTextInput(cm, inserted, deleted, sel, origin) { - var doc = cm.doc; - cm.display.shift = false; - if (!sel) { sel = doc.sel; } - - var recent = +new Date - 200; - var paste = origin == "paste" || cm.state.pasteIncoming > recent; - var textLines = splitLinesAuto(inserted), multiPaste = null; - // When pasting N lines into N selections, insert one line per selection - if (paste && sel.ranges.length > 1) { - if (lastCopied && lastCopied.text.join("\n") == inserted) { - if (sel.ranges.length % lastCopied.text.length == 0) { - multiPaste = []; - for (var i = 0; i < lastCopied.text.length; i++) - { multiPaste.push(doc.splitLines(lastCopied.text[i])); } - } - } else if (textLines.length == sel.ranges.length && cm.options.pasteLinesPerSelection) { - multiPaste = map(textLines, function (l) { return [l]; }); - } - } - - var updateInput = cm.curOp.updateInput; - // Normal behavior is to insert the new text into every selection - for (var i$1 = sel.ranges.length - 1; i$1 >= 0; i$1--) { - var range = sel.ranges[i$1]; - var from = range.from(), to = range.to(); - if (range.empty()) { - if (deleted && deleted > 0) // Handle deletion - { from = Pos(from.line, from.ch - deleted); } - else if (cm.state.overwrite && !paste) // Handle overwrite - { to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + lst(textLines).length)); } - else if (paste && lastCopied && lastCopied.lineWise && lastCopied.text.join("\n") == textLines.join("\n")) - { from = to = Pos(from.line, 0); } - } - var changeEvent = {from: from, to: to, text: multiPaste ? multiPaste[i$1 % multiPaste.length] : textLines, - origin: origin || (paste ? "paste" : cm.state.cutIncoming > recent ? "cut" : "+input")}; - makeChange(cm.doc, changeEvent); - signalLater(cm, "inputRead", cm, changeEvent); - } - if (inserted && !paste) - { triggerElectric(cm, inserted); } - - ensureCursorVisible(cm); - if (cm.curOp.updateInput < 2) { cm.curOp.updateInput = updateInput; } - cm.curOp.typing = true; - cm.state.pasteIncoming = cm.state.cutIncoming = -1; - } - - function handlePaste(e, cm) { - var pasted = e.clipboardData && e.clipboardData.getData("Text"); - if (pasted) { - e.preventDefault(); - if (!cm.isReadOnly() && !cm.options.disableInput) - { runInOp(cm, function () { return applyTextInput(cm, pasted, 0, null, "paste"); }); } - return true - } - } - - function triggerElectric(cm, inserted) { - // When an 'electric' character is inserted, immediately trigger a reindent - if (!cm.options.electricChars || !cm.options.smartIndent) { return } - var sel = cm.doc.sel; - - for (var i = sel.ranges.length - 1; i >= 0; i--) { - var range = sel.ranges[i]; - if (range.head.ch > 100 || (i && sel.ranges[i - 1].head.line == range.head.line)) { continue } - var mode = cm.getModeAt(range.head); - var indented = false; - if (mode.electricChars) { - for (var j = 0; j < mode.electricChars.length; j++) - { if (inserted.indexOf(mode.electricChars.charAt(j)) > -1) { - indented = indentLine(cm, range.head.line, "smart"); - break - } } - } else if (mode.electricInput) { - if (mode.electricInput.test(getLine(cm.doc, range.head.line).text.slice(0, range.head.ch))) - { indented = indentLine(cm, range.head.line, "smart"); } - } - if (indented) { signalLater(cm, "electricInput", cm, range.head.line); } - } - } - - function copyableRanges(cm) { - var text = [], ranges = []; - for (var i = 0; i < cm.doc.sel.ranges.length; i++) { - var line = cm.doc.sel.ranges[i].head.line; - var lineRange = {anchor: Pos(line, 0), head: Pos(line + 1, 0)}; - ranges.push(lineRange); - text.push(cm.getRange(lineRange.anchor, lineRange.head)); - } - return {text: text, ranges: ranges} - } - - function disableBrowserMagic(field, spellcheck, autocorrect, autocapitalize) { - field.setAttribute("autocorrect", autocorrect ? "" : "off"); - field.setAttribute("autocapitalize", autocapitalize ? "" : "off"); - field.setAttribute("spellcheck", !!spellcheck); - } - - function hiddenTextarea() { - var te = elt("textarea", null, null, "position: absolute; bottom: -1em; padding: 0; width: 1px; height: 1em; min-height: 1em; outline: none"); - var div = elt("div", [te], null, "overflow: hidden; position: relative; width: 3px; height: 0px;"); - // The textarea is kept positioned near the cursor to prevent the - // fact that it'll be scrolled into view on input from scrolling - // our fake cursor out of view. On webkit, when wrap=off, paste is - // very slow. So make the area wide instead. - if (webkit) { te.style.width = "1000px"; } - else { te.setAttribute("wrap", "off"); } - // If border: 0; -- iOS fails to open keyboard (issue #1287) - if (ios) { te.style.border = "1px solid black"; } - disableBrowserMagic(te); - return div - } - - // The publicly visible API. Note that methodOp(f) means - // 'wrap f in an operation, performed on its `this` parameter'. - - // This is not the complete set of editor methods. Most of the - // methods defined on the Doc type are also injected into - // CodeMirror.prototype, for backwards compatibility and - // convenience. - - function addEditorMethods(CodeMirror) { - var optionHandlers = CodeMirror.optionHandlers; - - var helpers = CodeMirror.helpers = {}; - - CodeMirror.prototype = { - constructor: CodeMirror, - focus: function(){window.focus(); this.display.input.focus();}, - - setOption: function(option, value) { - var options = this.options, old = options[option]; - if (options[option] == value && option != "mode") { return } - options[option] = value; - if (optionHandlers.hasOwnProperty(option)) - { operation(this, optionHandlers[option])(this, value, old); } - signal(this, "optionChange", this, option); - }, - - getOption: function(option) {return this.options[option]}, - getDoc: function() {return this.doc}, - - addKeyMap: function(map, bottom) { - this.state.keyMaps[bottom ? "push" : "unshift"](getKeyMap(map)); - }, - removeKeyMap: function(map) { - var maps = this.state.keyMaps; - for (var i = 0; i < maps.length; ++i) - { if (maps[i] == map || maps[i].name == map) { - maps.splice(i, 1); - return true - } } - }, - - addOverlay: methodOp(function(spec, options) { - var mode = spec.token ? spec : CodeMirror.getMode(this.options, spec); - if (mode.startState) { throw new Error("Overlays may not be stateful.") } - insertSorted(this.state.overlays, - {mode: mode, modeSpec: spec, opaque: options && options.opaque, - priority: (options && options.priority) || 0}, - function (overlay) { return overlay.priority; }); - this.state.modeGen++; - regChange(this); - }), - removeOverlay: methodOp(function(spec) { - var overlays = this.state.overlays; - for (var i = 0; i < overlays.length; ++i) { - var cur = overlays[i].modeSpec; - if (cur == spec || typeof spec == "string" && cur.name == spec) { - overlays.splice(i, 1); - this.state.modeGen++; - regChange(this); - return - } - } - }), - - indentLine: methodOp(function(n, dir, aggressive) { - if (typeof dir != "string" && typeof dir != "number") { - if (dir == null) { dir = this.options.smartIndent ? "smart" : "prev"; } - else { dir = dir ? "add" : "subtract"; } - } - if (isLine(this.doc, n)) { indentLine(this, n, dir, aggressive); } - }), - indentSelection: methodOp(function(how) { - var ranges = this.doc.sel.ranges, end = -1; - for (var i = 0; i < ranges.length; i++) { - var range = ranges[i]; - if (!range.empty()) { - var from = range.from(), to = range.to(); - var start = Math.max(end, from.line); - end = Math.min(this.lastLine(), to.line - (to.ch ? 0 : 1)) + 1; - for (var j = start; j < end; ++j) - { indentLine(this, j, how); } - var newRanges = this.doc.sel.ranges; - if (from.ch == 0 && ranges.length == newRanges.length && newRanges[i].from().ch > 0) - { replaceOneSelection(this.doc, i, new Range(from, newRanges[i].to()), sel_dontScroll); } - } else if (range.head.line > end) { - indentLine(this, range.head.line, how, true); - end = range.head.line; - if (i == this.doc.sel.primIndex) { ensureCursorVisible(this); } - } - } - }), - - // Fetch the parser token for a given character. Useful for hacks - // that want to inspect the mode state (say, for completion). - getTokenAt: function(pos, precise) { - return takeToken(this, pos, precise) - }, - - getLineTokens: function(line, precise) { - return takeToken(this, Pos(line), precise, true) - }, - - getTokenTypeAt: function(pos) { - pos = clipPos(this.doc, pos); - var styles = getLineStyles(this, getLine(this.doc, pos.line)); - var before = 0, after = (styles.length - 1) / 2, ch = pos.ch; - var type; - if (ch == 0) { type = styles[2]; } - else { for (;;) { - var mid = (before + after) >> 1; - if ((mid ? styles[mid * 2 - 1] : 0) >= ch) { after = mid; } - else if (styles[mid * 2 + 1] < ch) { before = mid + 1; } - else { type = styles[mid * 2 + 2]; break } - } } - var cut = type ? type.indexOf("overlay ") : -1; - return cut < 0 ? type : cut == 0 ? null : type.slice(0, cut - 1) - }, - - getModeAt: function(pos) { - var mode = this.doc.mode; - if (!mode.innerMode) { return mode } - return CodeMirror.innerMode(mode, this.getTokenAt(pos).state).mode - }, - - getHelper: function(pos, type) { - return this.getHelpers(pos, type)[0] - }, - - getHelpers: function(pos, type) { - var found = []; - if (!helpers.hasOwnProperty(type)) { return found } - var help = helpers[type], mode = this.getModeAt(pos); - if (typeof mode[type] == "string") { - if (help[mode[type]]) { found.push(help[mode[type]]); } - } else if (mode[type]) { - for (var i = 0; i < mode[type].length; i++) { - var val = help[mode[type][i]]; - if (val) { found.push(val); } - } - } else if (mode.helperType && help[mode.helperType]) { - found.push(help[mode.helperType]); - } else if (help[mode.name]) { - found.push(help[mode.name]); - } - for (var i$1 = 0; i$1 < help._global.length; i$1++) { - var cur = help._global[i$1]; - if (cur.pred(mode, this) && indexOf(found, cur.val) == -1) - { found.push(cur.val); } - } - return found - }, - - getStateAfter: function(line, precise) { - var doc = this.doc; - line = clipLine(doc, line == null ? doc.first + doc.size - 1: line); - return getContextBefore(this, line + 1, precise).state - }, - - cursorCoords: function(start, mode) { - var pos, range = this.doc.sel.primary(); - if (start == null) { pos = range.head; } - else if (typeof start == "object") { pos = clipPos(this.doc, start); } - else { pos = start ? range.from() : range.to(); } - return cursorCoords(this, pos, mode || "page") - }, - - charCoords: function(pos, mode) { - return charCoords(this, clipPos(this.doc, pos), mode || "page") - }, - - coordsChar: function(coords, mode) { - coords = fromCoordSystem(this, coords, mode || "page"); - return coordsChar(this, coords.left, coords.top) - }, - - lineAtHeight: function(height, mode) { - height = fromCoordSystem(this, {top: height, left: 0}, mode || "page").top; - return lineAtHeight(this.doc, height + this.display.viewOffset) - }, - heightAtLine: function(line, mode, includeWidgets) { - var end = false, lineObj; - if (typeof line == "number") { - var last = this.doc.first + this.doc.size - 1; - if (line < this.doc.first) { line = this.doc.first; } - else if (line > last) { line = last; end = true; } - lineObj = getLine(this.doc, line); - } else { - lineObj = line; - } - return intoCoordSystem(this, lineObj, {top: 0, left: 0}, mode || "page", includeWidgets || end).top + - (end ? this.doc.height - heightAtLine(lineObj) : 0) - }, - - defaultTextHeight: function() { return textHeight(this.display) }, - defaultCharWidth: function() { return charWidth(this.display) }, - - getViewport: function() { return {from: this.display.viewFrom, to: this.display.viewTo}}, - - addWidget: function(pos, node, scroll, vert, horiz) { - var display = this.display; - pos = cursorCoords(this, clipPos(this.doc, pos)); - var top = pos.bottom, left = pos.left; - node.style.position = "absolute"; - node.setAttribute("cm-ignore-events", "true"); - this.display.input.setUneditable(node); - display.sizer.appendChild(node); - if (vert == "over") { - top = pos.top; - } else if (vert == "above" || vert == "near") { - var vspace = Math.max(display.wrapper.clientHeight, this.doc.height), - hspace = Math.max(display.sizer.clientWidth, display.lineSpace.clientWidth); - // Default to positioning above (if specified and possible); otherwise default to positioning below - if ((vert == 'above' || pos.bottom + node.offsetHeight > vspace) && pos.top > node.offsetHeight) - { top = pos.top - node.offsetHeight; } - else if (pos.bottom + node.offsetHeight <= vspace) - { top = pos.bottom; } - if (left + node.offsetWidth > hspace) - { left = hspace - node.offsetWidth; } - } - node.style.top = top + "px"; - node.style.left = node.style.right = ""; - if (horiz == "right") { - left = display.sizer.clientWidth - node.offsetWidth; - node.style.right = "0px"; - } else { - if (horiz == "left") { left = 0; } - else if (horiz == "middle") { left = (display.sizer.clientWidth - node.offsetWidth) / 2; } - node.style.left = left + "px"; - } - if (scroll) - { scrollIntoView(this, {left: left, top: top, right: left + node.offsetWidth, bottom: top + node.offsetHeight}); } - }, - - triggerOnKeyDown: methodOp(onKeyDown), - triggerOnKeyPress: methodOp(onKeyPress), - triggerOnKeyUp: onKeyUp, - triggerOnMouseDown: methodOp(onMouseDown), - - execCommand: function(cmd) { - if (commands.hasOwnProperty(cmd)) - { return commands[cmd].call(null, this) } - }, - - triggerElectric: methodOp(function(text) { triggerElectric(this, text); }), - - findPosH: function(from, amount, unit, visually) { - var dir = 1; - if (amount < 0) { dir = -1; amount = -amount; } - var cur = clipPos(this.doc, from); - for (var i = 0; i < amount; ++i) { - cur = findPosH(this.doc, cur, dir, unit, visually); - if (cur.hitSide) { break } - } - return cur - }, - - moveH: methodOp(function(dir, unit) { - var this$1 = this; - - this.extendSelectionsBy(function (range) { - if (this$1.display.shift || this$1.doc.extend || range.empty()) - { return findPosH(this$1.doc, range.head, dir, unit, this$1.options.rtlMoveVisually) } - else - { return dir < 0 ? range.from() : range.to() } - }, sel_move); - }), - - deleteH: methodOp(function(dir, unit) { - var sel = this.doc.sel, doc = this.doc; - if (sel.somethingSelected()) - { doc.replaceSelection("", null, "+delete"); } - else - { deleteNearSelection(this, function (range) { - var other = findPosH(doc, range.head, dir, unit, false); - return dir < 0 ? {from: other, to: range.head} : {from: range.head, to: other} - }); } - }), - - findPosV: function(from, amount, unit, goalColumn) { - var dir = 1, x = goalColumn; - if (amount < 0) { dir = -1; amount = -amount; } - var cur = clipPos(this.doc, from); - for (var i = 0; i < amount; ++i) { - var coords = cursorCoords(this, cur, "div"); - if (x == null) { x = coords.left; } - else { coords.left = x; } - cur = findPosV(this, coords, dir, unit); - if (cur.hitSide) { break } - } - return cur - }, - - moveV: methodOp(function(dir, unit) { - var this$1 = this; - - var doc = this.doc, goals = []; - var collapse = !this.display.shift && !doc.extend && doc.sel.somethingSelected(); - doc.extendSelectionsBy(function (range) { - if (collapse) - { return dir < 0 ? range.from() : range.to() } - var headPos = cursorCoords(this$1, range.head, "div"); - if (range.goalColumn != null) { headPos.left = range.goalColumn; } - goals.push(headPos.left); - var pos = findPosV(this$1, headPos, dir, unit); - if (unit == "page" && range == doc.sel.primary()) - { addToScrollTop(this$1, charCoords(this$1, pos, "div").top - headPos.top); } - return pos - }, sel_move); - if (goals.length) { for (var i = 0; i < doc.sel.ranges.length; i++) - { doc.sel.ranges[i].goalColumn = goals[i]; } } - }), - - // Find the word at the given position (as returned by coordsChar). - findWordAt: function(pos) { - var doc = this.doc, line = getLine(doc, pos.line).text; - var start = pos.ch, end = pos.ch; - if (line) { - var helper = this.getHelper(pos, "wordChars"); - if ((pos.sticky == "before" || end == line.length) && start) { --start; } else { ++end; } - var startChar = line.charAt(start); - var check = isWordChar(startChar, helper) - ? function (ch) { return isWordChar(ch, helper); } - : /\s/.test(startChar) ? function (ch) { return /\s/.test(ch); } - : function (ch) { return (!/\s/.test(ch) && !isWordChar(ch)); }; - while (start > 0 && check(line.charAt(start - 1))) { --start; } - while (end < line.length && check(line.charAt(end))) { ++end; } - } - return new Range(Pos(pos.line, start), Pos(pos.line, end)) - }, - - toggleOverwrite: function(value) { - if (value != null && value == this.state.overwrite) { return } - if (this.state.overwrite = !this.state.overwrite) - { addClass(this.display.cursorDiv, "CodeMirror-overwrite"); } - else - { rmClass(this.display.cursorDiv, "CodeMirror-overwrite"); } - - signal(this, "overwriteToggle", this, this.state.overwrite); - }, - hasFocus: function() { return this.display.input.getField() == activeElt() }, - isReadOnly: function() { return !!(this.options.readOnly || this.doc.cantEdit) }, - - scrollTo: methodOp(function (x, y) { scrollToCoords(this, x, y); }), - getScrollInfo: function() { - var scroller = this.display.scroller; - return {left: scroller.scrollLeft, top: scroller.scrollTop, - height: scroller.scrollHeight - scrollGap(this) - this.display.barHeight, - width: scroller.scrollWidth - scrollGap(this) - this.display.barWidth, - clientHeight: displayHeight(this), clientWidth: displayWidth(this)} - }, - - scrollIntoView: methodOp(function(range, margin) { - if (range == null) { - range = {from: this.doc.sel.primary().head, to: null}; - if (margin == null) { margin = this.options.cursorScrollMargin; } - } else if (typeof range == "number") { - range = {from: Pos(range, 0), to: null}; - } else if (range.from == null) { - range = {from: range, to: null}; - } - if (!range.to) { range.to = range.from; } - range.margin = margin || 0; - - if (range.from.line != null) { - scrollToRange(this, range); - } else { - scrollToCoordsRange(this, range.from, range.to, range.margin); - } - }), - - setSize: methodOp(function(width, height) { - var this$1 = this; - - var interpret = function (val) { return typeof val == "number" || /^\d+$/.test(String(val)) ? val + "px" : val; }; - if (width != null) { this.display.wrapper.style.width = interpret(width); } - if (height != null) { this.display.wrapper.style.height = interpret(height); } - if (this.options.lineWrapping) { clearLineMeasurementCache(this); } - var lineNo = this.display.viewFrom; - this.doc.iter(lineNo, this.display.viewTo, function (line) { - if (line.widgets) { for (var i = 0; i < line.widgets.length; i++) - { if (line.widgets[i].noHScroll) { regLineChange(this$1, lineNo, "widget"); break } } } - ++lineNo; - }); - this.curOp.forceUpdate = true; - signal(this, "refresh", this); - }), - - operation: function(f){return runInOp(this, f)}, - startOperation: function(){return startOperation(this)}, - endOperation: function(){return endOperation(this)}, - - refresh: methodOp(function() { - var oldHeight = this.display.cachedTextHeight; - regChange(this); - this.curOp.forceUpdate = true; - clearCaches(this); - scrollToCoords(this, this.doc.scrollLeft, this.doc.scrollTop); - updateGutterSpace(this.display); - if (oldHeight == null || Math.abs(oldHeight - textHeight(this.display)) > .5 || this.options.lineWrapping) - { estimateLineHeights(this); } - signal(this, "refresh", this); - }), - - swapDoc: methodOp(function(doc) { - var old = this.doc; - old.cm = null; - // Cancel the current text selection if any (#5821) - if (this.state.selectingText) { this.state.selectingText(); } - attachDoc(this, doc); - clearCaches(this); - this.display.input.reset(); - scrollToCoords(this, doc.scrollLeft, doc.scrollTop); - this.curOp.forceScroll = true; - signalLater(this, "swapDoc", this, old); - return old - }), - - phrase: function(phraseText) { - var phrases = this.options.phrases; - return phrases && Object.prototype.hasOwnProperty.call(phrases, phraseText) ? phrases[phraseText] : phraseText - }, - - getInputField: function(){return this.display.input.getField()}, - getWrapperElement: function(){return this.display.wrapper}, - getScrollerElement: function(){return this.display.scroller}, - getGutterElement: function(){return this.display.gutters} - }; - eventMixin(CodeMirror); - - CodeMirror.registerHelper = function(type, name, value) { - if (!helpers.hasOwnProperty(type)) { helpers[type] = CodeMirror[type] = {_global: []}; } - helpers[type][name] = value; - }; - CodeMirror.registerGlobalHelper = function(type, name, predicate, value) { - CodeMirror.registerHelper(type, name, value); - helpers[type]._global.push({pred: predicate, val: value}); - }; - } - - // Used for horizontal relative motion. Dir is -1 or 1 (left or - // right), unit can be "codepoint", "char", "column" (like char, but - // doesn't cross line boundaries), "word" (across next word), or - // "group" (to the start of next group of word or - // non-word-non-whitespace chars). The visually param controls - // whether, in right-to-left text, direction 1 means to move towards - // the next index in the string, or towards the character to the right - // of the current position. The resulting position will have a - // hitSide=true property if it reached the end of the document. - function findPosH(doc, pos, dir, unit, visually) { - var oldPos = pos; - var origDir = dir; - var lineObj = getLine(doc, pos.line); - var lineDir = visually && doc.direction == "rtl" ? -dir : dir; - function findNextLine() { - var l = pos.line + lineDir; - if (l < doc.first || l >= doc.first + doc.size) { return false } - pos = new Pos(l, pos.ch, pos.sticky); - return lineObj = getLine(doc, l) - } - function moveOnce(boundToLine) { - var next; - if (unit == "codepoint") { - var ch = lineObj.text.charCodeAt(pos.ch + (dir > 0 ? 0 : -1)); - if (isNaN(ch)) { - next = null; - } else { - var astral = dir > 0 ? ch >= 0xD800 && ch < 0xDC00 : ch >= 0xDC00 && ch < 0xDFFF; - next = new Pos(pos.line, Math.max(0, Math.min(lineObj.text.length, pos.ch + dir * (astral ? 2 : 1))), -dir); - } - } else if (visually) { - next = moveVisually(doc.cm, lineObj, pos, dir); - } else { - next = moveLogically(lineObj, pos, dir); - } - if (next == null) { - if (!boundToLine && findNextLine()) - { pos = endOfLine(visually, doc.cm, lineObj, pos.line, lineDir); } - else - { return false } - } else { - pos = next; - } - return true - } - - if (unit == "char" || unit == "codepoint") { - moveOnce(); - } else if (unit == "column") { - moveOnce(true); - } else if (unit == "word" || unit == "group") { - var sawType = null, group = unit == "group"; - var helper = doc.cm && doc.cm.getHelper(pos, "wordChars"); - for (var first = true;; first = false) { - if (dir < 0 && !moveOnce(!first)) { break } - var cur = lineObj.text.charAt(pos.ch) || "\n"; - var type = isWordChar(cur, helper) ? "w" - : group && cur == "\n" ? "n" - : !group || /\s/.test(cur) ? null - : "p"; - if (group && !first && !type) { type = "s"; } - if (sawType && sawType != type) { - if (dir < 0) {dir = 1; moveOnce(); pos.sticky = "after";} - break - } - - if (type) { sawType = type; } - if (dir > 0 && !moveOnce(!first)) { break } - } - } - var result = skipAtomic(doc, pos, oldPos, origDir, true); - if (equalCursorPos(oldPos, result)) { result.hitSide = true; } - return result - } - - // For relative vertical movement. Dir may be -1 or 1. Unit can be - // "page" or "line". The resulting position will have a hitSide=true - // property if it reached the end of the document. - function findPosV(cm, pos, dir, unit) { - var doc = cm.doc, x = pos.left, y; - if (unit == "page") { - var pageSize = Math.min(cm.display.wrapper.clientHeight, window.innerHeight || document.documentElement.clientHeight); - var moveAmount = Math.max(pageSize - .5 * textHeight(cm.display), 3); - y = (dir > 0 ? pos.bottom : pos.top) + dir * moveAmount; - - } else if (unit == "line") { - y = dir > 0 ? pos.bottom + 3 : pos.top - 3; - } - var target; - for (;;) { - target = coordsChar(cm, x, y); - if (!target.outside) { break } - if (dir < 0 ? y <= 0 : y >= doc.height) { target.hitSide = true; break } - y += dir * 5; - } - return target - } - - // CONTENTEDITABLE INPUT STYLE - - var ContentEditableInput = function(cm) { - this.cm = cm; - this.lastAnchorNode = this.lastAnchorOffset = this.lastFocusNode = this.lastFocusOffset = null; - this.polling = new Delayed(); - this.composing = null; - this.gracePeriod = false; - this.readDOMTimeout = null; - }; - - ContentEditableInput.prototype.init = function (display) { - var this$1 = this; - - var input = this, cm = input.cm; - var div = input.div = display.lineDiv; - div.contentEditable = true; - disableBrowserMagic(div, cm.options.spellcheck, cm.options.autocorrect, cm.options.autocapitalize); - - function belongsToInput(e) { - for (var t = e.target; t; t = t.parentNode) { - if (t == div) { return true } - if (/\bCodeMirror-(?:line)?widget\b/.test(t.className)) { break } - } - return false - } - - on(div, "paste", function (e) { - if (!belongsToInput(e) || signalDOMEvent(cm, e) || handlePaste(e, cm)) { return } - // IE doesn't fire input events, so we schedule a read for the pasted content in this way - if (ie_version <= 11) { setTimeout(operation(cm, function () { return this$1.updateFromDOM(); }), 20); } - }); - - on(div, "compositionstart", function (e) { - this$1.composing = {data: e.data, done: false}; - }); - on(div, "compositionupdate", function (e) { - if (!this$1.composing) { this$1.composing = {data: e.data, done: false}; } - }); - on(div, "compositionend", function (e) { - if (this$1.composing) { - if (e.data != this$1.composing.data) { this$1.readFromDOMSoon(); } - this$1.composing.done = true; - } - }); - - on(div, "touchstart", function () { return input.forceCompositionEnd(); }); - - on(div, "input", function () { - if (!this$1.composing) { this$1.readFromDOMSoon(); } - }); - - function onCopyCut(e) { - if (!belongsToInput(e) || signalDOMEvent(cm, e)) { return } - if (cm.somethingSelected()) { - setLastCopied({lineWise: false, text: cm.getSelections()}); - if (e.type == "cut") { cm.replaceSelection("", null, "cut"); } - } else if (!cm.options.lineWiseCopyCut) { - return - } else { - var ranges = copyableRanges(cm); - setLastCopied({lineWise: true, text: ranges.text}); - if (e.type == "cut") { - cm.operation(function () { - cm.setSelections(ranges.ranges, 0, sel_dontScroll); - cm.replaceSelection("", null, "cut"); - }); - } - } - if (e.clipboardData) { - e.clipboardData.clearData(); - var content = lastCopied.text.join("\n"); - // iOS exposes the clipboard API, but seems to discard content inserted into it - e.clipboardData.setData("Text", content); - if (e.clipboardData.getData("Text") == content) { - e.preventDefault(); - return - } - } - // Old-fashioned briefly-focus-a-textarea hack - var kludge = hiddenTextarea(), te = kludge.firstChild; - cm.display.lineSpace.insertBefore(kludge, cm.display.lineSpace.firstChild); - te.value = lastCopied.text.join("\n"); - var hadFocus = activeElt(); - selectInput(te); - setTimeout(function () { - cm.display.lineSpace.removeChild(kludge); - hadFocus.focus(); - if (hadFocus == div) { input.showPrimarySelection(); } - }, 50); - } - on(div, "copy", onCopyCut); - on(div, "cut", onCopyCut); - }; - - ContentEditableInput.prototype.screenReaderLabelChanged = function (label) { - // Label for screenreaders, accessibility - if(label) { - this.div.setAttribute('aria-label', label); - } else { - this.div.removeAttribute('aria-label'); - } - }; - - ContentEditableInput.prototype.prepareSelection = function () { - var result = prepareSelection(this.cm, false); - result.focus = activeElt() == this.div; - return result - }; - - ContentEditableInput.prototype.showSelection = function (info, takeFocus) { - if (!info || !this.cm.display.view.length) { return } - if (info.focus || takeFocus) { this.showPrimarySelection(); } - this.showMultipleSelections(info); - }; - - ContentEditableInput.prototype.getSelection = function () { - return this.cm.display.wrapper.ownerDocument.getSelection() - }; - - ContentEditableInput.prototype.showPrimarySelection = function () { - var sel = this.getSelection(), cm = this.cm, prim = cm.doc.sel.primary(); - var from = prim.from(), to = prim.to(); - - if (cm.display.viewTo == cm.display.viewFrom || from.line >= cm.display.viewTo || to.line < cm.display.viewFrom) { - sel.removeAllRanges(); - return - } - - var curAnchor = domToPos(cm, sel.anchorNode, sel.anchorOffset); - var curFocus = domToPos(cm, sel.focusNode, sel.focusOffset); - if (curAnchor && !curAnchor.bad && curFocus && !curFocus.bad && - cmp(minPos(curAnchor, curFocus), from) == 0 && - cmp(maxPos(curAnchor, curFocus), to) == 0) - { return } - - var view = cm.display.view; - var start = (from.line >= cm.display.viewFrom && posToDOM(cm, from)) || - {node: view[0].measure.map[2], offset: 0}; - var end = to.line < cm.display.viewTo && posToDOM(cm, to); - if (!end) { - var measure = view[view.length - 1].measure; - var map = measure.maps ? measure.maps[measure.maps.length - 1] : measure.map; - end = {node: map[map.length - 1], offset: map[map.length - 2] - map[map.length - 3]}; - } - - if (!start || !end) { - sel.removeAllRanges(); - return - } - - var old = sel.rangeCount && sel.getRangeAt(0), rng; - try { rng = range(start.node, start.offset, end.offset, end.node); } - catch(e) {} // Our model of the DOM might be outdated, in which case the range we try to set can be impossible - if (rng) { - if (!gecko && cm.state.focused) { - sel.collapse(start.node, start.offset); - if (!rng.collapsed) { - sel.removeAllRanges(); - sel.addRange(rng); - } - } else { - sel.removeAllRanges(); - sel.addRange(rng); - } - if (old && sel.anchorNode == null) { sel.addRange(old); } - else if (gecko) { this.startGracePeriod(); } - } - this.rememberSelection(); - }; - - ContentEditableInput.prototype.startGracePeriod = function () { - var this$1 = this; - - clearTimeout(this.gracePeriod); - this.gracePeriod = setTimeout(function () { - this$1.gracePeriod = false; - if (this$1.selectionChanged()) - { this$1.cm.operation(function () { return this$1.cm.curOp.selectionChanged = true; }); } - }, 20); - }; - - ContentEditableInput.prototype.showMultipleSelections = function (info) { - removeChildrenAndAdd(this.cm.display.cursorDiv, info.cursors); - removeChildrenAndAdd(this.cm.display.selectionDiv, info.selection); - }; - - ContentEditableInput.prototype.rememberSelection = function () { - var sel = this.getSelection(); - this.lastAnchorNode = sel.anchorNode; this.lastAnchorOffset = sel.anchorOffset; - this.lastFocusNode = sel.focusNode; this.lastFocusOffset = sel.focusOffset; - }; - - ContentEditableInput.prototype.selectionInEditor = function () { - var sel = this.getSelection(); - if (!sel.rangeCount) { return false } - var node = sel.getRangeAt(0).commonAncestorContainer; - return contains(this.div, node) - }; - - ContentEditableInput.prototype.focus = function () { - if (this.cm.options.readOnly != "nocursor") { - if (!this.selectionInEditor() || activeElt() != this.div) - { this.showSelection(this.prepareSelection(), true); } - this.div.focus(); - } - }; - ContentEditableInput.prototype.blur = function () { this.div.blur(); }; - ContentEditableInput.prototype.getField = function () { return this.div }; - - ContentEditableInput.prototype.supportsTouch = function () { return true }; - - ContentEditableInput.prototype.receivedFocus = function () { - var this$1 = this; - - var input = this; - if (this.selectionInEditor()) - { setTimeout(function () { return this$1.pollSelection(); }, 20); } - else - { runInOp(this.cm, function () { return input.cm.curOp.selectionChanged = true; }); } - - function poll() { - if (input.cm.state.focused) { - input.pollSelection(); - input.polling.set(input.cm.options.pollInterval, poll); - } - } - this.polling.set(this.cm.options.pollInterval, poll); - }; - - ContentEditableInput.prototype.selectionChanged = function () { - var sel = this.getSelection(); - return sel.anchorNode != this.lastAnchorNode || sel.anchorOffset != this.lastAnchorOffset || - sel.focusNode != this.lastFocusNode || sel.focusOffset != this.lastFocusOffset - }; - - ContentEditableInput.prototype.pollSelection = function () { - if (this.readDOMTimeout != null || this.gracePeriod || !this.selectionChanged()) { return } - var sel = this.getSelection(), cm = this.cm; - // On Android Chrome (version 56, at least), backspacing into an - // uneditable block element will put the cursor in that element, - // and then, because it's not editable, hide the virtual keyboard. - // Because Android doesn't allow us to actually detect backspace - // presses in a sane way, this code checks for when that happens - // and simulates a backspace press in this case. - if (android && chrome && this.cm.display.gutterSpecs.length && isInGutter(sel.anchorNode)) { - this.cm.triggerOnKeyDown({type: "keydown", keyCode: 8, preventDefault: Math.abs}); - this.blur(); - this.focus(); - return - } - if (this.composing) { return } - this.rememberSelection(); - var anchor = domToPos(cm, sel.anchorNode, sel.anchorOffset); - var head = domToPos(cm, sel.focusNode, sel.focusOffset); - if (anchor && head) { runInOp(cm, function () { - setSelection(cm.doc, simpleSelection(anchor, head), sel_dontScroll); - if (anchor.bad || head.bad) { cm.curOp.selectionChanged = true; } - }); } - }; - - ContentEditableInput.prototype.pollContent = function () { - if (this.readDOMTimeout != null) { - clearTimeout(this.readDOMTimeout); - this.readDOMTimeout = null; - } - - var cm = this.cm, display = cm.display, sel = cm.doc.sel.primary(); - var from = sel.from(), to = sel.to(); - if (from.ch == 0 && from.line > cm.firstLine()) - { from = Pos(from.line - 1, getLine(cm.doc, from.line - 1).length); } - if (to.ch == getLine(cm.doc, to.line).text.length && to.line < cm.lastLine()) - { to = Pos(to.line + 1, 0); } - if (from.line < display.viewFrom || to.line > display.viewTo - 1) { return false } - - var fromIndex, fromLine, fromNode; - if (from.line == display.viewFrom || (fromIndex = findViewIndex(cm, from.line)) == 0) { - fromLine = lineNo(display.view[0].line); - fromNode = display.view[0].node; - } else { - fromLine = lineNo(display.view[fromIndex].line); - fromNode = display.view[fromIndex - 1].node.nextSibling; - } - var toIndex = findViewIndex(cm, to.line); - var toLine, toNode; - if (toIndex == display.view.length - 1) { - toLine = display.viewTo - 1; - toNode = display.lineDiv.lastChild; - } else { - toLine = lineNo(display.view[toIndex + 1].line) - 1; - toNode = display.view[toIndex + 1].node.previousSibling; - } - - if (!fromNode) { return false } - var newText = cm.doc.splitLines(domTextBetween(cm, fromNode, toNode, fromLine, toLine)); - var oldText = getBetween(cm.doc, Pos(fromLine, 0), Pos(toLine, getLine(cm.doc, toLine).text.length)); - while (newText.length > 1 && oldText.length > 1) { - if (lst(newText) == lst(oldText)) { newText.pop(); oldText.pop(); toLine--; } - else if (newText[0] == oldText[0]) { newText.shift(); oldText.shift(); fromLine++; } - else { break } - } - - var cutFront = 0, cutEnd = 0; - var newTop = newText[0], oldTop = oldText[0], maxCutFront = Math.min(newTop.length, oldTop.length); - while (cutFront < maxCutFront && newTop.charCodeAt(cutFront) == oldTop.charCodeAt(cutFront)) - { ++cutFront; } - var newBot = lst(newText), oldBot = lst(oldText); - var maxCutEnd = Math.min(newBot.length - (newText.length == 1 ? cutFront : 0), - oldBot.length - (oldText.length == 1 ? cutFront : 0)); - while (cutEnd < maxCutEnd && - newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1)) - { ++cutEnd; } - // Try to move start of change to start of selection if ambiguous - if (newText.length == 1 && oldText.length == 1 && fromLine == from.line) { - while (cutFront && cutFront > from.ch && - newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1)) { - cutFront--; - cutEnd++; - } - } - - newText[newText.length - 1] = newBot.slice(0, newBot.length - cutEnd).replace(/^\u200b+/, ""); - newText[0] = newText[0].slice(cutFront).replace(/\u200b+$/, ""); - - var chFrom = Pos(fromLine, cutFront); - var chTo = Pos(toLine, oldText.length ? lst(oldText).length - cutEnd : 0); - if (newText.length > 1 || newText[0] || cmp(chFrom, chTo)) { - replaceRange(cm.doc, newText, chFrom, chTo, "+input"); - return true - } - }; - - ContentEditableInput.prototype.ensurePolled = function () { - this.forceCompositionEnd(); - }; - ContentEditableInput.prototype.reset = function () { - this.forceCompositionEnd(); - }; - ContentEditableInput.prototype.forceCompositionEnd = function () { - if (!this.composing) { return } - clearTimeout(this.readDOMTimeout); - this.composing = null; - this.updateFromDOM(); - this.div.blur(); - this.div.focus(); - }; - ContentEditableInput.prototype.readFromDOMSoon = function () { - var this$1 = this; - - if (this.readDOMTimeout != null) { return } - this.readDOMTimeout = setTimeout(function () { - this$1.readDOMTimeout = null; - if (this$1.composing) { - if (this$1.composing.done) { this$1.composing = null; } - else { return } - } - this$1.updateFromDOM(); - }, 80); - }; - - ContentEditableInput.prototype.updateFromDOM = function () { - var this$1 = this; - - if (this.cm.isReadOnly() || !this.pollContent()) - { runInOp(this.cm, function () { return regChange(this$1.cm); }); } - }; - - ContentEditableInput.prototype.setUneditable = function (node) { - node.contentEditable = "false"; - }; - - ContentEditableInput.prototype.onKeyPress = function (e) { - if (e.charCode == 0 || this.composing) { return } - e.preventDefault(); - if (!this.cm.isReadOnly()) - { operation(this.cm, applyTextInput)(this.cm, String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode), 0); } - }; - - ContentEditableInput.prototype.readOnlyChanged = function (val) { - this.div.contentEditable = String(val != "nocursor"); - }; - - ContentEditableInput.prototype.onContextMenu = function () {}; - ContentEditableInput.prototype.resetPosition = function () {}; - - ContentEditableInput.prototype.needsContentAttribute = true; - - function posToDOM(cm, pos) { - var view = findViewForLine(cm, pos.line); - if (!view || view.hidden) { return null } - var line = getLine(cm.doc, pos.line); - var info = mapFromLineView(view, line, pos.line); - - var order = getOrder(line, cm.doc.direction), side = "left"; - if (order) { - var partPos = getBidiPartAt(order, pos.ch); - side = partPos % 2 ? "right" : "left"; - } - var result = nodeAndOffsetInLineMap(info.map, pos.ch, side); - result.offset = result.collapse == "right" ? result.end : result.start; - return result - } - - function isInGutter(node) { - for (var scan = node; scan; scan = scan.parentNode) - { if (/CodeMirror-gutter-wrapper/.test(scan.className)) { return true } } - return false - } - - function badPos(pos, bad) { if (bad) { pos.bad = true; } return pos } - - function domTextBetween(cm, from, to, fromLine, toLine) { - var text = "", closing = false, lineSep = cm.doc.lineSeparator(), extraLinebreak = false; - function recognizeMarker(id) { return function (marker) { return marker.id == id; } } - function close() { - if (closing) { - text += lineSep; - if (extraLinebreak) { text += lineSep; } - closing = extraLinebreak = false; - } - } - function addText(str) { - if (str) { - close(); - text += str; - } - } - function walk(node) { - if (node.nodeType == 1) { - var cmText = node.getAttribute("cm-text"); - if (cmText) { - addText(cmText); - return - } - var markerID = node.getAttribute("cm-marker"), range; - if (markerID) { - var found = cm.findMarks(Pos(fromLine, 0), Pos(toLine + 1, 0), recognizeMarker(+markerID)); - if (found.length && (range = found[0].find(0))) - { addText(getBetween(cm.doc, range.from, range.to).join(lineSep)); } - return - } - if (node.getAttribute("contenteditable") == "false") { return } - var isBlock = /^(pre|div|p|li|table|br)$/i.test(node.nodeName); - if (!/^br$/i.test(node.nodeName) && node.textContent.length == 0) { return } - - if (isBlock) { close(); } - for (var i = 0; i < node.childNodes.length; i++) - { walk(node.childNodes[i]); } - - if (/^(pre|p)$/i.test(node.nodeName)) { extraLinebreak = true; } - if (isBlock) { closing = true; } - } else if (node.nodeType == 3) { - addText(node.nodeValue.replace(/\u200b/g, "").replace(/\u00a0/g, " ")); - } - } - for (;;) { - walk(from); - if (from == to) { break } - from = from.nextSibling; - extraLinebreak = false; - } - return text - } - - function domToPos(cm, node, offset) { - var lineNode; - if (node == cm.display.lineDiv) { - lineNode = cm.display.lineDiv.childNodes[offset]; - if (!lineNode) { return badPos(cm.clipPos(Pos(cm.display.viewTo - 1)), true) } - node = null; offset = 0; - } else { - for (lineNode = node;; lineNode = lineNode.parentNode) { - if (!lineNode || lineNode == cm.display.lineDiv) { return null } - if (lineNode.parentNode && lineNode.parentNode == cm.display.lineDiv) { break } - } - } - for (var i = 0; i < cm.display.view.length; i++) { - var lineView = cm.display.view[i]; - if (lineView.node == lineNode) - { return locateNodeInLineView(lineView, node, offset) } - } - } - - function locateNodeInLineView(lineView, node, offset) { - var wrapper = lineView.text.firstChild, bad = false; - if (!node || !contains(wrapper, node)) { return badPos(Pos(lineNo(lineView.line), 0), true) } - if (node == wrapper) { - bad = true; - node = wrapper.childNodes[offset]; - offset = 0; - if (!node) { - var line = lineView.rest ? lst(lineView.rest) : lineView.line; - return badPos(Pos(lineNo(line), line.text.length), bad) - } - } - - var textNode = node.nodeType == 3 ? node : null, topNode = node; - if (!textNode && node.childNodes.length == 1 && node.firstChild.nodeType == 3) { - textNode = node.firstChild; - if (offset) { offset = textNode.nodeValue.length; } - } - while (topNode.parentNode != wrapper) { topNode = topNode.parentNode; } - var measure = lineView.measure, maps = measure.maps; - - function find(textNode, topNode, offset) { - for (var i = -1; i < (maps ? maps.length : 0); i++) { - var map = i < 0 ? measure.map : maps[i]; - for (var j = 0; j < map.length; j += 3) { - var curNode = map[j + 2]; - if (curNode == textNode || curNode == topNode) { - var line = lineNo(i < 0 ? lineView.line : lineView.rest[i]); - var ch = map[j] + offset; - if (offset < 0 || curNode != textNode) { ch = map[j + (offset ? 1 : 0)]; } - return Pos(line, ch) - } - } - } - } - var found = find(textNode, topNode, offset); - if (found) { return badPos(found, bad) } - - // FIXME this is all really shaky. might handle the few cases it needs to handle, but likely to cause problems - for (var after = topNode.nextSibling, dist = textNode ? textNode.nodeValue.length - offset : 0; after; after = after.nextSibling) { - found = find(after, after.firstChild, 0); - if (found) - { return badPos(Pos(found.line, found.ch - dist), bad) } - else - { dist += after.textContent.length; } - } - for (var before = topNode.previousSibling, dist$1 = offset; before; before = before.previousSibling) { - found = find(before, before.firstChild, -1); - if (found) - { return badPos(Pos(found.line, found.ch + dist$1), bad) } - else - { dist$1 += before.textContent.length; } - } - } - - // TEXTAREA INPUT STYLE - - var TextareaInput = function(cm) { - this.cm = cm; - // See input.poll and input.reset - this.prevInput = ""; - - // Flag that indicates whether we expect input to appear real soon - // now (after some event like 'keypress' or 'input') and are - // polling intensively. - this.pollingFast = false; - // Self-resetting timeout for the poller - this.polling = new Delayed(); - // Used to work around IE issue with selection being forgotten when focus moves away from textarea - this.hasSelection = false; - this.composing = null; - }; - - TextareaInput.prototype.init = function (display) { - var this$1 = this; - - var input = this, cm = this.cm; - this.createField(display); - var te = this.textarea; - - display.wrapper.insertBefore(this.wrapper, display.wrapper.firstChild); - - // Needed to hide big blue blinking cursor on Mobile Safari (doesn't seem to work in iOS 8 anymore) - if (ios) { te.style.width = "0px"; } - - on(te, "input", function () { - if (ie && ie_version >= 9 && this$1.hasSelection) { this$1.hasSelection = null; } - input.poll(); - }); - - on(te, "paste", function (e) { - if (signalDOMEvent(cm, e) || handlePaste(e, cm)) { return } - - cm.state.pasteIncoming = +new Date; - input.fastPoll(); - }); - - function prepareCopyCut(e) { - if (signalDOMEvent(cm, e)) { return } - if (cm.somethingSelected()) { - setLastCopied({lineWise: false, text: cm.getSelections()}); - } else if (!cm.options.lineWiseCopyCut) { - return - } else { - var ranges = copyableRanges(cm); - setLastCopied({lineWise: true, text: ranges.text}); - if (e.type == "cut") { - cm.setSelections(ranges.ranges, null, sel_dontScroll); - } else { - input.prevInput = ""; - te.value = ranges.text.join("\n"); - selectInput(te); - } - } - if (e.type == "cut") { cm.state.cutIncoming = +new Date; } - } - on(te, "cut", prepareCopyCut); - on(te, "copy", prepareCopyCut); - - on(display.scroller, "paste", function (e) { - if (eventInWidget(display, e) || signalDOMEvent(cm, e)) { return } - if (!te.dispatchEvent) { - cm.state.pasteIncoming = +new Date; - input.focus(); - return - } - - // Pass the `paste` event to the textarea so it's handled by its event listener. - var event = new Event("paste"); - event.clipboardData = e.clipboardData; - te.dispatchEvent(event); - }); - - // Prevent normal selection in the editor (we handle our own) - on(display.lineSpace, "selectstart", function (e) { - if (!eventInWidget(display, e)) { e_preventDefault(e); } - }); - - on(te, "compositionstart", function () { - var start = cm.getCursor("from"); - if (input.composing) { input.composing.range.clear(); } - input.composing = { - start: start, - range: cm.markText(start, cm.getCursor("to"), {className: "CodeMirror-composing"}) - }; - }); - on(te, "compositionend", function () { - if (input.composing) { - input.poll(); - input.composing.range.clear(); - input.composing = null; - } - }); - }; - - TextareaInput.prototype.createField = function (_display) { - // Wraps and hides input textarea - this.wrapper = hiddenTextarea(); - // The semihidden textarea that is focused when the editor is - // focused, and receives input. - this.textarea = this.wrapper.firstChild; - }; - - TextareaInput.prototype.screenReaderLabelChanged = function (label) { - // Label for screenreaders, accessibility - if(label) { - this.textarea.setAttribute('aria-label', label); - } else { - this.textarea.removeAttribute('aria-label'); - } - }; - - TextareaInput.prototype.prepareSelection = function () { - // Redraw the selection and/or cursor - var cm = this.cm, display = cm.display, doc = cm.doc; - var result = prepareSelection(cm); - - // Move the hidden textarea near the cursor to prevent scrolling artifacts - if (cm.options.moveInputWithCursor) { - var headPos = cursorCoords(cm, doc.sel.primary().head, "div"); - var wrapOff = display.wrapper.getBoundingClientRect(), lineOff = display.lineDiv.getBoundingClientRect(); - result.teTop = Math.max(0, Math.min(display.wrapper.clientHeight - 10, - headPos.top + lineOff.top - wrapOff.top)); - result.teLeft = Math.max(0, Math.min(display.wrapper.clientWidth - 10, - headPos.left + lineOff.left - wrapOff.left)); - } - - return result - }; - - TextareaInput.prototype.showSelection = function (drawn) { - var cm = this.cm, display = cm.display; - removeChildrenAndAdd(display.cursorDiv, drawn.cursors); - removeChildrenAndAdd(display.selectionDiv, drawn.selection); - if (drawn.teTop != null) { - this.wrapper.style.top = drawn.teTop + "px"; - this.wrapper.style.left = drawn.teLeft + "px"; - } - }; - - // Reset the input to correspond to the selection (or to be empty, - // when not typing and nothing is selected) - TextareaInput.prototype.reset = function (typing) { - if (this.contextMenuPending || this.composing) { return } - var cm = this.cm; - if (cm.somethingSelected()) { - this.prevInput = ""; - var content = cm.getSelection(); - this.textarea.value = content; - if (cm.state.focused) { selectInput(this.textarea); } - if (ie && ie_version >= 9) { this.hasSelection = content; } - } else if (!typing) { - this.prevInput = this.textarea.value = ""; - if (ie && ie_version >= 9) { this.hasSelection = null; } - } - }; - - TextareaInput.prototype.getField = function () { return this.textarea }; - - TextareaInput.prototype.supportsTouch = function () { return false }; - - TextareaInput.prototype.focus = function () { - if (this.cm.options.readOnly != "nocursor" && (!mobile || activeElt() != this.textarea)) { - try { this.textarea.focus(); } - catch (e) {} // IE8 will throw if the textarea is display: none or not in DOM - } - }; - - TextareaInput.prototype.blur = function () { this.textarea.blur(); }; - - TextareaInput.prototype.resetPosition = function () { - this.wrapper.style.top = this.wrapper.style.left = 0; - }; - - TextareaInput.prototype.receivedFocus = function () { this.slowPoll(); }; - - // Poll for input changes, using the normal rate of polling. This - // runs as long as the editor is focused. - TextareaInput.prototype.slowPoll = function () { - var this$1 = this; - - if (this.pollingFast) { return } - this.polling.set(this.cm.options.pollInterval, function () { - this$1.poll(); - if (this$1.cm.state.focused) { this$1.slowPoll(); } - }); - }; - - // When an event has just come in that is likely to add or change - // something in the input textarea, we poll faster, to ensure that - // the change appears on the screen quickly. - TextareaInput.prototype.fastPoll = function () { - var missed = false, input = this; - input.pollingFast = true; - function p() { - var changed = input.poll(); - if (!changed && !missed) {missed = true; input.polling.set(60, p);} - else {input.pollingFast = false; input.slowPoll();} - } - input.polling.set(20, p); - }; - - // Read input from the textarea, and update the document to match. - // When something is selected, it is present in the textarea, and - // selected (unless it is huge, in which case a placeholder is - // used). When nothing is selected, the cursor sits after previously - // seen text (can be empty), which is stored in prevInput (we must - // not reset the textarea when typing, because that breaks IME). - TextareaInput.prototype.poll = function () { - var this$1 = this; - - var cm = this.cm, input = this.textarea, prevInput = this.prevInput; - // Since this is called a *lot*, try to bail out as cheaply as - // possible when it is clear that nothing happened. hasSelection - // will be the case when there is a lot of text in the textarea, - // in which case reading its value would be expensive. - if (this.contextMenuPending || !cm.state.focused || - (hasSelection(input) && !prevInput && !this.composing) || - cm.isReadOnly() || cm.options.disableInput || cm.state.keySeq) - { return false } - - var text = input.value; - // If nothing changed, bail. - if (text == prevInput && !cm.somethingSelected()) { return false } - // Work around nonsensical selection resetting in IE9/10, and - // inexplicable appearance of private area unicode characters on - // some key combos in Mac (#2689). - if (ie && ie_version >= 9 && this.hasSelection === text || - mac && /[\uf700-\uf7ff]/.test(text)) { - cm.display.input.reset(); - return false - } - - if (cm.doc.sel == cm.display.selForContextMenu) { - var first = text.charCodeAt(0); - if (first == 0x200b && !prevInput) { prevInput = "\u200b"; } - if (first == 0x21da) { this.reset(); return this.cm.execCommand("undo") } - } - // Find the part of the input that is actually new - var same = 0, l = Math.min(prevInput.length, text.length); - while (same < l && prevInput.charCodeAt(same) == text.charCodeAt(same)) { ++same; } - - runInOp(cm, function () { - applyTextInput(cm, text.slice(same), prevInput.length - same, - null, this$1.composing ? "*compose" : null); - - // Don't leave long text in the textarea, since it makes further polling slow - if (text.length > 1000 || text.indexOf("\n") > -1) { input.value = this$1.prevInput = ""; } - else { this$1.prevInput = text; } - - if (this$1.composing) { - this$1.composing.range.clear(); - this$1.composing.range = cm.markText(this$1.composing.start, cm.getCursor("to"), - {className: "CodeMirror-composing"}); - } - }); - return true - }; - - TextareaInput.prototype.ensurePolled = function () { - if (this.pollingFast && this.poll()) { this.pollingFast = false; } - }; - - TextareaInput.prototype.onKeyPress = function () { - if (ie && ie_version >= 9) { this.hasSelection = null; } - this.fastPoll(); - }; - - TextareaInput.prototype.onContextMenu = function (e) { - var input = this, cm = input.cm, display = cm.display, te = input.textarea; - if (input.contextMenuPending) { input.contextMenuPending(); } - var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop; - if (!pos || presto) { return } // Opera is difficult. - - // Reset the current text selection only if the click is done outside of the selection - // and 'resetSelectionOnContextMenu' option is true. - var reset = cm.options.resetSelectionOnContextMenu; - if (reset && cm.doc.sel.contains(pos) == -1) - { operation(cm, setSelection)(cm.doc, simpleSelection(pos), sel_dontScroll); } - - var oldCSS = te.style.cssText, oldWrapperCSS = input.wrapper.style.cssText; - var wrapperBox = input.wrapper.offsetParent.getBoundingClientRect(); - input.wrapper.style.cssText = "position: static"; - te.style.cssText = "position: absolute; width: 30px; height: 30px;\n top: " + (e.clientY - wrapperBox.top - 5) + "px; left: " + (e.clientX - wrapperBox.left - 5) + "px;\n z-index: 1000; background: " + (ie ? "rgba(255, 255, 255, .05)" : "transparent") + ";\n outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);"; - var oldScrollY; - if (webkit) { oldScrollY = window.scrollY; } // Work around Chrome issue (#2712) - display.input.focus(); - if (webkit) { window.scrollTo(null, oldScrollY); } - display.input.reset(); - // Adds "Select all" to context menu in FF - if (!cm.somethingSelected()) { te.value = input.prevInput = " "; } - input.contextMenuPending = rehide; - display.selForContextMenu = cm.doc.sel; - clearTimeout(display.detectingSelectAll); - - // Select-all will be greyed out if there's nothing to select, so - // this adds a zero-width space so that we can later check whether - // it got selected. - function prepareSelectAllHack() { - if (te.selectionStart != null) { - var selected = cm.somethingSelected(); - var extval = "\u200b" + (selected ? te.value : ""); - te.value = "\u21da"; // Used to catch context-menu undo - te.value = extval; - input.prevInput = selected ? "" : "\u200b"; - te.selectionStart = 1; te.selectionEnd = extval.length; - // Re-set this, in case some other handler touched the - // selection in the meantime. - display.selForContextMenu = cm.doc.sel; - } - } - function rehide() { - if (input.contextMenuPending != rehide) { return } - input.contextMenuPending = false; - input.wrapper.style.cssText = oldWrapperCSS; - te.style.cssText = oldCSS; - if (ie && ie_version < 9) { display.scrollbars.setScrollTop(display.scroller.scrollTop = scrollPos); } - - // Try to detect the user choosing select-all - if (te.selectionStart != null) { - if (!ie || (ie && ie_version < 9)) { prepareSelectAllHack(); } - var i = 0, poll = function () { - if (display.selForContextMenu == cm.doc.sel && te.selectionStart == 0 && - te.selectionEnd > 0 && input.prevInput == "\u200b") { - operation(cm, selectAll)(cm); - } else if (i++ < 10) { - display.detectingSelectAll = setTimeout(poll, 500); - } else { - display.selForContextMenu = null; - display.input.reset(); - } - }; - display.detectingSelectAll = setTimeout(poll, 200); - } - } - - if (ie && ie_version >= 9) { prepareSelectAllHack(); } - if (captureRightClick) { - e_stop(e); - var mouseup = function () { - off(window, "mouseup", mouseup); - setTimeout(rehide, 20); - }; - on(window, "mouseup", mouseup); - } else { - setTimeout(rehide, 50); - } - }; - - TextareaInput.prototype.readOnlyChanged = function (val) { - if (!val) { this.reset(); } - this.textarea.disabled = val == "nocursor"; - this.textarea.readOnly = !!val; - }; - - TextareaInput.prototype.setUneditable = function () {}; - - TextareaInput.prototype.needsContentAttribute = false; - - function fromTextArea(textarea, options) { - options = options ? copyObj(options) : {}; - options.value = textarea.value; - if (!options.tabindex && textarea.tabIndex) - { options.tabindex = textarea.tabIndex; } - if (!options.placeholder && textarea.placeholder) - { options.placeholder = textarea.placeholder; } - // Set autofocus to true if this textarea is focused, or if it has - // autofocus and no other element is focused. - if (options.autofocus == null) { - var hasFocus = activeElt(); - options.autofocus = hasFocus == textarea || - textarea.getAttribute("autofocus") != null && hasFocus == document.body; - } - - function save() {textarea.value = cm.getValue();} - - var realSubmit; - if (textarea.form) { - on(textarea.form, "submit", save); - // Deplorable hack to make the submit method do the right thing. - if (!options.leaveSubmitMethodAlone) { - var form = textarea.form; - realSubmit = form.submit; - try { - var wrappedSubmit = form.submit = function () { - save(); - form.submit = realSubmit; - form.submit(); - form.submit = wrappedSubmit; - }; - } catch(e) {} - } - } - - options.finishInit = function (cm) { - cm.save = save; - cm.getTextArea = function () { return textarea; }; - cm.toTextArea = function () { - cm.toTextArea = isNaN; // Prevent this from being ran twice - save(); - textarea.parentNode.removeChild(cm.getWrapperElement()); - textarea.style.display = ""; - if (textarea.form) { - off(textarea.form, "submit", save); - if (!options.leaveSubmitMethodAlone && typeof textarea.form.submit == "function") - { textarea.form.submit = realSubmit; } - } - }; - }; - - textarea.style.display = "none"; - var cm = CodeMirror(function (node) { return textarea.parentNode.insertBefore(node, textarea.nextSibling); }, - options); - return cm - } - - function addLegacyProps(CodeMirror) { - CodeMirror.off = off; - CodeMirror.on = on; - CodeMirror.wheelEventPixels = wheelEventPixels; - CodeMirror.Doc = Doc; - CodeMirror.splitLines = splitLinesAuto; - CodeMirror.countColumn = countColumn; - CodeMirror.findColumn = findColumn; - CodeMirror.isWordChar = isWordCharBasic; - CodeMirror.Pass = Pass; - CodeMirror.signal = signal; - CodeMirror.Line = Line; - CodeMirror.changeEnd = changeEnd; - CodeMirror.scrollbarModel = scrollbarModel; - CodeMirror.Pos = Pos; - CodeMirror.cmpPos = cmp; - CodeMirror.modes = modes; - CodeMirror.mimeModes = mimeModes; - CodeMirror.resolveMode = resolveMode; - CodeMirror.getMode = getMode; - CodeMirror.modeExtensions = modeExtensions; - CodeMirror.extendMode = extendMode; - CodeMirror.copyState = copyState; - CodeMirror.startState = startState; - CodeMirror.innerMode = innerMode; - CodeMirror.commands = commands; - CodeMirror.keyMap = keyMap; - CodeMirror.keyName = keyName; - CodeMirror.isModifierKey = isModifierKey; - CodeMirror.lookupKey = lookupKey; - CodeMirror.normalizeKeyMap = normalizeKeyMap; - CodeMirror.StringStream = StringStream; - CodeMirror.SharedTextMarker = SharedTextMarker; - CodeMirror.TextMarker = TextMarker; - CodeMirror.LineWidget = LineWidget; - CodeMirror.e_preventDefault = e_preventDefault; - CodeMirror.e_stopPropagation = e_stopPropagation; - CodeMirror.e_stop = e_stop; - CodeMirror.addClass = addClass; - CodeMirror.contains = contains; - CodeMirror.rmClass = rmClass; - CodeMirror.keyNames = keyNames; - } - - // EDITOR CONSTRUCTOR - - defineOptions(CodeMirror); - - addEditorMethods(CodeMirror); - - // Set up methods on CodeMirror's prototype to redirect to the editor's document. - var dontDelegate = "iter insert remove copy getEditor constructor".split(" "); - for (var prop in Doc.prototype) { if (Doc.prototype.hasOwnProperty(prop) && indexOf(dontDelegate, prop) < 0) - { CodeMirror.prototype[prop] = (function(method) { - return function() {return method.apply(this.doc, arguments)} - })(Doc.prototype[prop]); } } - - eventMixin(Doc); - CodeMirror.inputStyles = {"textarea": TextareaInput, "contenteditable": ContentEditableInput}; - - // Extra arguments are stored as the mode's dependencies, which is - // used by (legacy) mechanisms like loadmode.js to automatically - // load a mode. (Preferred mechanism is the require/define calls.) - CodeMirror.defineMode = function(name/*, mode, …*/) { - if (!CodeMirror.defaults.mode && name != "null") { CodeMirror.defaults.mode = name; } - defineMode.apply(this, arguments); - }; - - CodeMirror.defineMIME = defineMIME; - - // Minimal default mode. - CodeMirror.defineMode("null", function () { return ({token: function (stream) { return stream.skipToEnd(); }}); }); - CodeMirror.defineMIME("text/plain", "null"); - - // EXTENSIONS - - CodeMirror.defineExtension = function (name, func) { - CodeMirror.prototype[name] = func; - }; - CodeMirror.defineDocExtension = function (name, func) { - Doc.prototype[name] = func; - }; - - CodeMirror.fromTextArea = fromTextArea; - - addLegacyProps(CodeMirror); - - CodeMirror.version = "5.65.2"; - - return CodeMirror; - -}))); diff --git a/www/js/codemirror/mode/css/css.js b/www/js/codemirror/mode/css/css.js deleted file mode 100644 index 503c48c..0000000 --- a/www/js/codemirror/mode/css/css.js +++ /dev/null @@ -1,866 +0,0 @@ -// CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE - -(function(mod) { - if (typeof exports == "object" && typeof module == "object") // CommonJS - mod(require("../../lib/codemirror")); - else if (typeof define == "function" && define.amd) // AMD - define(["../../lib/codemirror"], mod); - else // Plain browser env - mod(CodeMirror); -})(function(CodeMirror) { -"use strict"; - -CodeMirror.defineMode("css", function(config, parserConfig) { - var inline = parserConfig.inline - if (!parserConfig.propertyKeywords) parserConfig = CodeMirror.resolveMode("text/css"); - - var indentUnit = config.indentUnit, - tokenHooks = parserConfig.tokenHooks, - documentTypes = parserConfig.documentTypes || {}, - mediaTypes = parserConfig.mediaTypes || {}, - mediaFeatures = parserConfig.mediaFeatures || {}, - mediaValueKeywords = parserConfig.mediaValueKeywords || {}, - propertyKeywords = parserConfig.propertyKeywords || {}, - nonStandardPropertyKeywords = parserConfig.nonStandardPropertyKeywords || {}, - fontProperties = parserConfig.fontProperties || {}, - counterDescriptors = parserConfig.counterDescriptors || {}, - colorKeywords = parserConfig.colorKeywords || {}, - valueKeywords = parserConfig.valueKeywords || {}, - allowNested = parserConfig.allowNested, - lineComment = parserConfig.lineComment, - supportsAtComponent = parserConfig.supportsAtComponent === true, - highlightNonStandardPropertyKeywords = config.highlightNonStandardPropertyKeywords !== false; - - var type, override; - function ret(style, tp) { type = tp; return style; } - - // Tokenizers - - function tokenBase(stream, state) { - var ch = stream.next(); - if (tokenHooks[ch]) { - var result = tokenHooks[ch](stream, state); - if (result !== false) return result; - } - if (ch == "@") { - stream.eatWhile(/[\w\\\-]/); - return ret("def", stream.current()); - } else if (ch == "=" || (ch == "~" || ch == "|") && stream.eat("=")) { - return ret(null, "compare"); - } else if (ch == "\"" || ch == "'") { - state.tokenize = tokenString(ch); - return state.tokenize(stream, state); - } else if (ch == "#") { - stream.eatWhile(/[\w\\\-]/); - return ret("atom", "hash"); - } else if (ch == "!") { - stream.match(/^\s*\w*/); - return ret("keyword", "important"); - } else if (/\d/.test(ch) || ch == "." && stream.eat(/\d/)) { - stream.eatWhile(/[\w.%]/); - return ret("number", "unit"); - } else if (ch === "-") { - if (/[\d.]/.test(stream.peek())) { - stream.eatWhile(/[\w.%]/); - return ret("number", "unit"); - } else if (stream.match(/^-[\w\\\-]*/)) { - stream.eatWhile(/[\w\\\-]/); - if (stream.match(/^\s*:/, false)) - return ret("variable-2", "variable-definition"); - return ret("variable-2", "variable"); - } else if (stream.match(/^\w+-/)) { - return ret("meta", "meta"); - } - } else if (/[,+>*\/]/.test(ch)) { - return ret(null, "select-op"); - } else if (ch == "." && stream.match(/^-?[_a-z][_a-z0-9-]*/i)) { - return ret("qualifier", "qualifier"); - } else if (/[:;{}\[\]\(\)]/.test(ch)) { - return ret(null, ch); - } else if (stream.match(/^[\w-.]+(?=\()/)) { - if (/^(url(-prefix)?|domain|regexp)$/i.test(stream.current())) { - state.tokenize = tokenParenthesized; - } - return ret("variable callee", "variable"); - } else if (/[\w\\\-]/.test(ch)) { - stream.eatWhile(/[\w\\\-]/); - return ret("property", "word"); - } else { - return ret(null, null); - } - } - - function tokenString(quote) { - return function(stream, state) { - var escaped = false, ch; - while ((ch = stream.next()) != null) { - if (ch == quote && !escaped) { - if (quote == ")") stream.backUp(1); - break; - } - escaped = !escaped && ch == "\\"; - } - if (ch == quote || !escaped && quote != ")") state.tokenize = null; - return ret("string", "string"); - }; - } - - function tokenParenthesized(stream, state) { - stream.next(); // Must be '(' - if (!stream.match(/^\s*[\"\')]/, false)) - state.tokenize = tokenString(")"); - else - state.tokenize = null; - return ret(null, "("); - } - - // Context management - - function Context(type, indent, prev) { - this.type = type; - this.indent = indent; - this.prev = prev; - } - - function pushContext(state, stream, type, indent) { - state.context = new Context(type, stream.indentation() + (indent === false ? 0 : indentUnit), state.context); - return type; - } - - function popContext(state) { - if (state.context.prev) - state.context = state.context.prev; - return state.context.type; - } - - function pass(type, stream, state) { - return states[state.context.type](type, stream, state); - } - function popAndPass(type, stream, state, n) { - for (var i = n || 1; i > 0; i--) - state.context = state.context.prev; - return pass(type, stream, state); - } - - // Parser - - function wordAsValue(stream) { - var word = stream.current().toLowerCase(); - if (valueKeywords.hasOwnProperty(word)) - override = "atom"; - else if (colorKeywords.hasOwnProperty(word)) - override = "keyword"; - else - override = "variable"; - } - - var states = {}; - - states.top = function(type, stream, state) { - if (type == "{") { - return pushContext(state, stream, "block"); - } else if (type == "}" && state.context.prev) { - return popContext(state); - } else if (supportsAtComponent && /@component/i.test(type)) { - return pushContext(state, stream, "atComponentBlock"); - } else if (/^@(-moz-)?document$/i.test(type)) { - return pushContext(state, stream, "documentTypes"); - } else if (/^@(media|supports|(-moz-)?document|import)$/i.test(type)) { - return pushContext(state, stream, "atBlock"); - } else if (/^@(font-face|counter-style)/i.test(type)) { - state.stateArg = type; - return "restricted_atBlock_before"; - } else if (/^@(-(moz|ms|o|webkit)-)?keyframes$/i.test(type)) { - return "keyframes"; - } else if (type && type.charAt(0) == "@") { - return pushContext(state, stream, "at"); - } else if (type == "hash") { - override = "builtin"; - } else if (type == "word") { - override = "tag"; - } else if (type == "variable-definition") { - return "maybeprop"; - } else if (type == "interpolation") { - return pushContext(state, stream, "interpolation"); - } else if (type == ":") { - return "pseudo"; - } else if (allowNested && type == "(") { - return pushContext(state, stream, "parens"); - } - return state.context.type; - }; - - states.block = function(type, stream, state) { - if (type == "word") { - var word = stream.current().toLowerCase(); - if (propertyKeywords.hasOwnProperty(word)) { - override = "property"; - return "maybeprop"; - } else if (nonStandardPropertyKeywords.hasOwnProperty(word)) { - override = highlightNonStandardPropertyKeywords ? "string-2" : "property"; - return "maybeprop"; - } else if (allowNested) { - override = stream.match(/^\s*:(?:\s|$)/, false) ? "property" : "tag"; - return "block"; - } else { - override += " error"; - return "maybeprop"; - } - } else if (type == "meta") { - return "block"; - } else if (!allowNested && (type == "hash" || type == "qualifier")) { - override = "error"; - return "block"; - } else { - return states.top(type, stream, state); - } - }; - - states.maybeprop = function(type, stream, state) { - if (type == ":") return pushContext(state, stream, "prop"); - return pass(type, stream, state); - }; - - states.prop = function(type, stream, state) { - if (type == ";") return popContext(state); - if (type == "{" && allowNested) return pushContext(state, stream, "propBlock"); - if (type == "}" || type == "{") return popAndPass(type, stream, state); - if (type == "(") return pushContext(state, stream, "parens"); - - if (type == "hash" && !/^#([0-9a-fA-f]{3,4}|[0-9a-fA-f]{6}|[0-9a-fA-f]{8})$/.test(stream.current())) { - override += " error"; - } else if (type == "word") { - wordAsValue(stream); - } else if (type == "interpolation") { - return pushContext(state, stream, "interpolation"); - } - return "prop"; - }; - - states.propBlock = function(type, _stream, state) { - if (type == "}") return popContext(state); - if (type == "word") { override = "property"; return "maybeprop"; } - return state.context.type; - }; - - states.parens = function(type, stream, state) { - if (type == "{" || type == "}") return popAndPass(type, stream, state); - if (type == ")") return popContext(state); - if (type == "(") return pushContext(state, stream, "parens"); - if (type == "interpolation") return pushContext(state, stream, "interpolation"); - if (type == "word") wordAsValue(stream); - return "parens"; - }; - - states.pseudo = function(type, stream, state) { - if (type == "meta") return "pseudo"; - - if (type == "word") { - override = "variable-3"; - return state.context.type; - } - return pass(type, stream, state); - }; - - states.documentTypes = function(type, stream, state) { - if (type == "word" && documentTypes.hasOwnProperty(stream.current())) { - override = "tag"; - return state.context.type; - } else { - return states.atBlock(type, stream, state); - } - }; - - states.atBlock = function(type, stream, state) { - if (type == "(") return pushContext(state, stream, "atBlock_parens"); - if (type == "}" || type == ";") return popAndPass(type, stream, state); - if (type == "{") return popContext(state) && pushContext(state, stream, allowNested ? "block" : "top"); - - if (type == "interpolation") return pushContext(state, stream, "interpolation"); - - if (type == "word") { - var word = stream.current().toLowerCase(); - if (word == "only" || word == "not" || word == "and" || word == "or") - override = "keyword"; - else if (mediaTypes.hasOwnProperty(word)) - override = "attribute"; - else if (mediaFeatures.hasOwnProperty(word)) - override = "property"; - else if (mediaValueKeywords.hasOwnProperty(word)) - override = "keyword"; - else if (propertyKeywords.hasOwnProperty(word)) - override = "property"; - else if (nonStandardPropertyKeywords.hasOwnProperty(word)) - override = highlightNonStandardPropertyKeywords ? "string-2" : "property"; - else if (valueKeywords.hasOwnProperty(word)) - override = "atom"; - else if (colorKeywords.hasOwnProperty(word)) - override = "keyword"; - else - override = "error"; - } - return state.context.type; - }; - - states.atComponentBlock = function(type, stream, state) { - if (type == "}") - return popAndPass(type, stream, state); - if (type == "{") - return popContext(state) && pushContext(state, stream, allowNested ? "block" : "top", false); - if (type == "word") - override = "error"; - return state.context.type; - }; - - states.atBlock_parens = function(type, stream, state) { - if (type == ")") return popContext(state); - if (type == "{" || type == "}") return popAndPass(type, stream, state, 2); - return states.atBlock(type, stream, state); - }; - - states.restricted_atBlock_before = function(type, stream, state) { - if (type == "{") - return pushContext(state, stream, "restricted_atBlock"); - if (type == "word" && state.stateArg == "@counter-style") { - override = "variable"; - return "restricted_atBlock_before"; - } - return pass(type, stream, state); - }; - - states.restricted_atBlock = function(type, stream, state) { - if (type == "}") { - state.stateArg = null; - return popContext(state); - } - if (type == "word") { - if ((state.stateArg == "@font-face" && !fontProperties.hasOwnProperty(stream.current().toLowerCase())) || - (state.stateArg == "@counter-style" && !counterDescriptors.hasOwnProperty(stream.current().toLowerCase()))) - override = "error"; - else - override = "property"; - return "maybeprop"; - } - return "restricted_atBlock"; - }; - - states.keyframes = function(type, stream, state) { - if (type == "word") { override = "variable"; return "keyframes"; } - if (type == "{") return pushContext(state, stream, "top"); - return pass(type, stream, state); - }; - - states.at = function(type, stream, state) { - if (type == ";") return popContext(state); - if (type == "{" || type == "}") return popAndPass(type, stream, state); - if (type == "word") override = "tag"; - else if (type == "hash") override = "builtin"; - return "at"; - }; - - states.interpolation = function(type, stream, state) { - if (type == "}") return popContext(state); - if (type == "{" || type == ";") return popAndPass(type, stream, state); - if (type == "word") override = "variable"; - else if (type != "variable" && type != "(" && type != ")") override = "error"; - return "interpolation"; - }; - - return { - startState: function(base) { - return {tokenize: null, - state: inline ? "block" : "top", - stateArg: null, - context: new Context(inline ? "block" : "top", base || 0, null)}; - }, - - token: function(stream, state) { - if (!state.tokenize && stream.eatSpace()) return null; - var style = (state.tokenize || tokenBase)(stream, state); - if (style && typeof style == "object") { - type = style[1]; - style = style[0]; - } - override = style; - if (type != "comment") - state.state = states[state.state](type, stream, state); - return override; - }, - - indent: function(state, textAfter) { - var cx = state.context, ch = textAfter && textAfter.charAt(0); - var indent = cx.indent; - if (cx.type == "prop" && (ch == "}" || ch == ")")) cx = cx.prev; - if (cx.prev) { - if (ch == "}" && (cx.type == "block" || cx.type == "top" || - cx.type == "interpolation" || cx.type == "restricted_atBlock")) { - // Resume indentation from parent context. - cx = cx.prev; - indent = cx.indent; - } else if (ch == ")" && (cx.type == "parens" || cx.type == "atBlock_parens") || - ch == "{" && (cx.type == "at" || cx.type == "atBlock")) { - // Dedent relative to current context. - indent = Math.max(0, cx.indent - indentUnit); - } - } - return indent; - }, - - electricChars: "}", - blockCommentStart: "/*", - blockCommentEnd: "*/", - blockCommentContinue: " * ", - lineComment: lineComment, - fold: "brace" - }; -}); - - function keySet(array) { - var keys = {}; - for (var i = 0; i < array.length; ++i) { - keys[array[i].toLowerCase()] = true; - } - return keys; - } - - var documentTypes_ = [ - "domain", "regexp", "url", "url-prefix" - ], documentTypes = keySet(documentTypes_); - - var mediaTypes_ = [ - "all", "aural", "braille", "handheld", "print", "projection", "screen", - "tty", "tv", "embossed" - ], mediaTypes = keySet(mediaTypes_); - - var mediaFeatures_ = [ - "width", "min-width", "max-width", "height", "min-height", "max-height", - "device-width", "min-device-width", "max-device-width", "device-height", - "min-device-height", "max-device-height", "aspect-ratio", - "min-aspect-ratio", "max-aspect-ratio", "device-aspect-ratio", - "min-device-aspect-ratio", "max-device-aspect-ratio", "color", "min-color", - "max-color", "color-index", "min-color-index", "max-color-index", - "monochrome", "min-monochrome", "max-monochrome", "resolution", - "min-resolution", "max-resolution", "scan", "grid", "orientation", - "device-pixel-ratio", "min-device-pixel-ratio", "max-device-pixel-ratio", - "pointer", "any-pointer", "hover", "any-hover", "prefers-color-scheme", - "dynamic-range", "video-dynamic-range" - ], mediaFeatures = keySet(mediaFeatures_); - - var mediaValueKeywords_ = [ - "landscape", "portrait", "none", "coarse", "fine", "on-demand", "hover", - "interlace", "progressive", - "dark", "light", - "standard", "high" - ], mediaValueKeywords = keySet(mediaValueKeywords_); - - var propertyKeywords_ = [ - "align-content", "align-items", "align-self", "alignment-adjust", - "alignment-baseline", "all", "anchor-point", "animation", "animation-delay", - "animation-direction", "animation-duration", "animation-fill-mode", - "animation-iteration-count", "animation-name", "animation-play-state", - "animation-timing-function", "appearance", "azimuth", "backdrop-filter", - "backface-visibility", "background", "background-attachment", - "background-blend-mode", "background-clip", "background-color", - "background-image", "background-origin", "background-position", - "background-position-x", "background-position-y", "background-repeat", - "background-size", "baseline-shift", "binding", "bleed", "block-size", - "bookmark-label", "bookmark-level", "bookmark-state", "bookmark-target", - "border", "border-bottom", "border-bottom-color", "border-bottom-left-radius", - "border-bottom-right-radius", "border-bottom-style", "border-bottom-width", - "border-collapse", "border-color", "border-image", "border-image-outset", - "border-image-repeat", "border-image-slice", "border-image-source", - "border-image-width", "border-left", "border-left-color", "border-left-style", - "border-left-width", "border-radius", "border-right", "border-right-color", - "border-right-style", "border-right-width", "border-spacing", "border-style", - "border-top", "border-top-color", "border-top-left-radius", - "border-top-right-radius", "border-top-style", "border-top-width", - "border-width", "bottom", "box-decoration-break", "box-shadow", "box-sizing", - "break-after", "break-before", "break-inside", "caption-side", "caret-color", - "clear", "clip", "color", "color-profile", "column-count", "column-fill", - "column-gap", "column-rule", "column-rule-color", "column-rule-style", - "column-rule-width", "column-span", "column-width", "columns", "contain", - "content", "counter-increment", "counter-reset", "crop", "cue", "cue-after", - "cue-before", "cursor", "direction", "display", "dominant-baseline", - "drop-initial-after-adjust", "drop-initial-after-align", - "drop-initial-before-adjust", "drop-initial-before-align", "drop-initial-size", - "drop-initial-value", "elevation", "empty-cells", "fit", "fit-content", "fit-position", - "flex", "flex-basis", "flex-direction", "flex-flow", "flex-grow", - "flex-shrink", "flex-wrap", "float", "float-offset", "flow-from", "flow-into", - "font", "font-family", "font-feature-settings", "font-kerning", - "font-language-override", "font-optical-sizing", "font-size", - "font-size-adjust", "font-stretch", "font-style", "font-synthesis", - "font-variant", "font-variant-alternates", "font-variant-caps", - "font-variant-east-asian", "font-variant-ligatures", "font-variant-numeric", - "font-variant-position", "font-variation-settings", "font-weight", "gap", - "grid", "grid-area", "grid-auto-columns", "grid-auto-flow", "grid-auto-rows", - "grid-column", "grid-column-end", "grid-column-gap", "grid-column-start", - "grid-gap", "grid-row", "grid-row-end", "grid-row-gap", "grid-row-start", - "grid-template", "grid-template-areas", "grid-template-columns", - "grid-template-rows", "hanging-punctuation", "height", "hyphens", "icon", - "image-orientation", "image-rendering", "image-resolution", "inline-box-align", - "inset", "inset-block", "inset-block-end", "inset-block-start", "inset-inline", - "inset-inline-end", "inset-inline-start", "isolation", "justify-content", - "justify-items", "justify-self", "left", "letter-spacing", "line-break", - "line-height", "line-height-step", "line-stacking", "line-stacking-ruby", - "line-stacking-shift", "line-stacking-strategy", "list-style", - "list-style-image", "list-style-position", "list-style-type", "margin", - "margin-bottom", "margin-left", "margin-right", "margin-top", "marks", - "marquee-direction", "marquee-loop", "marquee-play-count", "marquee-speed", - "marquee-style", "mask-clip", "mask-composite", "mask-image", "mask-mode", - "mask-origin", "mask-position", "mask-repeat", "mask-size","mask-type", - "max-block-size", "max-height", "max-inline-size", - "max-width", "min-block-size", "min-height", "min-inline-size", "min-width", - "mix-blend-mode", "move-to", "nav-down", "nav-index", "nav-left", "nav-right", - "nav-up", "object-fit", "object-position", "offset", "offset-anchor", - "offset-distance", "offset-path", "offset-position", "offset-rotate", - "opacity", "order", "orphans", "outline", "outline-color", "outline-offset", - "outline-style", "outline-width", "overflow", "overflow-style", - "overflow-wrap", "overflow-x", "overflow-y", "padding", "padding-bottom", - "padding-left", "padding-right", "padding-top", "page", "page-break-after", - "page-break-before", "page-break-inside", "page-policy", "pause", - "pause-after", "pause-before", "perspective", "perspective-origin", "pitch", - "pitch-range", "place-content", "place-items", "place-self", "play-during", - "position", "presentation-level", "punctuation-trim", "quotes", - "region-break-after", "region-break-before", "region-break-inside", - "region-fragment", "rendering-intent", "resize", "rest", "rest-after", - "rest-before", "richness", "right", "rotate", "rotation", "rotation-point", - "row-gap", "ruby-align", "ruby-overhang", "ruby-position", "ruby-span", - "scale", "scroll-behavior", "scroll-margin", "scroll-margin-block", - "scroll-margin-block-end", "scroll-margin-block-start", "scroll-margin-bottom", - "scroll-margin-inline", "scroll-margin-inline-end", - "scroll-margin-inline-start", "scroll-margin-left", "scroll-margin-right", - "scroll-margin-top", "scroll-padding", "scroll-padding-block", - "scroll-padding-block-end", "scroll-padding-block-start", - "scroll-padding-bottom", "scroll-padding-inline", "scroll-padding-inline-end", - "scroll-padding-inline-start", "scroll-padding-left", "scroll-padding-right", - "scroll-padding-top", "scroll-snap-align", "scroll-snap-type", - "shape-image-threshold", "shape-inside", "shape-margin", "shape-outside", - "size", "speak", "speak-as", "speak-header", "speak-numeral", - "speak-punctuation", "speech-rate", "stress", "string-set", "tab-size", - "table-layout", "target", "target-name", "target-new", "target-position", - "text-align", "text-align-last", "text-combine-upright", "text-decoration", - "text-decoration-color", "text-decoration-line", "text-decoration-skip", - "text-decoration-skip-ink", "text-decoration-style", "text-emphasis", - "text-emphasis-color", "text-emphasis-position", "text-emphasis-style", - "text-height", "text-indent", "text-justify", "text-orientation", - "text-outline", "text-overflow", "text-rendering", "text-shadow", - "text-size-adjust", "text-space-collapse", "text-transform", - "text-underline-position", "text-wrap", "top", "touch-action", "transform", "transform-origin", - "transform-style", "transition", "transition-delay", "transition-duration", - "transition-property", "transition-timing-function", "translate", - "unicode-bidi", "user-select", "vertical-align", "visibility", "voice-balance", - "voice-duration", "voice-family", "voice-pitch", "voice-range", "voice-rate", - "voice-stress", "voice-volume", "volume", "white-space", "widows", "width", - "will-change", "word-break", "word-spacing", "word-wrap", "writing-mode", "z-index", - // SVG-specific - "clip-path", "clip-rule", "mask", "enable-background", "filter", "flood-color", - "flood-opacity", "lighting-color", "stop-color", "stop-opacity", "pointer-events", - "color-interpolation", "color-interpolation-filters", - "color-rendering", "fill", "fill-opacity", "fill-rule", "image-rendering", - "marker", "marker-end", "marker-mid", "marker-start", "paint-order", "shape-rendering", "stroke", - "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", - "stroke-miterlimit", "stroke-opacity", "stroke-width", "text-rendering", - "baseline-shift", "dominant-baseline", "glyph-orientation-horizontal", - "glyph-orientation-vertical", "text-anchor", "writing-mode", - ], propertyKeywords = keySet(propertyKeywords_); - - var nonStandardPropertyKeywords_ = [ - "accent-color", "aspect-ratio", "border-block", "border-block-color", "border-block-end", - "border-block-end-color", "border-block-end-style", "border-block-end-width", - "border-block-start", "border-block-start-color", "border-block-start-style", - "border-block-start-width", "border-block-style", "border-block-width", - "border-inline", "border-inline-color", "border-inline-end", - "border-inline-end-color", "border-inline-end-style", - "border-inline-end-width", "border-inline-start", "border-inline-start-color", - "border-inline-start-style", "border-inline-start-width", - "border-inline-style", "border-inline-width", "content-visibility", "margin-block", - "margin-block-end", "margin-block-start", "margin-inline", "margin-inline-end", - "margin-inline-start", "overflow-anchor", "overscroll-behavior", "padding-block", "padding-block-end", - "padding-block-start", "padding-inline", "padding-inline-end", - "padding-inline-start", "scroll-snap-stop", "scrollbar-3d-light-color", - "scrollbar-arrow-color", "scrollbar-base-color", "scrollbar-dark-shadow-color", - "scrollbar-face-color", "scrollbar-highlight-color", "scrollbar-shadow-color", - "scrollbar-track-color", "searchfield-cancel-button", "searchfield-decoration", - "searchfield-results-button", "searchfield-results-decoration", "shape-inside", "zoom" - ], nonStandardPropertyKeywords = keySet(nonStandardPropertyKeywords_); - - var fontProperties_ = [ - "font-display", "font-family", "src", "unicode-range", "font-variant", - "font-feature-settings", "font-stretch", "font-weight", "font-style" - ], fontProperties = keySet(fontProperties_); - - var counterDescriptors_ = [ - "additive-symbols", "fallback", "negative", "pad", "prefix", "range", - "speak-as", "suffix", "symbols", "system" - ], counterDescriptors = keySet(counterDescriptors_); - - var colorKeywords_ = [ - "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", "grey", "green", "greenyellow", "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", "rebeccapurple", "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" - ], colorKeywords = keySet(colorKeywords_); - - var valueKeywords_ = [ - "above", "absolute", "activeborder", "additive", "activecaption", "afar", - "after-white-space", "ahead", "alias", "all", "all-scroll", "alphabetic", "alternate", - "always", "amharic", "amharic-abegede", "antialiased", "appworkspace", - "arabic-indic", "armenian", "asterisks", "attr", "auto", "auto-flow", "avoid", "avoid-column", "avoid-page", - "avoid-region", "axis-pan", "background", "backwards", "baseline", "below", "bidi-override", "binary", - "bengali", "blink", "block", "block-axis", "blur", "bold", "bolder", "border", "border-box", - "both", "bottom", "break", "break-all", "break-word", "brightness", "bullets", "button", "button-bevel", - "buttonface", "buttonhighlight", "buttonshadow", "buttontext", "calc", "cambodian", - "capitalize", "caps-lock-indicator", "caption", "captiontext", "caret", - "cell", "center", "checkbox", "circle", "cjk-decimal", "cjk-earthly-branch", - "cjk-heavenly-stem", "cjk-ideographic", "clear", "clip", "close-quote", - "col-resize", "collapse", "color", "color-burn", "color-dodge", "column", "column-reverse", - "compact", "condensed", "conic-gradient", "contain", "content", "contents", - "content-box", "context-menu", "continuous", "contrast", "copy", "counter", "counters", "cover", "crop", - "cross", "crosshair", "cubic-bezier", "currentcolor", "cursive", "cyclic", "darken", "dashed", "decimal", - "decimal-leading-zero", "default", "default-button", "dense", "destination-atop", - "destination-in", "destination-out", "destination-over", "devanagari", "difference", - "disc", "discard", "disclosure-closed", "disclosure-open", "document", - "dot-dash", "dot-dot-dash", - "dotted", "double", "down", "drop-shadow", "e-resize", "ease", "ease-in", "ease-in-out", "ease-out", - "element", "ellipse", "ellipsis", "embed", "end", "ethiopic", "ethiopic-abegede", - "ethiopic-abegede-am-et", "ethiopic-abegede-gez", "ethiopic-abegede-ti-er", - "ethiopic-abegede-ti-et", "ethiopic-halehame-aa-er", - "ethiopic-halehame-aa-et", "ethiopic-halehame-am-et", - "ethiopic-halehame-gez", "ethiopic-halehame-om-et", - "ethiopic-halehame-sid-et", "ethiopic-halehame-so-et", - "ethiopic-halehame-ti-er", "ethiopic-halehame-ti-et", "ethiopic-halehame-tig", - "ethiopic-numeric", "ew-resize", "exclusion", "expanded", "extends", "extra-condensed", - "extra-expanded", "fantasy", "fast", "fill", "fill-box", "fixed", "flat", "flex", "flex-end", "flex-start", "footnotes", - "forwards", "from", "geometricPrecision", "georgian", "grayscale", "graytext", "grid", "groove", - "gujarati", "gurmukhi", "hand", "hangul", "hangul-consonant", "hard-light", "hebrew", - "help", "hidden", "hide", "higher", "highlight", "highlighttext", - "hiragana", "hiragana-iroha", "horizontal", "hsl", "hsla", "hue", "hue-rotate", "icon", "ignore", - "inactiveborder", "inactivecaption", "inactivecaptiontext", "infinite", - "infobackground", "infotext", "inherit", "initial", "inline", "inline-axis", - "inline-block", "inline-flex", "inline-grid", "inline-table", "inset", "inside", "intrinsic", "invert", - "italic", "japanese-formal", "japanese-informal", "justify", "kannada", - "katakana", "katakana-iroha", "keep-all", "khmer", - "korean-hangul-formal", "korean-hanja-formal", "korean-hanja-informal", - "landscape", "lao", "large", "larger", "left", "level", "lighter", "lighten", - "line-through", "linear", "linear-gradient", "lines", "list-item", "listbox", "listitem", - "local", "logical", "loud", "lower", "lower-alpha", "lower-armenian", - "lower-greek", "lower-hexadecimal", "lower-latin", "lower-norwegian", - "lower-roman", "lowercase", "ltr", "luminosity", "malayalam", "manipulation", "match", "matrix", "matrix3d", - "media-controls-background", "media-current-time-display", - "media-fullscreen-button", "media-mute-button", "media-play-button", - "media-return-to-realtime-button", "media-rewind-button", - "media-seek-back-button", "media-seek-forward-button", "media-slider", - "media-sliderthumb", "media-time-remaining-display", "media-volume-slider", - "media-volume-slider-container", "media-volume-sliderthumb", "medium", - "menu", "menulist", "menulist-button", "menulist-text", - "menulist-textfield", "menutext", "message-box", "middle", "min-intrinsic", - "mix", "mongolian", "monospace", "move", "multiple", "multiple_mask_images", "multiply", "myanmar", "n-resize", - "narrower", "ne-resize", "nesw-resize", "no-close-quote", "no-drop", - "no-open-quote", "no-repeat", "none", "normal", "not-allowed", "nowrap", - "ns-resize", "numbers", "numeric", "nw-resize", "nwse-resize", "oblique", "octal", "opacity", "open-quote", - "optimizeLegibility", "optimizeSpeed", "oriya", "oromo", "outset", - "outside", "outside-shape", "overlay", "overline", "padding", "padding-box", - "painted", "page", "paused", "persian", "perspective", "pinch-zoom", "plus-darker", "plus-lighter", - "pointer", "polygon", "portrait", "pre", "pre-line", "pre-wrap", "preserve-3d", - "progress", "push-button", "radial-gradient", "radio", "read-only", - "read-write", "read-write-plaintext-only", "rectangle", "region", - "relative", "repeat", "repeating-linear-gradient", "repeating-radial-gradient", - "repeating-conic-gradient", "repeat-x", "repeat-y", "reset", "reverse", - "rgb", "rgba", "ridge", "right", "rotate", "rotate3d", "rotateX", "rotateY", - "rotateZ", "round", "row", "row-resize", "row-reverse", "rtl", "run-in", "running", - "s-resize", "sans-serif", "saturate", "saturation", "scale", "scale3d", "scaleX", "scaleY", "scaleZ", "screen", - "scroll", "scrollbar", "scroll-position", "se-resize", "searchfield", - "searchfield-cancel-button", "searchfield-decoration", - "searchfield-results-button", "searchfield-results-decoration", "self-start", "self-end", - "semi-condensed", "semi-expanded", "separate", "sepia", "serif", "show", "sidama", - "simp-chinese-formal", "simp-chinese-informal", "single", - "skew", "skewX", "skewY", "skip-white-space", "slide", "slider-horizontal", - "slider-vertical", "sliderthumb-horizontal", "sliderthumb-vertical", "slow", - "small", "small-caps", "small-caption", "smaller", "soft-light", "solid", "somali", - "source-atop", "source-in", "source-out", "source-over", "space", "space-around", "space-between", "space-evenly", "spell-out", "square", - "square-button", "start", "static", "status-bar", "stretch", "stroke", "stroke-box", "sub", - "subpixel-antialiased", "svg_masks", "super", "sw-resize", "symbolic", "symbols", "system-ui", "table", - "table-caption", "table-cell", "table-column", "table-column-group", - "table-footer-group", "table-header-group", "table-row", "table-row-group", - "tamil", - "telugu", "text", "text-bottom", "text-top", "textarea", "textfield", "thai", - "thick", "thin", "threeddarkshadow", "threedface", "threedhighlight", - "threedlightshadow", "threedshadow", "tibetan", "tigre", "tigrinya-er", - "tigrinya-er-abegede", "tigrinya-et", "tigrinya-et-abegede", "to", "top", - "trad-chinese-formal", "trad-chinese-informal", "transform", - "translate", "translate3d", "translateX", "translateY", "translateZ", - "transparent", "ultra-condensed", "ultra-expanded", "underline", "unidirectional-pan", "unset", "up", - "upper-alpha", "upper-armenian", "upper-greek", "upper-hexadecimal", - "upper-latin", "upper-norwegian", "upper-roman", "uppercase", "urdu", "url", - "var", "vertical", "vertical-text", "view-box", "visible", "visibleFill", "visiblePainted", - "visibleStroke", "visual", "w-resize", "wait", "wave", "wider", - "window", "windowframe", "windowtext", "words", "wrap", "wrap-reverse", "x-large", "x-small", "xor", - "xx-large", "xx-small" - ], valueKeywords = keySet(valueKeywords_); - - var allWords = documentTypes_.concat(mediaTypes_).concat(mediaFeatures_).concat(mediaValueKeywords_) - .concat(propertyKeywords_).concat(nonStandardPropertyKeywords_).concat(colorKeywords_) - .concat(valueKeywords_); - CodeMirror.registerHelper("hintWords", "css", allWords); - - function tokenCComment(stream, state) { - var maybeEnd = false, ch; - while ((ch = stream.next()) != null) { - if (maybeEnd && ch == "/") { - state.tokenize = null; - break; - } - maybeEnd = (ch == "*"); - } - return ["comment", "comment"]; - } - - CodeMirror.defineMIME("text/css", { - documentTypes: documentTypes, - mediaTypes: mediaTypes, - mediaFeatures: mediaFeatures, - mediaValueKeywords: mediaValueKeywords, - propertyKeywords: propertyKeywords, - nonStandardPropertyKeywords: nonStandardPropertyKeywords, - fontProperties: fontProperties, - counterDescriptors: counterDescriptors, - colorKeywords: colorKeywords, - valueKeywords: valueKeywords, - tokenHooks: { - "/": function(stream, state) { - if (!stream.eat("*")) return false; - state.tokenize = tokenCComment; - return tokenCComment(stream, state); - } - }, - name: "css" - }); - - CodeMirror.defineMIME("text/x-scss", { - mediaTypes: mediaTypes, - mediaFeatures: mediaFeatures, - mediaValueKeywords: mediaValueKeywords, - propertyKeywords: propertyKeywords, - nonStandardPropertyKeywords: nonStandardPropertyKeywords, - colorKeywords: colorKeywords, - valueKeywords: valueKeywords, - fontProperties: fontProperties, - allowNested: true, - lineComment: "//", - tokenHooks: { - "/": function(stream, state) { - if (stream.eat("/")) { - stream.skipToEnd(); - return ["comment", "comment"]; - } else if (stream.eat("*")) { - state.tokenize = tokenCComment; - return tokenCComment(stream, state); - } else { - return ["operator", "operator"]; - } - }, - ":": function(stream) { - if (stream.match(/^\s*\{/, false)) - return [null, null] - return false; - }, - "$": function(stream) { - stream.match(/^[\w-]+/); - if (stream.match(/^\s*:/, false)) - return ["variable-2", "variable-definition"]; - return ["variable-2", "variable"]; - }, - "#": function(stream) { - if (!stream.eat("{")) return false; - return [null, "interpolation"]; - } - }, - name: "css", - helperType: "scss" - }); - - CodeMirror.defineMIME("text/x-less", { - mediaTypes: mediaTypes, - mediaFeatures: mediaFeatures, - mediaValueKeywords: mediaValueKeywords, - propertyKeywords: propertyKeywords, - nonStandardPropertyKeywords: nonStandardPropertyKeywords, - colorKeywords: colorKeywords, - valueKeywords: valueKeywords, - fontProperties: fontProperties, - allowNested: true, - lineComment: "//", - tokenHooks: { - "/": function(stream, state) { - if (stream.eat("/")) { - stream.skipToEnd(); - return ["comment", "comment"]; - } else if (stream.eat("*")) { - state.tokenize = tokenCComment; - return tokenCComment(stream, state); - } else { - return ["operator", "operator"]; - } - }, - "@": function(stream) { - if (stream.eat("{")) return [null, "interpolation"]; - if (stream.match(/^(charset|document|font-face|import|(-(moz|ms|o|webkit)-)?keyframes|media|namespace|page|supports)\b/i, false)) return false; - stream.eatWhile(/[\w\\\-]/); - if (stream.match(/^\s*:/, false)) - return ["variable-2", "variable-definition"]; - return ["variable-2", "variable"]; - }, - "&": function() { - return ["atom", "atom"]; - } - }, - name: "css", - helperType: "less" - }); - - CodeMirror.defineMIME("text/x-gss", { - documentTypes: documentTypes, - mediaTypes: mediaTypes, - mediaFeatures: mediaFeatures, - propertyKeywords: propertyKeywords, - nonStandardPropertyKeywords: nonStandardPropertyKeywords, - fontProperties: fontProperties, - counterDescriptors: counterDescriptors, - colorKeywords: colorKeywords, - valueKeywords: valueKeywords, - supportsAtComponent: true, - tokenHooks: { - "/": function(stream, state) { - if (!stream.eat("*")) return false; - state.tokenize = tokenCComment; - return tokenCComment(stream, state); - } - }, - name: "css", - helperType: "gss" - }); - -}); diff --git a/www/js/codemirror/mode/htmlmixed/htmlmixed.js b/www/js/codemirror/mode/htmlmixed/htmlmixed.js deleted file mode 100644 index af31381..0000000 --- a/www/js/codemirror/mode/htmlmixed/htmlmixed.js +++ /dev/null @@ -1,153 +0,0 @@ -// CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE - -(function(mod) { - if (typeof exports == "object" && typeof module == "object") // CommonJS - mod(require("../../lib/codemirror"), require("../xml/xml"), require("../javascript/javascript"), require("../css/css")); - else if (typeof define == "function" && define.amd) // AMD - define(["../../lib/codemirror", "../xml/xml", "../javascript/javascript", "../css/css"], mod); - else // Plain browser env - mod(CodeMirror); -})(function(CodeMirror) { - "use strict"; - - var defaultTags = { - script: [ - ["lang", /(javascript|babel)/i, "javascript"], - ["type", /^(?:text|application)\/(?:x-)?(?:java|ecma)script$|^module$|^$/i, "javascript"], - ["type", /./, "text/plain"], - [null, null, "javascript"] - ], - style: [ - ["lang", /^css$/i, "css"], - ["type", /^(text\/)?(x-)?(stylesheet|css)$/i, "css"], - ["type", /./, "text/plain"], - [null, null, "css"] - ] - }; - - function maybeBackup(stream, pat, style) { - var cur = stream.current(), close = cur.search(pat); - if (close > -1) { - stream.backUp(cur.length - close); - } else if (cur.match(/<\/?$/)) { - stream.backUp(cur.length); - if (!stream.match(pat, false)) stream.match(cur); - } - return style; - } - - var attrRegexpCache = {}; - function getAttrRegexp(attr) { - var regexp = attrRegexpCache[attr]; - if (regexp) return regexp; - return attrRegexpCache[attr] = new RegExp("\\s+" + attr + "\\s*=\\s*('|\")?([^'\"]+)('|\")?\\s*"); - } - - function getAttrValue(text, attr) { - var match = text.match(getAttrRegexp(attr)) - return match ? /^\s*(.*?)\s*$/.exec(match[2])[1] : "" - } - - function getTagRegexp(tagName, anchored) { - return new RegExp((anchored ? "^" : "") + "<\/\\s*" + tagName + "\\s*>", "i"); - } - - function addTags(from, to) { - for (var tag in from) { - var dest = to[tag] || (to[tag] = []); - var source = from[tag]; - for (var i = source.length - 1; i >= 0; i--) - dest.unshift(source[i]) - } - } - - function findMatchingMode(tagInfo, tagText) { - for (var i = 0; i < tagInfo.length; i++) { - var spec = tagInfo[i]; - if (!spec[0] || spec[1].test(getAttrValue(tagText, spec[0]))) return spec[2]; - } - } - - CodeMirror.defineMode("htmlmixed", function (config, parserConfig) { - var htmlMode = CodeMirror.getMode(config, { - name: "xml", - htmlMode: true, - multilineTagIndentFactor: parserConfig.multilineTagIndentFactor, - multilineTagIndentPastTag: parserConfig.multilineTagIndentPastTag, - allowMissingTagName: parserConfig.allowMissingTagName, - }); - - var tags = {}; - var configTags = parserConfig && parserConfig.tags, configScript = parserConfig && parserConfig.scriptTypes; - addTags(defaultTags, tags); - if (configTags) addTags(configTags, tags); - if (configScript) for (var i = configScript.length - 1; i >= 0; i--) - tags.script.unshift(["type", configScript[i].matches, configScript[i].mode]) - - function html(stream, state) { - var style = htmlMode.token(stream, state.htmlState), tag = /\btag\b/.test(style), tagName - if (tag && !/[<>\s\/]/.test(stream.current()) && - (tagName = state.htmlState.tagName && state.htmlState.tagName.toLowerCase()) && - tags.hasOwnProperty(tagName)) { - state.inTag = tagName + " " - } else if (state.inTag && tag && />$/.test(stream.current())) { - var inTag = /^([\S]+) (.*)/.exec(state.inTag) - state.inTag = null - var modeSpec = stream.current() == ">" && findMatchingMode(tags[inTag[1]], inTag[2]) - var mode = CodeMirror.getMode(config, modeSpec) - var endTagA = getTagRegexp(inTag[1], true), endTag = getTagRegexp(inTag[1], false); - state.token = function (stream, state) { - if (stream.match(endTagA, false)) { - state.token = html; - state.localState = state.localMode = null; - return null; - } - return maybeBackup(stream, endTag, state.localMode.token(stream, state.localState)); - }; - state.localMode = mode; - state.localState = CodeMirror.startState(mode, htmlMode.indent(state.htmlState, "", "")); - } else if (state.inTag) { - state.inTag += stream.current() - if (stream.eol()) state.inTag += " " - } - return style; - }; - - return { - startState: function () { - var state = CodeMirror.startState(htmlMode); - return {token: html, inTag: null, localMode: null, localState: null, htmlState: state}; - }, - - copyState: function (state) { - var local; - if (state.localState) { - local = CodeMirror.copyState(state.localMode, state.localState); - } - return {token: state.token, inTag: state.inTag, - localMode: state.localMode, localState: local, - htmlState: CodeMirror.copyState(htmlMode, state.htmlState)}; - }, - - token: function (stream, state) { - return state.token(stream, state); - }, - - indent: function (state, textAfter, line) { - if (!state.localMode || /^\s*<\//.test(textAfter)) - return htmlMode.indent(state.htmlState, textAfter, line); - else if (state.localMode.indent) - return state.localMode.indent(state.localState, textAfter, line); - else - return CodeMirror.Pass; - }, - - innerMode: function (state) { - return {state: state.localState || state.htmlState, mode: state.localMode || htmlMode}; - } - }; - }, "xml", "javascript", "css"); - - CodeMirror.defineMIME("text/html", "htmlmixed"); -}); diff --git a/www/js/codemirror/mode/javascript/javascript.js b/www/js/codemirror/mode/javascript/javascript.js deleted file mode 100644 index 7cfee31..0000000 --- a/www/js/codemirror/mode/javascript/javascript.js +++ /dev/null @@ -1,960 +0,0 @@ -// CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE - -(function(mod) { - if (typeof exports == "object" && typeof module == "object") // CommonJS - mod(require("../../lib/codemirror")); - else if (typeof define == "function" && define.amd) // AMD - define(["../../lib/codemirror"], mod); - else // Plain browser env - mod(CodeMirror); -})(function(CodeMirror) { -"use strict"; - -CodeMirror.defineMode("javascript", function(config, parserConfig) { - var indentUnit = config.indentUnit; - var statementIndent = parserConfig.statementIndent; - var jsonldMode = parserConfig.jsonld; - var jsonMode = parserConfig.json || jsonldMode; - var trackScope = parserConfig.trackScope !== false - var isTS = parserConfig.typescript; - var wordRE = parserConfig.wordCharacters || /[\w$\xa1-\uffff]/; - - // Tokenizer - - var keywords = function(){ - function kw(type) {return {type: type, style: "keyword"};} - var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c"), D = kw("keyword d"); - var operator = kw("operator"), atom = {type: "atom", style: "atom"}; - - return { - "if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B, - "return": D, "break": D, "continue": D, "new": kw("new"), "delete": C, "void": C, "throw": C, - "debugger": kw("debugger"), "var": kw("var"), "const": kw("var"), "let": kw("var"), - "function": kw("function"), "catch": kw("catch"), - "for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"), - "in": operator, "typeof": operator, "instanceof": operator, - "true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom, - "this": kw("this"), "class": kw("class"), "super": kw("atom"), - "yield": C, "export": kw("export"), "import": kw("import"), "extends": C, - "await": C - }; - }(); - - var isOperatorChar = /[+\-*&%=<>!?|~^@]/; - var isJsonldKeyword = /^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/; - - function readRegexp(stream) { - var escaped = false, next, inSet = false; - while ((next = stream.next()) != null) { - if (!escaped) { - if (next == "/" && !inSet) return; - if (next == "[") inSet = true; - else if (inSet && next == "]") inSet = false; - } - escaped = !escaped && next == "\\"; - } - } - - // Used as scratch variables to communicate multiple values without - // consing up tons of objects. - var type, content; - function ret(tp, style, cont) { - type = tp; content = cont; - return style; - } - function tokenBase(stream, state) { - var ch = stream.next(); - if (ch == '"' || ch == "'") { - state.tokenize = tokenString(ch); - return state.tokenize(stream, state); - } else if (ch == "." && stream.match(/^\d[\d_]*(?:[eE][+\-]?[\d_]+)?/)) { - return ret("number", "number"); - } else if (ch == "." && stream.match("..")) { - return ret("spread", "meta"); - } else if (/[\[\]{}\(\),;\:\.]/.test(ch)) { - return ret(ch); - } else if (ch == "=" && stream.eat(">")) { - return ret("=>", "operator"); - } else if (ch == "0" && stream.match(/^(?:x[\dA-Fa-f_]+|o[0-7_]+|b[01_]+)n?/)) { - return ret("number", "number"); - } else if (/\d/.test(ch)) { - stream.match(/^[\d_]*(?:n|(?:\.[\d_]*)?(?:[eE][+\-]?[\d_]+)?)?/); - return ret("number", "number"); - } else if (ch == "/") { - if (stream.eat("*")) { - state.tokenize = tokenComment; - return tokenComment(stream, state); - } else if (stream.eat("/")) { - stream.skipToEnd(); - return ret("comment", "comment"); - } else if (expressionAllowed(stream, state, 1)) { - readRegexp(stream); - stream.match(/^\b(([gimyus])(?![gimyus]*\2))+\b/); - return ret("regexp", "string-2"); - } else { - stream.eat("="); - return ret("operator", "operator", stream.current()); - } - } else if (ch == "`") { - state.tokenize = tokenQuasi; - return tokenQuasi(stream, state); - } else if (ch == "#" && stream.peek() == "!") { - stream.skipToEnd(); - return ret("meta", "meta"); - } else if (ch == "#" && stream.eatWhile(wordRE)) { - return ret("variable", "property") - } else if (ch == "<" && stream.match("!--") || - (ch == "-" && stream.match("->") && !/\S/.test(stream.string.slice(0, stream.start)))) { - stream.skipToEnd() - return ret("comment", "comment") - } else if (isOperatorChar.test(ch)) { - if (ch != ">" || !state.lexical || state.lexical.type != ">") { - if (stream.eat("=")) { - if (ch == "!" || ch == "=") stream.eat("=") - } else if (/[<>*+\-|&?]/.test(ch)) { - stream.eat(ch) - if (ch == ">") stream.eat(ch) - } - } - if (ch == "?" && stream.eat(".")) return ret(".") - return ret("operator", "operator", stream.current()); - } else if (wordRE.test(ch)) { - stream.eatWhile(wordRE); - var word = stream.current() - if (state.lastType != ".") { - if (keywords.propertyIsEnumerable(word)) { - var kw = keywords[word] - return ret(kw.type, kw.style, word) - } - if (word == "async" && stream.match(/^(\s|\/\*([^*]|\*(?!\/))*?\*\/)*[\[\(\w]/, false)) - return ret("async", "keyword", word) - } - return ret("variable", "variable", word) - } - } - - function tokenString(quote) { - return function(stream, state) { - var escaped = false, next; - if (jsonldMode && stream.peek() == "@" && stream.match(isJsonldKeyword)){ - state.tokenize = tokenBase; - return ret("jsonld-keyword", "meta"); - } - while ((next = stream.next()) != null) { - if (next == quote && !escaped) break; - escaped = !escaped && next == "\\"; - } - if (!escaped) state.tokenize = tokenBase; - return ret("string", "string"); - }; - } - - function tokenComment(stream, state) { - var maybeEnd = false, ch; - while (ch = stream.next()) { - if (ch == "/" && maybeEnd) { - state.tokenize = tokenBase; - break; - } - maybeEnd = (ch == "*"); - } - return ret("comment", "comment"); - } - - function tokenQuasi(stream, state) { - var escaped = false, next; - while ((next = stream.next()) != null) { - if (!escaped && (next == "`" || next == "$" && stream.eat("{"))) { - state.tokenize = tokenBase; - break; - } - escaped = !escaped && next == "\\"; - } - return ret("quasi", "string-2", stream.current()); - } - - var brackets = "([{}])"; - // This is a crude lookahead trick to try and notice that we're - // parsing the argument patterns for a fat-arrow function before we - // actually hit the arrow token. It only works if the arrow is on - // the same line as the arguments and there's no strange noise - // (comments) in between. Fallback is to only notice when we hit the - // arrow, and not declare the arguments as locals for the arrow - // body. - function findFatArrow(stream, state) { - if (state.fatArrowAt) state.fatArrowAt = null; - var arrow = stream.string.indexOf("=>", stream.start); - if (arrow < 0) return; - - if (isTS) { // Try to skip TypeScript return type declarations after the arguments - var m = /:\s*(?:\w+(?:<[^>]*>|\[\])?|\{[^}]*\})\s*$/.exec(stream.string.slice(stream.start, arrow)) - if (m) arrow = m.index - } - - var depth = 0, sawSomething = false; - for (var pos = arrow - 1; pos >= 0; --pos) { - var ch = stream.string.charAt(pos); - var bracket = brackets.indexOf(ch); - if (bracket >= 0 && bracket < 3) { - if (!depth) { ++pos; break; } - if (--depth == 0) { if (ch == "(") sawSomething = true; break; } - } else if (bracket >= 3 && bracket < 6) { - ++depth; - } else if (wordRE.test(ch)) { - sawSomething = true; - } else if (/["'\/`]/.test(ch)) { - for (;; --pos) { - if (pos == 0) return - var next = stream.string.charAt(pos - 1) - if (next == ch && stream.string.charAt(pos - 2) != "\\") { pos--; break } - } - } else if (sawSomething && !depth) { - ++pos; - break; - } - } - if (sawSomething && !depth) state.fatArrowAt = pos; - } - - // Parser - - var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, - "regexp": true, "this": true, "import": true, "jsonld-keyword": true}; - - function JSLexical(indented, column, type, align, prev, info) { - this.indented = indented; - this.column = column; - this.type = type; - this.prev = prev; - this.info = info; - if (align != null) this.align = align; - } - - function inScope(state, varname) { - if (!trackScope) return false - for (var v = state.localVars; v; v = v.next) - if (v.name == varname) return true; - for (var cx = state.context; cx; cx = cx.prev) { - for (var v = cx.vars; v; v = v.next) - if (v.name == varname) return true; - } - } - - function parseJS(state, style, type, content, stream) { - var cc = state.cc; - // Communicate our context to the combinators. - // (Less wasteful than consing up a hundred closures on every call.) - cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc; cx.style = style; - - if (!state.lexical.hasOwnProperty("align")) - state.lexical.align = true; - - while(true) { - var combinator = cc.length ? cc.pop() : jsonMode ? expression : statement; - if (combinator(type, content)) { - while(cc.length && cc[cc.length - 1].lex) - cc.pop()(); - if (cx.marked) return cx.marked; - if (type == "variable" && inScope(state, content)) return "variable-2"; - return style; - } - } - } - - // Combinator utils - - var cx = {state: null, column: null, marked: null, cc: null}; - function pass() { - for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]); - } - function cont() { - pass.apply(null, arguments); - return true; - } - function inList(name, list) { - for (var v = list; v; v = v.next) if (v.name == name) return true - return false; - } - function register(varname) { - var state = cx.state; - cx.marked = "def"; - if (!trackScope) return - if (state.context) { - if (state.lexical.info == "var" && state.context && state.context.block) { - // FIXME function decls are also not block scoped - var newContext = registerVarScoped(varname, state.context) - if (newContext != null) { - state.context = newContext - return - } - } else if (!inList(varname, state.localVars)) { - state.localVars = new Var(varname, state.localVars) - return - } - } - // Fall through means this is global - if (parserConfig.globalVars && !inList(varname, state.globalVars)) - state.globalVars = new Var(varname, state.globalVars) - } - function registerVarScoped(varname, context) { - if (!context) { - return null - } else if (context.block) { - var inner = registerVarScoped(varname, context.prev) - if (!inner) return null - if (inner == context.prev) return context - return new Context(inner, context.vars, true) - } else if (inList(varname, context.vars)) { - return context - } else { - return new Context(context.prev, new Var(varname, context.vars), false) - } - } - - function isModifier(name) { - return name == "public" || name == "private" || name == "protected" || name == "abstract" || name == "readonly" - } - - // Combinators - - function Context(prev, vars, block) { this.prev = prev; this.vars = vars; this.block = block } - function Var(name, next) { this.name = name; this.next = next } - - var defaultVars = new Var("this", new Var("arguments", null)) - function pushcontext() { - cx.state.context = new Context(cx.state.context, cx.state.localVars, false) - cx.state.localVars = defaultVars - } - function pushblockcontext() { - cx.state.context = new Context(cx.state.context, cx.state.localVars, true) - cx.state.localVars = null - } - pushcontext.lex = pushblockcontext.lex = true - function popcontext() { - cx.state.localVars = cx.state.context.vars - cx.state.context = cx.state.context.prev - } - popcontext.lex = true - function pushlex(type, info) { - var result = function() { - var state = cx.state, indent = state.indented; - if (state.lexical.type == "stat") indent = state.lexical.indented; - else for (var outer = state.lexical; outer && outer.type == ")" && outer.align; outer = outer.prev) - indent = outer.indented; - state.lexical = new JSLexical(indent, cx.stream.column(), type, null, state.lexical, info); - }; - result.lex = true; - return result; - } - function poplex() { - var state = cx.state; - if (state.lexical.prev) { - if (state.lexical.type == ")") - state.indented = state.lexical.indented; - state.lexical = state.lexical.prev; - } - } - poplex.lex = true; - - function expect(wanted) { - function exp(type) { - if (type == wanted) return cont(); - else if (wanted == ";" || type == "}" || type == ")" || type == "]") return pass(); - else return cont(exp); - }; - return exp; - } - - function statement(type, value) { - if (type == "var") return cont(pushlex("vardef", value), vardef, expect(";"), poplex); - if (type == "keyword a") return cont(pushlex("form"), parenExpr, statement, poplex); - if (type == "keyword b") return cont(pushlex("form"), statement, poplex); - if (type == "keyword d") return cx.stream.match(/^\s*$/, false) ? cont() : cont(pushlex("stat"), maybeexpression, expect(";"), poplex); - if (type == "debugger") return cont(expect(";")); - if (type == "{") return cont(pushlex("}"), pushblockcontext, block, poplex, popcontext); - if (type == ";") return cont(); - if (type == "if") { - if (cx.state.lexical.info == "else" && cx.state.cc[cx.state.cc.length - 1] == poplex) - cx.state.cc.pop()(); - return cont(pushlex("form"), parenExpr, statement, poplex, maybeelse); - } - if (type == "function") return cont(functiondef); - if (type == "for") return cont(pushlex("form"), pushblockcontext, forspec, statement, popcontext, poplex); - if (type == "class" || (isTS && value == "interface")) { - cx.marked = "keyword" - return cont(pushlex("form", type == "class" ? type : value), className, poplex) - } - if (type == "variable") { - if (isTS && value == "declare") { - cx.marked = "keyword" - return cont(statement) - } else if (isTS && (value == "module" || value == "enum" || value == "type") && cx.stream.match(/^\s*\w/, false)) { - cx.marked = "keyword" - if (value == "enum") return cont(enumdef); - else if (value == "type") return cont(typename, expect("operator"), typeexpr, expect(";")); - else return cont(pushlex("form"), pattern, expect("{"), pushlex("}"), block, poplex, poplex) - } else if (isTS && value == "namespace") { - cx.marked = "keyword" - return cont(pushlex("form"), expression, statement, poplex) - } else if (isTS && value == "abstract") { - cx.marked = "keyword" - return cont(statement) - } else { - return cont(pushlex("stat"), maybelabel); - } - } - if (type == "switch") return cont(pushlex("form"), parenExpr, expect("{"), pushlex("}", "switch"), pushblockcontext, - block, poplex, poplex, popcontext); - if (type == "case") return cont(expression, expect(":")); - if (type == "default") return cont(expect(":")); - if (type == "catch") return cont(pushlex("form"), pushcontext, maybeCatchBinding, statement, poplex, popcontext); - if (type == "export") return cont(pushlex("stat"), afterExport, poplex); - if (type == "import") return cont(pushlex("stat"), afterImport, poplex); - if (type == "async") return cont(statement) - if (value == "@") return cont(expression, statement) - return pass(pushlex("stat"), expression, expect(";"), poplex); - } - function maybeCatchBinding(type) { - if (type == "(") return cont(funarg, expect(")")) - } - function expression(type, value) { - return expressionInner(type, value, false); - } - function expressionNoComma(type, value) { - return expressionInner(type, value, true); - } - function parenExpr(type) { - if (type != "(") return pass() - return cont(pushlex(")"), maybeexpression, expect(")"), poplex) - } - function expressionInner(type, value, noComma) { - if (cx.state.fatArrowAt == cx.stream.start) { - var body = noComma ? arrowBodyNoComma : arrowBody; - if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, expect("=>"), body, popcontext); - else if (type == "variable") return pass(pushcontext, pattern, expect("=>"), body, popcontext); - } - - var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma; - if (atomicTypes.hasOwnProperty(type)) return cont(maybeop); - if (type == "function") return cont(functiondef, maybeop); - if (type == "class" || (isTS && value == "interface")) { cx.marked = "keyword"; return cont(pushlex("form"), classExpression, poplex); } - if (type == "keyword c" || type == "async") return cont(noComma ? expressionNoComma : expression); - if (type == "(") return cont(pushlex(")"), maybeexpression, expect(")"), poplex, maybeop); - if (type == "operator" || type == "spread") return cont(noComma ? expressionNoComma : expression); - if (type == "[") return cont(pushlex("]"), arrayLiteral, poplex, maybeop); - if (type == "{") return contCommasep(objprop, "}", null, maybeop); - if (type == "quasi") return pass(quasi, maybeop); - if (type == "new") return cont(maybeTarget(noComma)); - return cont(); - } - function maybeexpression(type) { - if (type.match(/[;\}\)\],]/)) return pass(); - return pass(expression); - } - - function maybeoperatorComma(type, value) { - if (type == ",") return cont(maybeexpression); - return maybeoperatorNoComma(type, value, false); - } - function maybeoperatorNoComma(type, value, noComma) { - var me = noComma == false ? maybeoperatorComma : maybeoperatorNoComma; - var expr = noComma == false ? expression : expressionNoComma; - if (type == "=>") return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext); - if (type == "operator") { - if (/\+\+|--/.test(value) || isTS && value == "!") return cont(me); - if (isTS && value == "<" && cx.stream.match(/^([^<>]|<[^<>]*>)*>\s*\(/, false)) - return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, me); - if (value == "?") return cont(expression, expect(":"), expr); - return cont(expr); - } - if (type == "quasi") { return pass(quasi, me); } - if (type == ";") return; - if (type == "(") return contCommasep(expressionNoComma, ")", "call", me); - if (type == ".") return cont(property, me); - if (type == "[") return cont(pushlex("]"), maybeexpression, expect("]"), poplex, me); - if (isTS && value == "as") { cx.marked = "keyword"; return cont(typeexpr, me) } - if (type == "regexp") { - cx.state.lastType = cx.marked = "operator" - cx.stream.backUp(cx.stream.pos - cx.stream.start - 1) - return cont(expr) - } - } - function quasi(type, value) { - if (type != "quasi") return pass(); - if (value.slice(value.length - 2) != "${") return cont(quasi); - return cont(maybeexpression, continueQuasi); - } - function continueQuasi(type) { - if (type == "}") { - cx.marked = "string-2"; - cx.state.tokenize = tokenQuasi; - return cont(quasi); - } - } - function arrowBody(type) { - findFatArrow(cx.stream, cx.state); - return pass(type == "{" ? statement : expression); - } - function arrowBodyNoComma(type) { - findFatArrow(cx.stream, cx.state); - return pass(type == "{" ? statement : expressionNoComma); - } - function maybeTarget(noComma) { - return function(type) { - if (type == ".") return cont(noComma ? targetNoComma : target); - else if (type == "variable" && isTS) return cont(maybeTypeArgs, noComma ? maybeoperatorNoComma : maybeoperatorComma) - else return pass(noComma ? expressionNoComma : expression); - }; - } - function target(_, value) { - if (value == "target") { cx.marked = "keyword"; return cont(maybeoperatorComma); } - } - function targetNoComma(_, value) { - if (value == "target") { cx.marked = "keyword"; return cont(maybeoperatorNoComma); } - } - function maybelabel(type) { - if (type == ":") return cont(poplex, statement); - return pass(maybeoperatorComma, expect(";"), poplex); - } - function property(type) { - if (type == "variable") {cx.marked = "property"; return cont();} - } - function objprop(type, value) { - if (type == "async") { - cx.marked = "property"; - return cont(objprop); - } else if (type == "variable" || cx.style == "keyword") { - cx.marked = "property"; - if (value == "get" || value == "set") return cont(getterSetter); - var m // Work around fat-arrow-detection complication for detecting typescript typed arrow params - if (isTS && cx.state.fatArrowAt == cx.stream.start && (m = cx.stream.match(/^\s*:\s*/, false))) - cx.state.fatArrowAt = cx.stream.pos + m[0].length - return cont(afterprop); - } else if (type == "number" || type == "string") { - cx.marked = jsonldMode ? "property" : (cx.style + " property"); - return cont(afterprop); - } else if (type == "jsonld-keyword") { - return cont(afterprop); - } else if (isTS && isModifier(value)) { - cx.marked = "keyword" - return cont(objprop) - } else if (type == "[") { - return cont(expression, maybetype, expect("]"), afterprop); - } else if (type == "spread") { - return cont(expressionNoComma, afterprop); - } else if (value == "*") { - cx.marked = "keyword"; - return cont(objprop); - } else if (type == ":") { - return pass(afterprop) - } - } - function getterSetter(type) { - if (type != "variable") return pass(afterprop); - cx.marked = "property"; - return cont(functiondef); - } - function afterprop(type) { - if (type == ":") return cont(expressionNoComma); - if (type == "(") return pass(functiondef); - } - function commasep(what, end, sep) { - function proceed(type, value) { - if (sep ? sep.indexOf(type) > -1 : type == ",") { - var lex = cx.state.lexical; - if (lex.info == "call") lex.pos = (lex.pos || 0) + 1; - return cont(function(type, value) { - if (type == end || value == end) return pass() - return pass(what) - }, proceed); - } - if (type == end || value == end) return cont(); - if (sep && sep.indexOf(";") > -1) return pass(what) - return cont(expect(end)); - } - return function(type, value) { - if (type == end || value == end) return cont(); - return pass(what, proceed); - }; - } - function contCommasep(what, end, info) { - for (var i = 3; i < arguments.length; i++) - cx.cc.push(arguments[i]); - return cont(pushlex(end, info), commasep(what, end), poplex); - } - function block(type) { - if (type == "}") return cont(); - return pass(statement, block); - } - function maybetype(type, value) { - if (isTS) { - if (type == ":") return cont(typeexpr); - if (value == "?") return cont(maybetype); - } - } - function maybetypeOrIn(type, value) { - if (isTS && (type == ":" || value == "in")) return cont(typeexpr) - } - function mayberettype(type) { - if (isTS && type == ":") { - if (cx.stream.match(/^\s*\w+\s+is\b/, false)) return cont(expression, isKW, typeexpr) - else return cont(typeexpr) - } - } - function isKW(_, value) { - if (value == "is") { - cx.marked = "keyword" - return cont() - } - } - function typeexpr(type, value) { - if (value == "keyof" || value == "typeof" || value == "infer" || value == "readonly") { - cx.marked = "keyword" - return cont(value == "typeof" ? expressionNoComma : typeexpr) - } - if (type == "variable" || value == "void") { - cx.marked = "type" - return cont(afterType) - } - if (value == "|" || value == "&") return cont(typeexpr) - if (type == "string" || type == "number" || type == "atom") return cont(afterType); - if (type == "[") return cont(pushlex("]"), commasep(typeexpr, "]", ","), poplex, afterType) - if (type == "{") return cont(pushlex("}"), typeprops, poplex, afterType) - if (type == "(") return cont(commasep(typearg, ")"), maybeReturnType, afterType) - if (type == "<") return cont(commasep(typeexpr, ">"), typeexpr) - if (type == "quasi") { return pass(quasiType, afterType); } - } - function maybeReturnType(type) { - if (type == "=>") return cont(typeexpr) - } - function typeprops(type) { - if (type.match(/[\}\)\]]/)) return cont() - if (type == "," || type == ";") return cont(typeprops) - return pass(typeprop, typeprops) - } - function typeprop(type, value) { - if (type == "variable" || cx.style == "keyword") { - cx.marked = "property" - return cont(typeprop) - } else if (value == "?" || type == "number" || type == "string") { - return cont(typeprop) - } else if (type == ":") { - return cont(typeexpr) - } else if (type == "[") { - return cont(expect("variable"), maybetypeOrIn, expect("]"), typeprop) - } else if (type == "(") { - return pass(functiondecl, typeprop) - } else if (!type.match(/[;\}\)\],]/)) { - return cont() - } - } - function quasiType(type, value) { - if (type != "quasi") return pass(); - if (value.slice(value.length - 2) != "${") return cont(quasiType); - return cont(typeexpr, continueQuasiType); - } - function continueQuasiType(type) { - if (type == "}") { - cx.marked = "string-2"; - cx.state.tokenize = tokenQuasi; - return cont(quasiType); - } - } - function typearg(type, value) { - if (type == "variable" && cx.stream.match(/^\s*[?:]/, false) || value == "?") return cont(typearg) - if (type == ":") return cont(typeexpr) - if (type == "spread") return cont(typearg) - return pass(typeexpr) - } - function afterType(type, value) { - if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, afterType) - if (value == "|" || type == "." || value == "&") return cont(typeexpr) - if (type == "[") return cont(typeexpr, expect("]"), afterType) - if (value == "extends" || value == "implements") { cx.marked = "keyword"; return cont(typeexpr) } - if (value == "?") return cont(typeexpr, expect(":"), typeexpr) - } - function maybeTypeArgs(_, value) { - if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, afterType) - } - function typeparam() { - return pass(typeexpr, maybeTypeDefault) - } - function maybeTypeDefault(_, value) { - if (value == "=") return cont(typeexpr) - } - function vardef(_, value) { - if (value == "enum") {cx.marked = "keyword"; return cont(enumdef)} - return pass(pattern, maybetype, maybeAssign, vardefCont); - } - function pattern(type, value) { - if (isTS && isModifier(value)) { cx.marked = "keyword"; return cont(pattern) } - if (type == "variable") { register(value); return cont(); } - if (type == "spread") return cont(pattern); - if (type == "[") return contCommasep(eltpattern, "]"); - if (type == "{") return contCommasep(proppattern, "}"); - } - function proppattern(type, value) { - if (type == "variable" && !cx.stream.match(/^\s*:/, false)) { - register(value); - return cont(maybeAssign); - } - if (type == "variable") cx.marked = "property"; - if (type == "spread") return cont(pattern); - if (type == "}") return pass(); - if (type == "[") return cont(expression, expect(']'), expect(':'), proppattern); - return cont(expect(":"), pattern, maybeAssign); - } - function eltpattern() { - return pass(pattern, maybeAssign) - } - function maybeAssign(_type, value) { - if (value == "=") return cont(expressionNoComma); - } - function vardefCont(type) { - if (type == ",") return cont(vardef); - } - function maybeelse(type, value) { - if (type == "keyword b" && value == "else") return cont(pushlex("form", "else"), statement, poplex); - } - function forspec(type, value) { - if (value == "await") return cont(forspec); - if (type == "(") return cont(pushlex(")"), forspec1, poplex); - } - function forspec1(type) { - if (type == "var") return cont(vardef, forspec2); - if (type == "variable") return cont(forspec2); - return pass(forspec2) - } - function forspec2(type, value) { - if (type == ")") return cont() - if (type == ";") return cont(forspec2) - if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression, forspec2) } - return pass(expression, forspec2) - } - function functiondef(type, value) { - if (value == "*") {cx.marked = "keyword"; return cont(functiondef);} - if (type == "variable") {register(value); return cont(functiondef);} - if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, mayberettype, statement, popcontext); - if (isTS && value == "<") return cont(pushlex(">"), commasep(typeparam, ">"), poplex, functiondef) - } - function functiondecl(type, value) { - if (value == "*") {cx.marked = "keyword"; return cont(functiondecl);} - if (type == "variable") {register(value); return cont(functiondecl);} - if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, mayberettype, popcontext); - if (isTS && value == "<") return cont(pushlex(">"), commasep(typeparam, ">"), poplex, functiondecl) - } - function typename(type, value) { - if (type == "keyword" || type == "variable") { - cx.marked = "type" - return cont(typename) - } else if (value == "<") { - return cont(pushlex(">"), commasep(typeparam, ">"), poplex) - } - } - function funarg(type, value) { - if (value == "@") cont(expression, funarg) - if (type == "spread") return cont(funarg); - if (isTS && isModifier(value)) { cx.marked = "keyword"; return cont(funarg); } - if (isTS && type == "this") return cont(maybetype, maybeAssign) - return pass(pattern, maybetype, maybeAssign); - } - function classExpression(type, value) { - // Class expressions may have an optional name. - if (type == "variable") return className(type, value); - return classNameAfter(type, value); - } - function className(type, value) { - if (type == "variable") {register(value); return cont(classNameAfter);} - } - function classNameAfter(type, value) { - if (value == "<") return cont(pushlex(">"), commasep(typeparam, ">"), poplex, classNameAfter) - if (value == "extends" || value == "implements" || (isTS && type == ",")) { - if (value == "implements") cx.marked = "keyword"; - return cont(isTS ? typeexpr : expression, classNameAfter); - } - if (type == "{") return cont(pushlex("}"), classBody, poplex); - } - function classBody(type, value) { - if (type == "async" || - (type == "variable" && - (value == "static" || value == "get" || value == "set" || (isTS && isModifier(value))) && - cx.stream.match(/^\s+[\w$\xa1-\uffff]/, false))) { - cx.marked = "keyword"; - return cont(classBody); - } - if (type == "variable" || cx.style == "keyword") { - cx.marked = "property"; - return cont(classfield, classBody); - } - if (type == "number" || type == "string") return cont(classfield, classBody); - if (type == "[") - return cont(expression, maybetype, expect("]"), classfield, classBody) - if (value == "*") { - cx.marked = "keyword"; - return cont(classBody); - } - if (isTS && type == "(") return pass(functiondecl, classBody) - if (type == ";" || type == ",") return cont(classBody); - if (type == "}") return cont(); - if (value == "@") return cont(expression, classBody) - } - function classfield(type, value) { - if (value == "!") return cont(classfield) - if (value == "?") return cont(classfield) - if (type == ":") return cont(typeexpr, maybeAssign) - if (value == "=") return cont(expressionNoComma) - var context = cx.state.lexical.prev, isInterface = context && context.info == "interface" - return pass(isInterface ? functiondecl : functiondef) - } - function afterExport(type, value) { - if (value == "*") { cx.marked = "keyword"; return cont(maybeFrom, expect(";")); } - if (value == "default") { cx.marked = "keyword"; return cont(expression, expect(";")); } - if (type == "{") return cont(commasep(exportField, "}"), maybeFrom, expect(";")); - return pass(statement); - } - function exportField(type, value) { - if (value == "as") { cx.marked = "keyword"; return cont(expect("variable")); } - if (type == "variable") return pass(expressionNoComma, exportField); - } - function afterImport(type) { - if (type == "string") return cont(); - if (type == "(") return pass(expression); - if (type == ".") return pass(maybeoperatorComma); - return pass(importSpec, maybeMoreImports, maybeFrom); - } - function importSpec(type, value) { - if (type == "{") return contCommasep(importSpec, "}"); - if (type == "variable") register(value); - if (value == "*") cx.marked = "keyword"; - return cont(maybeAs); - } - function maybeMoreImports(type) { - if (type == ",") return cont(importSpec, maybeMoreImports) - } - function maybeAs(_type, value) { - if (value == "as") { cx.marked = "keyword"; return cont(importSpec); } - } - function maybeFrom(_type, value) { - if (value == "from") { cx.marked = "keyword"; return cont(expression); } - } - function arrayLiteral(type) { - if (type == "]") return cont(); - return pass(commasep(expressionNoComma, "]")); - } - function enumdef() { - return pass(pushlex("form"), pattern, expect("{"), pushlex("}"), commasep(enummember, "}"), poplex, poplex) - } - function enummember() { - return pass(pattern, maybeAssign); - } - - function isContinuedStatement(state, textAfter) { - return state.lastType == "operator" || state.lastType == "," || - isOperatorChar.test(textAfter.charAt(0)) || - /[,.]/.test(textAfter.charAt(0)); - } - - function expressionAllowed(stream, state, backUp) { - return state.tokenize == tokenBase && - /^(?:operator|sof|keyword [bcd]|case|new|export|default|spread|[\[{}\(,;:]|=>)$/.test(state.lastType) || - (state.lastType == "quasi" && /\{\s*$/.test(stream.string.slice(0, stream.pos - (backUp || 0)))) - } - - // Interface - - return { - startState: function(basecolumn) { - var state = { - tokenize: tokenBase, - lastType: "sof", - cc: [], - lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false), - localVars: parserConfig.localVars, - context: parserConfig.localVars && new Context(null, null, false), - indented: basecolumn || 0 - }; - if (parserConfig.globalVars && typeof parserConfig.globalVars == "object") - state.globalVars = parserConfig.globalVars; - return state; - }, - - token: function(stream, state) { - if (stream.sol()) { - if (!state.lexical.hasOwnProperty("align")) - state.lexical.align = false; - state.indented = stream.indentation(); - findFatArrow(stream, state); - } - if (state.tokenize != tokenComment && stream.eatSpace()) return null; - var style = state.tokenize(stream, state); - if (type == "comment") return style; - state.lastType = type == "operator" && (content == "++" || content == "--") ? "incdec" : type; - return parseJS(state, style, type, content, stream); - }, - - indent: function(state, textAfter) { - if (state.tokenize == tokenComment || state.tokenize == tokenQuasi) return CodeMirror.Pass; - if (state.tokenize != tokenBase) return 0; - var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical, top - // Kludge to prevent 'maybelse' from blocking lexical scope pops - if (!/^\s*else\b/.test(textAfter)) for (var i = state.cc.length - 1; i >= 0; --i) { - var c = state.cc[i]; - if (c == poplex) lexical = lexical.prev; - else if (c != maybeelse && c != popcontext) break; - } - while ((lexical.type == "stat" || lexical.type == "form") && - (firstChar == "}" || ((top = state.cc[state.cc.length - 1]) && - (top == maybeoperatorComma || top == maybeoperatorNoComma) && - !/^[,\.=+\-*:?[\(]/.test(textAfter)))) - lexical = lexical.prev; - if (statementIndent && lexical.type == ")" && lexical.prev.type == "stat") - lexical = lexical.prev; - var type = lexical.type, closing = firstChar == type; - - if (type == "vardef") return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? lexical.info.length + 1 : 0); - else if (type == "form" && firstChar == "{") return lexical.indented; - else if (type == "form") return lexical.indented + indentUnit; - else if (type == "stat") - return lexical.indented + (isContinuedStatement(state, textAfter) ? statementIndent || indentUnit : 0); - else if (lexical.info == "switch" && !closing && parserConfig.doubleIndentSwitch != false) - return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? indentUnit : 2 * indentUnit); - else if (lexical.align) return lexical.column + (closing ? 0 : 1); - else return lexical.indented + (closing ? 0 : indentUnit); - }, - - electricInput: /^\s*(?:case .*?:|default:|\{|\})$/, - blockCommentStart: jsonMode ? null : "/*", - blockCommentEnd: jsonMode ? null : "*/", - blockCommentContinue: jsonMode ? null : " * ", - lineComment: jsonMode ? null : "//", - fold: "brace", - closeBrackets: "()[]{}''\"\"``", - - helperType: jsonMode ? "json" : "javascript", - jsonldMode: jsonldMode, - jsonMode: jsonMode, - - expressionAllowed: expressionAllowed, - - skipExpression: function(state) { - parseJS(state, "atom", "atom", "true", new CodeMirror.StringStream("", 2, null)) - } - }; -}); - -CodeMirror.registerHelper("wordChars", "javascript", /[\w$]/); - -CodeMirror.defineMIME("text/javascript", "javascript"); -CodeMirror.defineMIME("text/ecmascript", "javascript"); -CodeMirror.defineMIME("application/javascript", "javascript"); -CodeMirror.defineMIME("application/x-javascript", "javascript"); -CodeMirror.defineMIME("application/ecmascript", "javascript"); -CodeMirror.defineMIME("application/json", { name: "javascript", json: true }); -CodeMirror.defineMIME("application/x-json", { name: "javascript", json: true }); -CodeMirror.defineMIME("application/manifest+json", { name: "javascript", json: true }) -CodeMirror.defineMIME("application/ld+json", { name: "javascript", jsonld: true }); -CodeMirror.defineMIME("text/typescript", { name: "javascript", typescript: true }); -CodeMirror.defineMIME("application/typescript", { name: "javascript", typescript: true }); - -}); diff --git a/www/js/codemirror/mode/xml/xml.js b/www/js/codemirror/mode/xml/xml.js deleted file mode 100644 index 4e36106..0000000 --- a/www/js/codemirror/mode/xml/xml.js +++ /dev/null @@ -1,417 +0,0 @@ -// CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE - -(function(mod) { - if (typeof exports == "object" && typeof module == "object") // CommonJS - mod(require("../../lib/codemirror")); - else if (typeof define == "function" && define.amd) // AMD - define(["../../lib/codemirror"], mod); - else // Plain browser env - mod(CodeMirror); -})(function(CodeMirror) { -"use strict"; - -var htmlConfig = { - autoSelfClosers: {'area': true, 'base': true, 'br': true, 'col': true, 'command': true, - 'embed': true, 'frame': true, 'hr': true, 'img': true, 'input': true, - 'keygen': true, 'link': true, 'meta': true, 'param': true, 'source': true, - 'track': true, 'wbr': true, 'menuitem': true}, - implicitlyClosed: {'dd': true, 'li': true, 'optgroup': true, 'option': true, 'p': true, - 'rp': true, 'rt': true, 'tbody': true, 'td': true, 'tfoot': true, - 'th': true, 'tr': true}, - contextGrabbers: { - 'dd': {'dd': true, 'dt': true}, - 'dt': {'dd': true, 'dt': true}, - 'li': {'li': true}, - 'option': {'option': true, 'optgroup': true}, - 'optgroup': {'optgroup': true}, - 'p': {'address': true, 'article': true, 'aside': true, 'blockquote': true, 'dir': true, - 'div': true, 'dl': true, 'fieldset': true, 'footer': true, 'form': true, - 'h1': true, 'h2': true, 'h3': true, 'h4': true, 'h5': true, 'h6': true, - 'header': true, 'hgroup': true, 'hr': true, 'menu': true, 'nav': true, 'ol': true, - 'p': true, 'pre': true, 'section': true, 'table': true, 'ul': true}, - 'rp': {'rp': true, 'rt': true}, - 'rt': {'rp': true, 'rt': true}, - 'tbody': {'tbody': true, 'tfoot': true}, - 'td': {'td': true, 'th': true}, - 'tfoot': {'tbody': true}, - 'th': {'td': true, 'th': true}, - 'thead': {'tbody': true, 'tfoot': true}, - 'tr': {'tr': true} - }, - doNotIndent: {"pre": true}, - allowUnquoted: true, - allowMissing: true, - caseFold: true -} - -var xmlConfig = { - autoSelfClosers: {}, - implicitlyClosed: {}, - contextGrabbers: {}, - doNotIndent: {}, - allowUnquoted: false, - allowMissing: false, - allowMissingTagName: false, - caseFold: false -} - -CodeMirror.defineMode("xml", function(editorConf, config_) { - var indentUnit = editorConf.indentUnit - var config = {} - var defaults = config_.htmlMode ? htmlConfig : xmlConfig - for (var prop in defaults) config[prop] = defaults[prop] - for (var prop in config_) config[prop] = config_[prop] - - // Return variables for tokenizers - var type, setStyle; - - function inText(stream, state) { - function chain(parser) { - state.tokenize = parser; - return parser(stream, state); - } - - var ch = stream.next(); - if (ch == "<") { - if (stream.eat("!")) { - if (stream.eat("[")) { - if (stream.match("CDATA[")) return chain(inBlock("atom", "]]>")); - else return null; - } else if (stream.match("--")) { - return chain(inBlock("comment", "-->")); - } else if (stream.match("DOCTYPE", true, true)) { - stream.eatWhile(/[\w\._\-]/); - return chain(doctype(1)); - } else { - return null; - } - } else if (stream.eat("?")) { - stream.eatWhile(/[\w\._\-]/); - state.tokenize = inBlock("meta", "?>"); - return "meta"; - } else { - type = stream.eat("/") ? "closeTag" : "openTag"; - state.tokenize = inTag; - return "tag bracket"; - } - } else if (ch == "&") { - var ok; - if (stream.eat("#")) { - if (stream.eat("x")) { - ok = stream.eatWhile(/[a-fA-F\d]/) && stream.eat(";"); - } else { - ok = stream.eatWhile(/[\d]/) && stream.eat(";"); - } - } else { - ok = stream.eatWhile(/[\w\.\-:]/) && stream.eat(";"); - } - return ok ? "atom" : "error"; - } else { - stream.eatWhile(/[^&<]/); - return null; - } - } - inText.isInText = true; - - function inTag(stream, state) { - var ch = stream.next(); - if (ch == ">" || (ch == "/" && stream.eat(">"))) { - state.tokenize = inText; - type = ch == ">" ? "endTag" : "selfcloseTag"; - return "tag bracket"; - } else if (ch == "=") { - type = "equals"; - return null; - } else if (ch == "<") { - state.tokenize = inText; - state.state = baseState; - state.tagName = state.tagStart = null; - var next = state.tokenize(stream, state); - return next ? next + " tag error" : "tag error"; - } else if (/[\'\"]/.test(ch)) { - state.tokenize = inAttribute(ch); - state.stringStartCol = stream.column(); - return state.tokenize(stream, state); - } else { - stream.match(/^[^\s\u00a0=<>\"\']*[^\s\u00a0=<>\"\'\/]/); - return "word"; - } - } - - function inAttribute(quote) { - var closure = function(stream, state) { - while (!stream.eol()) { - if (stream.next() == quote) { - state.tokenize = inTag; - break; - } - } - return "string"; - }; - closure.isInAttribute = true; - return closure; - } - - function inBlock(style, terminator) { - return function(stream, state) { - while (!stream.eol()) { - if (stream.match(terminator)) { - state.tokenize = inText; - break; - } - stream.next(); - } - return style; - } - } - - function doctype(depth) { - return function(stream, state) { - var ch; - while ((ch = stream.next()) != null) { - if (ch == "<") { - state.tokenize = doctype(depth + 1); - return state.tokenize(stream, state); - } else if (ch == ">") { - if (depth == 1) { - state.tokenize = inText; - break; - } else { - state.tokenize = doctype(depth - 1); - return state.tokenize(stream, state); - } - } - } - return "meta"; - }; - } - - function lower(tagName) { - return tagName && tagName.toLowerCase(); - } - - function Context(state, tagName, startOfLine) { - this.prev = state.context; - this.tagName = tagName || ""; - this.indent = state.indented; - this.startOfLine = startOfLine; - if (config.doNotIndent.hasOwnProperty(tagName) || (state.context && state.context.noIndent)) - this.noIndent = true; - } - function popContext(state) { - if (state.context) state.context = state.context.prev; - } - function maybePopContext(state, nextTagName) { - var parentTagName; - while (true) { - if (!state.context) { - return; - } - parentTagName = state.context.tagName; - if (!config.contextGrabbers.hasOwnProperty(lower(parentTagName)) || - !config.contextGrabbers[lower(parentTagName)].hasOwnProperty(lower(nextTagName))) { - return; - } - popContext(state); - } - } - - function baseState(type, stream, state) { - if (type == "openTag") { - state.tagStart = stream.column(); - return tagNameState; - } else if (type == "closeTag") { - return closeTagNameState; - } else { - return baseState; - } - } - function tagNameState(type, stream, state) { - if (type == "word") { - state.tagName = stream.current(); - setStyle = "tag"; - return attrState; - } else if (config.allowMissingTagName && type == "endTag") { - setStyle = "tag bracket"; - return attrState(type, stream, state); - } else { - setStyle = "error"; - return tagNameState; - } - } - function closeTagNameState(type, stream, state) { - if (type == "word") { - var tagName = stream.current(); - if (state.context && state.context.tagName != tagName && - config.implicitlyClosed.hasOwnProperty(lower(state.context.tagName))) - popContext(state); - if ((state.context && state.context.tagName == tagName) || config.matchClosing === false) { - setStyle = "tag"; - return closeState; - } else { - setStyle = "tag error"; - return closeStateErr; - } - } else if (config.allowMissingTagName && type == "endTag") { - setStyle = "tag bracket"; - return closeState(type, stream, state); - } else { - setStyle = "error"; - return closeStateErr; - } - } - - function closeState(type, _stream, state) { - if (type != "endTag") { - setStyle = "error"; - return closeState; - } - popContext(state); - return baseState; - } - function closeStateErr(type, stream, state) { - setStyle = "error"; - return closeState(type, stream, state); - } - - function attrState(type, _stream, state) { - if (type == "word") { - setStyle = "attribute"; - return attrEqState; - } else if (type == "endTag" || type == "selfcloseTag") { - var tagName = state.tagName, tagStart = state.tagStart; - state.tagName = state.tagStart = null; - if (type == "selfcloseTag" || - config.autoSelfClosers.hasOwnProperty(lower(tagName))) { - maybePopContext(state, tagName); - } else { - maybePopContext(state, tagName); - state.context = new Context(state, tagName, tagStart == state.indented); - } - return baseState; - } - setStyle = "error"; - return attrState; - } - function attrEqState(type, stream, state) { - if (type == "equals") return attrValueState; - if (!config.allowMissing) setStyle = "error"; - return attrState(type, stream, state); - } - function attrValueState(type, stream, state) { - if (type == "string") return attrContinuedState; - if (type == "word" && config.allowUnquoted) {setStyle = "string"; return attrState;} - setStyle = "error"; - return attrState(type, stream, state); - } - function attrContinuedState(type, stream, state) { - if (type == "string") return attrContinuedState; - return attrState(type, stream, state); - } - - return { - startState: function(baseIndent) { - var state = {tokenize: inText, - state: baseState, - indented: baseIndent || 0, - tagName: null, tagStart: null, - context: null} - if (baseIndent != null) state.baseIndent = baseIndent - return state - }, - - token: function(stream, state) { - if (!state.tagName && stream.sol()) - state.indented = stream.indentation(); - - if (stream.eatSpace()) return null; - type = null; - var style = state.tokenize(stream, state); - if ((style || type) && style != "comment") { - setStyle = null; - state.state = state.state(type || style, stream, state); - if (setStyle) - style = setStyle == "error" ? style + " error" : setStyle; - } - return style; - }, - - indent: function(state, textAfter, fullLine) { - var context = state.context; - // Indent multi-line strings (e.g. css). - if (state.tokenize.isInAttribute) { - if (state.tagStart == state.indented) - return state.stringStartCol + 1; - else - return state.indented + indentUnit; - } - if (context && context.noIndent) return CodeMirror.Pass; - if (state.tokenize != inTag && state.tokenize != inText) - return fullLine ? fullLine.match(/^(\s*)/)[0].length : 0; - // Indent the starts of attribute names. - if (state.tagName) { - if (config.multilineTagIndentPastTag !== false) - return state.tagStart + state.tagName.length + 2; - else - return state.tagStart + indentUnit * (config.multilineTagIndentFactor || 1); - } - if (config.alignCDATA && /$/, - blockCommentStart: "", - - configuration: config.htmlMode ? "html" : "xml", - helperType: config.htmlMode ? "html" : "xml", - - skipAttribute: function(state) { - if (state.state == attrValueState) - state.state = attrState - }, - - xmlCurrentTag: function(state) { - return state.tagName ? {name: state.tagName, close: state.type == "closeTag"} : null - }, - - xmlCurrentContext: function(state) { - var context = [] - for (var cx = state.context; cx; cx = cx.prev) - context.push(cx.tagName) - return context.reverse() - } - }; -}); - -CodeMirror.defineMIME("text/xml", "xml"); -CodeMirror.defineMIME("application/xml", "xml"); -if (!CodeMirror.mimeModes.hasOwnProperty("text/html")) - CodeMirror.defineMIME("text/html", {name: "xml", htmlMode: true}); - -}); diff --git a/www/js/codemirror/theme/base16-dark.css b/www/js/codemirror/theme/base16-dark.css deleted file mode 100644 index b3c31ab..0000000 --- a/www/js/codemirror/theme/base16-dark.css +++ /dev/null @@ -1,40 +0,0 @@ -/* - - Name: Base16 Default Dark - Author: Chris Kempson (http://chriskempson.com) - - CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror) - Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) - -*/ - -.cm-s-base16-dark.CodeMirror { background: #151515; color: #e0e0e0; } -.cm-s-base16-dark div.CodeMirror-selected { background: #303030; } -.cm-s-base16-dark .CodeMirror-line::selection, .cm-s-base16-dark .CodeMirror-line > span::selection, .cm-s-base16-dark .CodeMirror-line > span > span::selection { background: rgba(48, 48, 48, .99); } -.cm-s-base16-dark .CodeMirror-line::-moz-selection, .cm-s-base16-dark .CodeMirror-line > span::-moz-selection, .cm-s-base16-dark .CodeMirror-line > span > span::-moz-selection { background: rgba(48, 48, 48, .99); } -.cm-s-base16-dark .CodeMirror-gutters { background: #151515; border-right: 0px; } -.cm-s-base16-dark .CodeMirror-guttermarker { color: #ac4142; } -.cm-s-base16-dark .CodeMirror-guttermarker-subtle { color: #505050; } -.cm-s-base16-dark .CodeMirror-linenumber { color: #505050; } -.cm-s-base16-dark .CodeMirror-cursor { border-left: 1px solid #b0b0b0; } -.cm-s-base16-dark.cm-fat-cursor .CodeMirror-cursor { background-color: #8e8d8875 !important; } -.cm-s-base16-dark .cm-animate-fat-cursor { background-color: #8e8d8875 !important; } - -.cm-s-base16-dark span.cm-comment { color: #8f5536; } -.cm-s-base16-dark span.cm-atom { color: #aa759f; } -.cm-s-base16-dark span.cm-number { color: #aa759f; } - -.cm-s-base16-dark span.cm-property, .cm-s-base16-dark span.cm-attribute { color: #90a959; } -.cm-s-base16-dark span.cm-keyword { color: #ac4142; } -.cm-s-base16-dark span.cm-string { color: #f4bf75; } - -.cm-s-base16-dark span.cm-variable { color: #90a959; } -.cm-s-base16-dark span.cm-variable-2 { color: #6a9fb5; } -.cm-s-base16-dark span.cm-def { color: #d28445; } -.cm-s-base16-dark span.cm-bracket { color: #e0e0e0; } -.cm-s-base16-dark span.cm-tag { color: #ac4142; } -.cm-s-base16-dark span.cm-link { color: #aa759f; } -.cm-s-base16-dark span.cm-error { background: #ac4142; color: #b0b0b0; } - -.cm-s-base16-dark .CodeMirror-activeline-background { background: #202020; } -.cm-s-base16-dark .CodeMirror-matchingbracket { text-decoration: underline; color: white !important; } diff --git a/www/js/simply-edit.js b/www/js/simply-edit.js deleted file mode 100755 index 5be4d05..0000000 --- a/www/js/simply-edit.js +++ /dev/null @@ -1,3824 +0,0 @@ -/* - Simply edit the Web - - Written by Yvo Brevoort - Copyright Muze 2015-2020, all rights reserved. -*/ -(function() { - if (window.editor) { - return; - } - - var getScriptEl = function() { - var scriptEl = document.querySelector("[src$='simply-edit.js'][data-api-key]"); - if (!scriptEl) { - scriptEl = document.querySelector("[src$='simply-edit.js']"); - } - if (!scriptEl) { - scriptEl = document.querySelector("[data-api-key]"); - } - return scriptEl; - }; - - var scriptEl = getScriptEl(); - var apiKey = scriptEl.getAttribute("data-api-key") ? scriptEl.getAttribute("data-api-key") : ""; - - var getKeylessBaseURL = function(url) { - var scriptURL = document.createElement('a'); - scriptURL.href = url; - scriptURL.pathname = scriptURL.pathname.replace('simply-edit.js', '').replace(/\/js\/$/, '/'); - return scriptURL.href; - }; - - var getBaseURL = function(url) { - var scriptURL = document.createElement('a'); - scriptURL.href = url; - scriptURL.pathname = scriptURL.pathname.replace('simply-edit.js', '').replace(/\/js\/$/, '/'); - if (apiKey !== "") { - scriptURL.pathname = scriptURL.pathname + apiKey + "/"; - } - return scriptURL.href; - }; - - var editor = { - version: '@version', - apiKey : apiKey, - baseURL : getBaseURL(scriptEl.src), - baseURLClean : getKeylessBaseURL(scriptEl.src), - bindingParents : [], - transformers: {}, - data : { - getDataPath : function(field) { - var parent = field; - while (parent && parent.parentNode) { - var parentPath = parent.getAttribute("data-simply-path"); - if (parentPath) { - if (parentPath.indexOf("/") !== 0) { // Resolve as relative path if it doesn't start with a slash; allows the use of ../ - var resolver = document.createElement("A"); - var basePath = location.pathname.replace(/(.*)\/.*?$/, "$1/"); - resolver.href = basePath + parentPath; - if (resolver.pathname.indexOf("./") == -1) { - // IE11 doesn't add a leading slash; - if (resolver.pathname.indexOf("/") !== 0) { - return "/" + resolver.pathname; - } else { - return resolver.pathname; - } - } else { - var origin = document.location.origin; - if (!origin) { - origin = document.location.protocol + "//" + document.location.host; // IE9 doesn't have document.location.origin - } - return resolver.href.replace(origin, ""); // IE11 doesn't resolve ../ or ./ in the path - } - } - return parentPath; - } - parent = parent.parentNode; - } - if (parent && parent.dataSimplyPath) { - return parent.dataSimplyPath; - } - if (field && field.storedPath && !field.offsetParent) { - return field.storedPath; - } - return location.pathname; - }, - apply : function(data, target) { - if (typeof data === "undefined") { - data = {}; - } - - // data = JSON.parse(JSON.stringify(data)); // clone data to prevent reference issues; - - if (typeof editor.data.originalBody === "undefined" && document.body) { - editor.data.originalBody = document.body.cloneNode(true); - } - - editor.responsiveImages.init(target); // FIXME: should this be more defensive and skip images within fields/lists? - - var dataFields; - if (target.nodeType == document.ELEMENT_NODE && target.getAttribute("data-simply-field")) { - dataFields = [target]; - if ( - (target.getAttribute("data-simply-content") === 'fixed') || - (target.getAttribute("data-simply-content") === 'attributes') - ) { // special case - if the target field has content fixed or attributes, we need to handle its children as well. - var extraFields = target.querySelectorAll("[data-simply-field]"); - for (var x=0; x -1); - if (isSub) { - continue; - } - - var dataPath = editor.data.getDataPath(dataFields[i]); - if (!data[dataPath]) { - data[dataPath] = {}; - } - - editor.field.init(dataFields[i], data[dataPath], true); - } - - editor.settings.databind.parentKey = savedParentKey; - editor.list.initLists(data, target); - editor.fireEvent("simply-data-applied", target); - editor.fireEvent("simply-selectable-inserted", target); - }, - get : function(target) { - if (target == document && editor.currentData) { - return editor.currentData; - } else if (target.dataBinding) { - return target.dataBinding.get(); - } else { - var stashedFields = target.querySelectorAll("[data-simply-stashed]"); - for (i=0; i -1); - if (isSub) { - continue; - } - - editor.list.initList(data, dataLists[i]); - } - if (target.nodeType == document.ELEMENT_NODE && target.getAttribute("data-simply-list")) { - editor.list.initList(data, target); - } - }, - fixFirstElementChild : function(clone) { - if (!("firstElementChild" in clone)) { - for (var l=0; l template, :scope > *[data-simply-template]"); - - if (templates.length === 0) { - console.log("Warning: no list templates found for " + dataName); - } - - if (typeof list.templates === "undefined") { - list.templates = {}; - } - if (typeof list.templateIcons === "undefined") { - list.templateIcons = {}; - } - for (var t=0; t -1); - if (isSub) { - continue; - } - editor.list.init(dataLists[i], listDataItem, useDataBinding); - } - - if (clone.nodeType == document.ELEMENT_NODE && clone.getAttribute("data-simply-list")) { - editor.list.init(clone, listDataItem, useDataBinding); - } - - editor.list.runScripts(clone); - }, - set : function(list, listData) { - if (list.dataBinding) { - list.dataBinding.pauseListeners(list); - } - - var transformer = list.getAttribute('data-simply-transformer'); - if (transformer) { - if (editor.transformers[transformer] && (typeof editor.transformers[transformer].render === "function")) { - try { - listData = editor.transformers[transformer].render.call(list, listData); - } catch(e) { - console.log("Error thrown in transformer " + transformer); - console.log(e); - } - } else { - console.log("Warning: transformer " + transformer + " is not defined"); - } - } - - if (list.previousValue == JSON.stringify(listData)) { - if (list.dataBinding) { - list.dataBinding.resumeListeners(list); - } - return; // value is the same as the previous time we set it, just keep it; - } - - list.previousValue = JSON.stringify(listData); - var previousStyle = list.getAttribute("style"); - list.style.height = list.offsetHeight + "px"; // this will prevent the screen from bouncing and messing up the scroll offset. - editor.list.clear(list); - editor.list.append(list, listData); - if (previousStyle) { - list.setAttribute("style", previousStyle); - } else { - list.removeAttribute("style"); - } - editor.list.emptyClass(list); - if (list.dataBinding) { - list.dataBinding.resumeListeners(list); - } - }, - runScripts: function(node) { - var scripts = node.querySelectorAll('script'); - var newNode; - for (var i=0; i [data-simply-list-item]"); - - var fragment = document.createDocumentFragment(); - fragment.dataSimplyPath = list.dataSimplyPath; - - list.warnedFieldDataBinding = false; - - if (!list.clones) { - list.clones = {}; - } - - var listEntryMapping = list.getAttribute("data-simply-entry"); - var listDataSource = list.getAttribute("data-simply-data"); - - var listDataGetter = function() { - return listData; - }; - var listEntryMappingGetter = function() { - return listEntryMapping; - }; - - for (j=0; j 1) { - clone.firstElementChild.setAttribute("data-simply-template", requestedTemplate); - } - - clone.firstElementChild.setAttribute("data-simply-list-item", true); - clone.firstElementChild.setAttribute("data-simply-selectable", true); - clone.firstElementChild.simplyListIndex = j; - if (list.templateIcons[requestedTemplate]) { - clone.firstElementChild.setAttribute("data-simply-list-icon", list.templateIcons[requestedTemplate]); - } - - stashedFields = clone.firstElementChild.querySelectorAll("[data-simply-stashed]"); - for (i=0; i 1) { - clone.setAttribute("data-simply-template", requestedTemplate); - } - clone.setAttribute("data-simply-list-item", true); - clone.setAttribute("data-simply-selectable", true); - clone.simplyListIndex = j; - - if (list.templateIcons[requestedTemplate]) { - clone.firstElementChild.setAttribute("data-simply-list-icon", list.templateIcons[requestedTemplate]); - } - - stashedFields = clone.querySelectorAll("[data-simply-stashed]"); - for (i=0; i -1) { - options[i].selected = true; - options[i].setAttribute("selected", true); - } else { - options[i].selected = false; - options[i].removeAttribute("selected"); - } - } - } - }, - "option" : { - get : function(field) { - var result = editor.field.defaultGetter(field, ["innerHTML"]); - result.value = field.value; - if (field.simplyString) { - return result.value; - } - return result; - }, - set : function(field, data) { - if (typeof data === "string") { - field.simplyString = true; - if (field.getAttribute("data-simply-content") != "fixed") { - field.innerHTML = data; - } - field.value = data; - } else { - editor.field.defaultSetter(field, data); - } - } - }, - "[data-simply-content='template']" : { - get : function(field) { - if (editor.data.getDataPath(field) == field.storedPath) { - return field.storedData; - } - if (field.hasAttribute("data-simply-default-value")) { - return field.getAttribute("data-simply-default-value"); - } - }, - set : function(field, data) { - editor.list.parseTemplates(field); - field.innerHTML = ''; - - var savedBindingParents = editor.bindingParents; - var savedParentKey = editor.settings.databind.parentKey; - var fieldPath = editor.data.getDataPath(field); - - if (!field.templates[data]) { - var defaultTemplate = field.getAttribute("data-simply-default-template"); - if (defaultTemplate && field.templates[defaultTemplate]) { - // We don't have a template for this value, but there is a default template set; - field.templates[data] = field.templates[defaultTemplate]; - } - } - - if (field.templates[data]) { - var clone = editor.list.cloneTemplate(field.templates[data]); - field.appendChild(clone); - for (var i=0; i rect.left && - this.clickStart.x < rect.right && - this.clickStart.y < rect.bottom && - this.clickStart.y > rect.top - ) { - // this will prevent triggering list sorting when using tap-hold on text; - // the check of the clientrect will allow a click on the list item marker to continue, because it is positioned out of bounds; - evt.preventDefault(); // this will prevent triggering list sorting when using tap-hold on text; - return false; - } - }, false); - field.addEventListener("slip:beforeswipe", function(evt) { - var rect = this.getBoundingClientRect(); - if ( - this.clickStart && - this.clickStart.x > rect.left && - this.clickStart.x < rect.right && - this.clickStart.y < rect.bottom && - this.clickStart.y > rect.top - ) { - // this will prevent triggering list swiping; - // the check of the clientrect will allow a click on the list item marker to continue, because it is positioned out of bounds; - evt.preventDefault(); // this will prevent triggering list swiping on text; - return false; - } - }, false); - }, - initHopeStub : function(field) { - if (typeof field.hopeEditor !== "undefined") { - return; - } - field.hopeEditor = { - field : field, - parseHTML : function(){}, - fragment : { - has : function() { - return false; - } - }, - getBlockAnnotation : function() { - return false; - }, - currentRange : false, - selection : { - getRange : function() { - return false; - }, - updateRange : function() {} - }, - update : function() {}, - showCursor : function() {} - }; - }, - matches : function(el, selector) { - var p = Element.prototype; - var f = p.matches || p.webkitMatchesSelector || p.mozMatchesSelector || p.msMatchesSelector || function(s) { - return [].indexOf.call(document.querySelectorAll(s), this) !== -1; - }; - return f.call(el, selector); - }, - defaultGetter : function(field, attributes) { - var result = {}; - var contentType = field.getAttribute('data-simply-content'); - if (field.dataBinding) { - var currentValue = field.dataBinding.get(); - if (typeof currentValue === "object" && currentValue !== null) { - result = JSON.parse(JSON.stringify(currentValue)); // Start with the existing data if there to prevent destroying data that is not part of our scope; - } - } - for (var i=0; i 199) && (http.status < 300)) { // accept any 2xx http status as 'OK'; - var toolbars = document.createElement("TEMPLATE"); - toolbars.innerHTML = http.responseText; - - if (!("content" in toolbars)) { - var fragment = document.createDocumentFragment(); - while (toolbars.children.length) { - fragment.appendChild(toolbars.children[0]); - } - toolbars.content = fragment; - } - var scriptTags = toolbars.content.querySelectorAll("SCRIPT"); - for (i=0; i 0) { - imgEl.setAttribute("sizes", sizeRatio + "vw"); - } - imgEl.setAttribute("srcset", srcSet.join(", ")); - imgEl.setAttribute("src", imageSrc); - - if (imgEl.dataBinding) { - imgEl.dataBinding.resumeListeners(imgEl); - } - editor.fireEvent("selectionchange", document); - }, - getSizeRatio : function(imgEl) { - if (imgEl.dataBinding) { - imgEl.dataBinding.pauseListeners(imgEl); - } - var storedAlt = imgEl.getAttribute("alt"); - var storedSrc = imgEl.getAttribute("src"); - - imgEl.setAttribute("alt", ""); - imgEl.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"; // transparent 1x1 gif, this forces a redraw of the image thus recalculating its width; - var imageWidth = imgEl.width; - if (storedSrc) { - imgEl.setAttribute("src", storedSrc); - imageWidth = imgEl.width; - } else { - imgEl.removeAttribute("src"); - if (imageWidth == 1) { - // We didn't have a source to start with and the calculated width is 1 pixel - // from the transparent 1x1. This means the width is not resized by the image - // tag or css; - imageWidth = 0; - } - } - - if (storedAlt) { - imgEl.setAttribute("alt", storedAlt); - } - if (imgEl.dataBinding) { - imgEl.dataBinding.resumeListeners(imgEl); - } - - if (imgEl.simplyComputedWidth || imageWidth === 0) { - imgEl.simplyComputedWidth = true; - var computed = getComputedStyle(imgEl); - - if (computed.maxWidth) { - if (computed.maxWidth.indexOf("%") != -1) { - imageWidth = parseFloat(computed.maxWidth) / 100.0; - var offsetParent = imgEl.offsetParent ? imgEl.offsetParent : imgEl.parentNode; - imageWidth = offsetParent ? offsetParent.offsetWidth * imageWidth : 0; - } - if (computed.maxWidth.indexOf("px") != -1) { - imageWidth = parseInt(computed.maxWidth); - } - } - } - - var sizeRatio = parseInt(Math.ceil(100 * imageWidth / window.innerWidth)); - return sizeRatio; - }, - resizeHandler : function() { - var images = document.querySelectorAll("img[data-simply-src][sizes]"); - for (var i=0; i 0) { - images[i].setAttribute("sizes", sizeRatio + "vw"); - } - } - }, - isInDocumentFragment : function(el) { - var parent = el.parentNode; - while (parent) { - if (parent.nodeType === document.DOCUMENT_FRAGMENT_NODE && parent != editor.toolbarsContainer) { - return true; - } - parent = parent.parentNode; - } - return false; - } - } - }; - - var storage; - if (scriptEl.getAttribute("data-simply-storage") == "none") { - var returnTrue = function() { - return true; - }; - storage = { - init : function(endpoint) { - return { - init : returnTrue, - save : returnTrue, - load : function(callback) { - callback("{}"); - }, - connect: returnTrue, - disconnect: returnTrue - }; - } - }; - } else { - storage = { - getType : function(endpoint) { - if (document.querySelector("[data-simply-storage]")) { - return document.querySelector("[data-simply-storage]").getAttribute("data-simply-storage"); - } - if (endpoint === null) { - endpoint = document.location.href; - } - if (endpoint.indexOf("/ariadne/loader.php/") !== -1) { - return "ariadne"; - } else if (endpoint.indexOf("github.io") !== -1) { - return "github"; - } else if (endpoint.indexOf("github.com") !== -1) { - return "github"; - } - return "default"; - }, - init : function(endpoint) { - var result; - - var storageType = storage.getType(endpoint); - - if (storage[storageType]) { - result = storage[storageType]; - } else if (window[storageType]) { - result = window[storageType]; - } else { - console.log("Warning: custom storage (" + storageType + ") not found"); - } - - if (!result.escape) { - result.escape = storage.default.escape; - } - - if (typeof result.init === "function") { - result.init(endpoint); - } - return result; - }, - ariadne : { - init : function(endpoint) { - if (endpoint === null) { - endpoint = location.origin + "/"; - } - this.url = endpoint; - this.list = storage.default.list; - this.sitemap = storage.default.sitemap; - this.listSitemap = storage.default.listSitemap; - this.disconnect = storage.default.disconnect; - this.escape = storage.default.escape; - this.page = storage.default.page; - - this.endpoint = endpoint; - this.dataEndpoint = endpoint + "data.json"; - this.file = storage.default.file; - - if (editor.responsiveImages) { - if ( - editor.settings['simply-image'] && - editor.settings['simply-image'].responsive - ) { - if (typeof editor.settings['simply-image'].responsive.sizes === "function") { - editor.responsiveImages.sizes = editor.settings['simply-image'].responsive.sizes; - } else if (typeof editor.settings['simply-image'].responsive.sizes === "object") { - editor.responsiveImages.sizes = (function(sizes) { - return function(src) { - var result = {}; - var info = src.split("."); - var extension = info.pop().toLowerCase(); - if (extension === "jpg" || extension === "jpeg" || extension === "png") { - for (var i=0; i 199) && (http.status < 300) && http.responseText.length) { // accept any 2xx http status as 'OK'; - if (http.responseText === "") { - console.log("Warning: data file found, but empty"); - return callback("{}"); - } - callback(http.responseText.replace(/data-vedor/g, "data-simply")); - } else { - console.log("Could not load data, starting empty."); - callback("{}"); - } - } - }; - http.send(); - }, - connect : function(callback) { - var url = editor.storage.url + "login"; - var http = new XMLHttpRequest(); - http.open("POST", url, true); - http.send(); - if (typeof callback === "function") { - callback(); - } - return true; - } - }, - beaker : { - init : function(endpoint) { - this.endpoint = endpoint; - this.dataEndpoint = endpoint + "data.json"; - if (this.endpoint.indexOf("hyper://") === 0 && window.beaker) { - this.hyperdrive = beaker.hyperdrive.drive(this.endpoint); - this.hyperdrive.getInfo().then(function(meta) { - editor.storage.meta = meta; - editor.storage.meta.web_root = "/"; - }); - } - this.load = editor.storageConnectors.default.load; - this.sitemap = editor.storageConnectors.default.sitemap; - this.page = editor.storageConnectors.default.page; - this.listSitemap = editor.storageConnectors.default.listSitemap; - - if (editor.responsiveImages) { - if ( - editor.settings['simply-image'] && - editor.settings['simply-image'].responsive - ) { - if (typeof editor.settings['simply-image'].responsive.sizes === "function") { - editor.responsiveImages.sizes = editor.settings['simply-image'].responsive.sizes; - } else if (typeof editor.settings['simply-image'].responsive.sizes === "object") { - editor.responsiveImages.sizes = (function(sizes) { - return function(src) { - var result = {}; - var info = src.split("."); - var extension = info.pop().toLowerCase(); - if (extension === "jpg" || extension === "jpeg" || extension === "png") { - for (var i=0; i 199) && (http.status < 300)) { // accept any 2xx http status as 'OK'; - if (http.responseText === "") { - console.log("Warning: data file found, but empty"); - return callback("{}"); - } - callback(http.responseText); - } else { - console.log("No data found, starting with empty dataset"); - callback("{}"); - } - } - }; - http.send(); - }, - saveTemplate : function(pageTemplate, callback) { - var dataPath = location.pathname.split(/\//, 3)[2]; - if (dataPath.match(/\/$/)) { - dataPath += "index.html"; - } - - var repo = this.repo; - repo.read(this.repoBranch, pageTemplate, function(err, data) { - if (data) { - repo.write(this.repoBranch, dataPath, data, pageTemplate + " (copy)", callback); - } - }); - }, - list : function(url, callback) { - if (url.indexOf(editor.storage.dataEndpoint) === 0) { - return this.listSitemap(url, callback); - } - - var repoInfo = this.getRepoInfo(url); - - var repoUser = repoInfo.repoUser; - var repoName = repoInfo.repoName; - var repoBranch = repoInfo.repoBranch; - var repoPath = repoInfo.repoPath; - - var github = new Github({}); - var repo = github.getRepo(repoUser, repoName); - repo.read(repoBranch, repoPath, function(err, data) { - var result = { - images : [], - folders : [], - files : [] - }; - - if (data) { - data = JSON.parse(data); - for (var i=0; i 199) && (http.status < 300)) { // accept any 2xx http status as 'OK'; - saveResult = {path : path, response: http.responseText}; - } else { - saveResult = {path : path, message : "SAVE FAILED: Could not store.", error: true, response: http.responseText}; - } - var saveEvent = editor.fireEvent("simply-storage-file-saved", document, saveResult); - if (!saveEvent.defaultPrevented) { - callback(saveEvent.data); - } - } - }; - http.upload.onprogress = function (event) { - if (event.lengthComputable) { - var complete = (event.loaded / event.total * 100 | 0); - var progress = document.querySelector("progress[data-simply-progress='" + editor.storage.escape(path) + "']"); - if (progress) { - progress.value = progress.innerHTML = complete; - } - } - }; - - http.send(data); - }, - delete : function(path, callback) { - var http = new XMLHttpRequest(); - var url = editor.storage.url + path; - - if (editor.storage.getPostOnly) { - url += "?_method=DELETE"; - http.open("POST", url, true); - } else { - http.open("DELETE", url, true); - } - http.withCredentials = true; - - http.onreadystatechange = function() {//Call a function when the state changes. - if(http.readyState == 4) { - var deleteResult = {}; - if ((http.status > 199) && (http.status < 300)) { // accept any 2xx http status as 'OK'; - deleteResult = {path : path, response: http.responseText}; - } else { - deleteResult = {path : path, message : "DELETE FAILED: Could not delete.", error: true, response: http.responseText}; - } - var deleteEvent = editor.fireEvent("simply-storage-file-deleted", document, deleteResult); - if (!deleteEvent.defaultPrevented) { - callback(deleteEvent.data); - } - } - }; - - http.send(); - } - }, - save : function(data, callback) { - return editor.storage.file.save(this.dataPath, data, callback); - }, - load : function(callback) { - var http = new XMLHttpRequest(); - var url = editor.storage.dataEndpoint; - if (editor.profile == "dev") { - url += "?t=" + (new Date().getTime()); - } - http.open("GET", url, true); - http.onreadystatechange = function() {//Call a function when the state changes. - if(http.readyState == 4) { - if ((http.status > 199) && (http.status < 300)) { // accept any 2xx http status as 'OK'; - if (http.responseText === "") { - console.log("Warning: data file found, but empty"); - return callback("{}"); - } - callback(http.responseText.replace(/\0+$/, '')); - } else { - callback("{}"); - console.log("Warning: no data found. Starting with empty set"); - } - } - }; - http.send(); - }, - connect : function(callback) { - var http = new XMLHttpRequest(); - var url = editor.storage.url + "login"; - http.open("POST", url, true); - http.send(); - if (typeof callback === "function") { - callback(); - } - return true; - }, - disconnect : function(callback) { - delete editor.storage.key; - delete localStorage.storageKey; - - var http = new XMLHttpRequest(); - var url = editor.storage.url + "logout"; - http.open("GET", url, true, "logout", (new Date()).getTime().toString()); - http.setRequestHeader("Authorization", "Basic ABCDEF"); - - http.onreadystatechange = function() {//Call a function when the state changes. - if(http.readyState == 4 && ((http.status > 399) && (http.status < 500)) ) { - if (typeof callback === "function") { - callback(); - } - } - }; - http.send(); - }, - page : { - save : function(url) { - history.pushState(null, null, url + "#simply-edit"); - - document.body.innerHTML = editor.data.originalBody.innerHTML; - document.body.removeAttribute("data-simply-edit"); - - editor.data.load(); - var openTemplateDialog = function() { - if (editor.actions['simply-template']) { - if (!document.getElementById("simply-template")) { - window.setTimeout(openTemplateDialog, 200); - return; - } - editor.actions['simply-template'](); - } else { - alert("This page does not exist yet. Save it to create it!"); - } - }; - openTemplateDialog(); - } - }, - sitemap : function() { - var output = { - children : {}, - name : 'Sitemap' - }; - for (var i in editor.currentData) { - var chain = i.split("/"); - chain.shift(); - var lastItem = chain.pop(); - if (lastItem !== "") { - chain.push(lastItem); - } else { - var item = chain.pop(); - if (typeof item === "undefined") { - item = ''; - } - chain.push(item + "/"); - } - - var currentNode = output.children; - var prevNode; - for (var j = 0; j < chain.length; j++) { - var wantedNode = chain[j]; - var lastNode = currentNode; - for (var k in currentNode) { - if (currentNode[k].name == wantedNode) { - currentNode = currentNode[k].children; - break; - } - } - // If we couldn't find an item in this list of children - // that has the right name, create one: - if (lastNode == currentNode) { - currentNode[wantedNode] = { - name : wantedNode, - children : {} - }; - currentNode = currentNode[wantedNode].children; - } - } - } - return output; - }, - listSitemap : function(url, callback) { - if (url.indexOf(editor.storage.dataEndpoint) === 0) { - var subpath = url.replace(editor.storage.dataEndpoint, ""); - var sitemap = editor.storage.sitemap(); - var result = { - folders : [], - files : [] - }; - if (subpath !== "") { - var pathicles = subpath.split("/"); - pathicles.shift(); - for (var i=0; i=0); - } - }, - get: function() { - return this.value; - } - }, -// '[data-simply-content="template"]': { -// allowNesting: true -// }, - }, options.fieldTypes); - - return options; - }; - - return simply; -})(this.simply || {}, this); -this.simply = (function(simply) { - - simply.path = { - get: function(model, path) { - if (!path) { - return model; - } - return path.split('.').reduce(function(acc, name) { - return (acc && acc[name] ? acc[name] : null); - }, model); - }, - set: function(model, path, value) { - var lastName = simply.path.pop(path); - var parentPath = simply.path.parent(path); - var parentOb = simply.path.get(model, parentPath); - parentOb[lastName] = value; - }, - pop: function(path) { - return path.split('.').pop(); - }, - push: function(path, name) { - return (path ? path + '.' : '') + name; - }, - parent: function(path) { - var p = path.split('.'); - p.pop(); - return p.join('.'); - }, - parents: function(path) { - var result = []; - path.split('.').reduce(function(acc, name) { - acc.push( (acc.length ? acc[acc.length-1] + '.' : '') + name ); - return acc; - },result); - return result; - } - }; - - return simply; -})(this.simply || {}); -/** - * simply.observe - * This component lets you observe changes in a json compatible data structure - * It doesn't support linking the same object multiple times - * It doesn't register deletion of properties using the delete keyword, assign - * null to the property instead. - * It doesn't register addition of new properties. - * It doesn't register directly assigning new entries in an array on a previously - * non-existant index. - * - * usage: - * - * (function) simply.observe( (object) model, (string) path, (function) callback) - * - * var model = { foo: { bar: 'baz' } }; - * var removeObserver = simply.observe(model, 'foo.bar', function(value, sourcePath) { - * console.log(sourcePath+': '+value); - * }; - * - * The function returns a function that removes the observer when called. - * - * The component can observe in place changes in arrays, either by changing - * an item in a specific index, by calling methods on the array that change - * the array in place or by reassigning the array with a new value. - * - * The sourcePath contains the exact entry that was changed, the value is the - * value for the path passed to simply.observe. - * If an array method was called that changes the array in place, the sourcePath - * also contains that method and its arguments JSON serialized. - * - * sourcePath parts are always seperated with '.', even for array indexes. - * so if foo = [ 'bar' ], the path to 'bar' would be 'foo.0' - */ - - /* - FIXME: child properties added after initial observe() call aren't added to the - childListeners. onMissingChildren can't then find them. - TODO: onMissingChildren must loop through all fields to get only the direct child -properties for a given parent, keep seperate index for this? - */ - -this.simply = (function (simply, global) { - var changeListeners = new WeakMap(); - var parentListeners = new WeakMap(); - var childListeners = new WeakMap(); - var changesSignalled = {}; - var observersPaused = 0; - - function signalChange(model, path, value, sourcePath) { - if (observersPaused) { - return; - } - - sourcePath = sourcePath ? sourcePath : path; - changesSignalled = {}; - - var signalRecursion = function(model, path, value, sourcePath) { - if (changeListeners.has(model) && changeListeners.get(model)[path]) { - // changeListeners[model][path] contains callback methods - changeListeners.get(model)[path].forEach(function(callback) { - changesSignalled[path] = true; - callback(value, sourcePath); - }); - } - }; - - //TODO: check if this is correct - //previous version only triggered parentListeners when no changeListeners were - //triggered. that created problems with arrays. make an exhaustive unit test. - signalRecursion(model, path, value, sourcePath); - - if (parentListeners.has(model) && parentListeners.get(model)[path]) { - // parentListeners[model][path] contains child paths to signal change on - // if a parent object is changed, this signals the change to the child objects - parentListeners.get(model)[path].forEach(function(childPath) { - if (!changesSignalled[childPath]) { - var value = getByPath(model, childPath); - if (value) { - attach(model, childPath); - } - signalRecursion(model, childPath, value, sourcePath); - changesSignalled[childPath] = true; - } - }); - } - - if (childListeners.has(model) && childListeners.get(model)[path]) { - // childListeners[model][path] contains parent paths to signal change on - // if a child object is changed, this signals the change to the parent objects - childListeners.get(model)[path].forEach(function(parentPath) { - if (!changesSignalled[parentPath]) { - var value = getByPath(model, parentPath); - signalRecursion(model, parentPath, value, sourcePath); - changesSignalled[parentPath] = true; - // check if the parent object still has this child property - //FIXME: add a setter trigger here to restore observers once the child property get set again - - } - }); - } - - } - - function getByPath(model, path) { - var parts = path.split('.'); - var curr = model; - do { - curr = curr[parts.shift()]; - } while (parts.length && curr); - return curr; - } - - function parent(path) { - var parts = path.split('.'); - parts.pop(); - return parts.join('.'); - } - - function head(path) { - return path.split('.').shift(); - } - - function onParents(model, path, callback) { - var parent = ''; - var parentOb = model; - var parents = path.split('.'); - do { - var head = parents.shift(); - if (parentOb && typeof parentOb[head] != 'undefined') { - callback(parentOb, head, (parent ? parent + '.' + head : head)); - parentOb = parentOb[head]; - } - parent = (parent ? parent + '.' + head : head ); - } while (parents.length); - } - - function onChildren(model, path, callback) { - var onChildObjects = function(object, path, callback) { - if (typeof object != 'object' || object == null) { - return; - } - if (Array.isArray(object)) { - return; - } - // register the current keys - Object.keys(object).forEach(function(key) { - callback(object, key, path+'.'+key); - onChildObjects(object[key], path+'.'+key, callback); - }); - }; - var parent = getByPath(model, path); - onChildObjects(parent, path, callback); - } - - function onMissingChildren(model, path, callback) { - var allChildren = Object.keys(childListeners.get(model) || []).filter(function(childPath) { - return childPath.substr(0, path.length)==path && childPath.length>path.length; - }); - if (!allChildren.length) { - return; - } - var object = getByPath(model, path); - var keysSeen = {}; - allChildren.forEach(function(childPath) { - var key = head(childPath.substr(path.length+1)); - if (typeof object[key] == 'undefined') { - if (!keysSeen[key]) { - callback(object, key, path+'.'+key); - keysSeen[key] = true; - } - } else { - onMissingChildren(model, path+'.'+key, callback); - } - }); - } - - function addChangeListener(model, path, callback) { - if (!changeListeners.has(model)) { - changeListeners.set(model, {}); - } - if (!changeListeners.get(model)[path]) { - changeListeners.get(model)[path] = []; - } - changeListeners.get(model)[path].push(callback); - - if (!parentListeners.has(model)) { - parentListeners.set(model, {}); - } - var parentPath = parent(path); - onParents(model, parentPath, function(parentOb, key, currPath) { - if (!parentListeners.get(model)[currPath]) { - parentListeners.get(model)[currPath] = []; - } - parentListeners.get(model)[currPath].push(path); - }); - - if (!childListeners.has(model)) { - childListeners.set(model, {}); - } - onChildren(model, path, function(childOb, key, currPath) { - if (!childListeners.get(model)[currPath]) { - childListeners.get(model)[currPath] = []; - } - childListeners.get(model)[currPath].push(path); - }); - } - - function removeChangeListener(model, path, callback) { - if (!changeListeners.has(model)) { - return; - } - if (changeListeners.get(model)[path]) { - changeListeners.get(model)[path] = changeListeners.get(model)[path].filter(function(f) { - return f != callback; - }); - } - } - - function pauseObservers() { - observersPaused++; - } - - function resumeObservers() { - observersPaused--; - } - - function attach(model, path, options) { - - var attachArray = function(object, path) { - var desc = Object.getOwnPropertyDescriptor(object, 'push'); - if (!desc || desc.configurable) { - for (var f of ['push','pop','reverse','shift','sort','splice','unshift','copyWithin']) { - (function(f) { - try { - Object.defineProperty(object, f, { - value: function() { - pauseObservers(); - var result = Array.prototype[f].apply(this, arguments); - attach(model, path); - var args = [].slice.call(arguments).map(function(arg) { - return JSON.stringify(arg); - }); - resumeObservers(); - signalChange(model, path, this, path+'.'+f+'('+args.join(',')+')'); - return result; - }, - readable: false, - enumerable: false, - configurable: false - }); - } catch(e) { - console.error('simply.observer: Error: Couldn\'t redefine array method '+f+' on '+path, e); - } - }(f)); - } - for (var i=0, l=object.length; i=0; i--) { - if (el.matches(handlers[i].match)) { - matched = true; - if (handlers[i].check(el, evt)) { - return { - name: el.dataset.simplyCommand, - source: el, - value: handlers[i].get(el) - }; - } - } - } - if (!matched && fallbackHandler.check(el,evt)) { - return { - name: el.dataset.simplyCommand, - source: el, - value: fallbackHandler.get(el) - }; - } - } - return null; - } - - simply.command = function(app, inCommands) { - - var commands = Object.create(defaultCommands); - for (var i in inCommands) { - commands[i] = inCommands[i]; - } - - commands.app = app; - - commands.action = function(name) { - var params = Array.prototype.slice.call(arguments); - params.shift(); - return app.actions[name].apply(app.actions,params); - }; - - commands.call = function(name) { - var params = Array.prototype.slice.call(arguments); - params.shift(); - return this[name].apply(this,params); - }; - - commands.appendHandler = function(handler) { - handlers.push(handler); - }; - - commands.prependHandler = function(handler) { - handlers.unshift(handler); - }; - - var commandHandler = function(evt) { - var command = getCommand(evt); - if ( command ) { - if (!commands[command.name]) { - console.error('simply.command: undefined command '+command.name, command.source); - } else { - commands.call(command.name, command.source, command.value); - evt.preventDefault(); - evt.stopPropagation(); - return false; - } - } - }; - - app.container.addEventListener('click', commandHandler); - app.container.addEventListener('submit', commandHandler); - app.container.addEventListener('change', commandHandler); - app.container.addEventListener('input', commandHandler); - - return commands; - }; - - return simply; - -})(this.simply || {}, this); -this.simply = (function(simply, global) { - - var knownCollections = {}; - - simply.collect = { - addListener: function(name, callback) { - if (!knownCollections[name]) { - knownCollections[name] = []; - } - if (knownCollections[name].indexOf(callback) == -1) { - knownCollections[name].push(callback); - } - }, - removeListener: function(name, callback) { - if (knownCollections[name]) { - var index = knownCollections[name].indexOf(callback); - if (index>=0) { - knownCollections[name].splice(index, 1); - } - } - }, - update: function(element, value) { - element.value = value; - element.dispatchEvent(new Event('change', { - bubbles: true, - cancelable: true - })); - } - }; - - function findCollection(el) { - while (el && !el.dataset.simplyCollection) { - el = el.parentElement; - } - return el; - } - - document.addEventListener('change', function(evt) { - var root = null; - var name = ''; - if (evt.target.dataset.simplyElement) { - root = findCollection(evt.target); - if (root && root.dataset) { - name = root.dataset.simplyCollection; - } - } - if (name && knownCollections[name]) { - var inputs = root.querySelectorAll('[data-simply-element]'); - var elements = [].reduce.call(inputs, function(elements, input) { - elements[input.dataset.simplyElement] = input; - return elements; - }, {}); - for (var i=knownCollections[name].length-1; i>=0; i--) { - var result = knownCollections[name][i].call(evt.target.form, elements); - if (result === false) { - break; - } - } - } - }, true); - - return simply; - -})(this.simply || {}, this); -this.simply = (function(simply, global) { - if (!simply.observe) { - console.error('Error: simply.bind requires simply.observe'); - return simply; - } - - function getByPath(model, path) { - var parts = path.split('.'); - var curr = model; - do { - curr = curr[parts.shift()]; - } while (parts.length && curr); - return curr; - } - - function setByPath(model, path, value) { - var parts = path.split('.'); - var curr = model; - while (parts.length>1 && curr) { - var key = parts.shift(); - if (typeof curr[key] == 'undefined' || curr[key]==null) { - curr[key] = {}; - } - curr = curr[key]; - } - curr[parts.shift()] = value; - } - - function setValue(el, value, binding) { - if (el!=focusedElement) { - var fieldType = getFieldType(binding.fieldTypes, el); - if (fieldType) { - fieldType.set.call(el, (typeof value != 'undefined' ? value : ''), binding); - el.dispatchEvent(new Event('simply.bind.resolved', { - bubbles: true, - cancelable: false - })); - } - } - } - - function getValue(el, binding) { - var setters = Object.keys(binding.fieldTypes); - for(var i=setters.length-1;i>=0;i--) { - if (el.matches(setters[i])) { - return binding.fieldTypes[setters[i]].get.call(el); - } - } - } - - function getFieldType(fieldTypes, el) { - var setters = Object.keys(fieldTypes); - for(var i=setters.length-1;i>=0;i--) { - if (el.matches(setters[i])) { - return fieldTypes[setters[i]]; - } - } - return null; - } - - function getPath(el, attribute) { - var attributes = attribute.split(','); - for (var attr of attributes) { - if (el.hasAttribute(attr)) { - return el.getAttribute(attr); - } - } - return null; - } - - function throttle( callbackFunction, intervalTime ) { - var eventId = 0; - return function() { - var myArguments = arguments; - var me = this; - if ( eventId ) { - return; - } else { - eventId = global.setTimeout( function() { - callbackFunction.apply(me, myArguments); - eventId = 0; - }, intervalTime ); - } - }; - } - - var runWhenIdle = (function() { - if (global.requestIdleCallback) { - return function(callback) { - global.requestIdleCallback(callback, {timeout: 500}); - }; - } - return global.requestAnimationFrame; - })(); - - function Binding(config, force) { - this.config = config; - if (!this.config) { - this.config = {}; - } - if (!this.config.model) { - this.config.model = {}; - } - if (!this.config.attribute) { - this.config.attribute = 'data-simply-bind'; - } - if (!this.config.selector) { - this.config.selector = '[data-simply-bind]'; - } - if (!this.config.container) { - this.config.container = document; - } - if (typeof this.config.twoway == 'undefined') { - this.config.twoway = true; - } - this.fieldTypes = { - '*': { - set: function(value) { - this.innerHTML = value; - }, - get: function() { - return this.innerHTML; - } - } - }; - if (this.config.fieldTypes) { - Object.assign(this.fieldTypes, this.config.fieldTypes); - } - this.attach(this.config.container.querySelectorAll(this.config.selector), this.config.model, force); - if (this.config.twoway) { - var self = this; - var observer = new MutationObserver( - throttle(function() { - runWhenIdle(function() { - self.attach(self.config.container.querySelectorAll(self.config.selector), self.config.model); - }); - }) - ); - observer.observe(this.config.container, { - subtree: true, - childList: true - }); - } - } - - var focusedElement = null; - var initialized = new WeakMap(); - var observers = new WeakMap(); - var observersPaused = 0; - - Binding.prototype.attach = function(el, model, force) { - var illegalNesting = function() { - return (!force && el.parentElement && el.parentElement.closest(self.config.selector)); - }; - - var attachElement = function(jsonPath) { - el.dataset.simplyBound = true; - initElement(el); - setValue(el, getByPath(model, jsonPath), self); - simply.observe(model, jsonPath, function(value) { - if (el != focusedElement) { - setValue(el, value, self); - } - }); - }; - - var addMutationObserver = function(jsonPath) { - if (el.dataset.simplyList) { - return; - } - var update = throttle(function() { - runWhenIdle(function() { - var v = getValue(el, self); - var s = getByPath(model, jsonPath); - if (v != s) { - focusedElement = el; - setByPath(model, jsonPath, v); - focusedElement = null; - } - }); - }, 250); - var observer = new MutationObserver(function() { - if (observersPaused) { - return; - } - update(); - }); - observer.observe(el, { - characterData: true, - subtree: true, - childList: true, - attributes: true - }); - if (!observers.has(el)) { - observers.set(el, []); - } - observers.get(el).push(observer); - return observer; - }; - - /** - * Runs the init() method of the fieldType, if it is defined. - **/ - var initElement = function(el) { - if (initialized.has(el)) { - return; - } - initialized.set(el, true); - var selectors = Object.keys(self.fieldTypes); - for (var i=selectors.length-1; i>=0; i--) { - if (self.fieldTypes[selectors[i]].init && el.matches(selectors[i])) { - self.fieldTypes[selectors[i]].init.call(el, self); - return; - } - } - }; - - var self = this; - if (el instanceof HTMLElement) { - if (!force && el.dataset.simplyBound) { - return; - } - var jsonPath = getPath(el, this.config.attribute); - if (illegalNesting(el)) { - el.dataset.simplyBound = 'Error: nested binding'; - console.error('Error: found nested data-binding element:',el); - return; - } - attachElement(jsonPath); - if (this.config.twoway) { - addMutationObserver(jsonPath); - } - } else { - [].forEach.call(el, function(element) { - self.attach(element, model, force); - }); - } - }; - - Binding.prototype.pauseObservers = function() { - observersPaused++; - }; - - Binding.prototype.resumeObservers = function() { - observersPaused--; - }; - - simply.bind = function(config, force) { - return new Binding(config, force); - }; - - return simply; -})(this.simply || {}, this);this.simply = (function(simply, global) { - simply.app = function(options) { - if (!options) { - options = {}; - } - if (!options.container) { - console.warn('No simply.app application container element specified, using document.body.'); - } - - function simplyApp(options) { - if (!options) { - options = {}; - } - if ( options.routes ) { - simply.route.load(options.routes); - simply.route.handleEvents(); - global.setTimeout(function() { - simply.route.match(global.location.pathname+global.location.hash); - },1); - } - this.container = options.container || document.body; - this.actions = simply.action ? simply.action(this, options.actions) : false; - this.commands = simply.command ? simply.command(this, options.commands) : false; - this.resize = simply.resize ? simply.resize(this, options.resize) : false; - this.view = simply.view ? simply.view(this, options.view) : false; - if (!(global.editor && global.editor.field) && simply.bind) { - // skip simplyview databinding if SimplyEdit is loaded - options.bind = simply.render(options.bind || {}); - options.bind.model = this.view; - options.bind.container = this.container; - this.bind = options.bindings = simply.bind(options.bind); - } - } - - simplyApp.prototype.get = function(id) { - return this.container.querySelector('[data-simply-id='+id+']') || document.getElementById(id); - }; - - var app = new simplyApp(options); - - return app; - }; - - return simply; -})(this.simply || {}, this); -this.simply = (function(simply, global) { - - var listeners = {}; - - simply.activate = { - addListener: function(name, callback) { - if (!listeners[name]) { - listeners[name] = []; - } - listeners[name].push(callback); - initialCall(name); - }, - removeListener: function(name, callback) { - if (!listeners[name]) { - return false; - } - listeners[name] = listeners[name].filter(function(listener) { - return listener!=callback; - }); - } - }; - - var initialCall = function(name) { - var nodes = document.querySelectorAll('[data-simply-activate="'+name+'"]'); - if (nodes) { - [].forEach.call(nodes, function(node) { - callListeners(node); - }); - } - }; - - var callListeners = function(node) { - if (node && node.dataset.simplyActivate - && listeners[node.dataset.simplyActivate] - ) { - listeners[node.dataset.simplyActivate].forEach(function(callback) { - callback.call(node); - }); - } - }; - - var handleChanges = function(changes) { - var activateNodes = []; - for (var change of changes) { - if (change.type=='childList') { - [].forEach.call(change.addedNodes, function(node) { - if (node.querySelectorAll) { - var toActivate = [].slice.call(node.querySelectorAll('[data-simply-activate]')); - if (node.matches('[data-simply-activate]')) { - toActivate.push(node); - } - activateNodes = activateNodes.concat(toActivate); - } - }); - } - } - if (activateNodes.length) { - activateNodes.forEach(function(node) { - callListeners(node); - }); - } - }; - - var observer = new MutationObserver(handleChanges); - observer.observe(document, { - subtree: true, - childList: true - }); - - return simply; -})(this.simply || {}, this); -this.simply = (function(simply, global) { - var defaultActions = { - 'simply-hide': function(el) { - el.classList.remove('simply-visible'); - return Promise.resolve(); - }, - 'simply-show': function(el) { - el.classList.add('simply-visible'); - return Promise.resolve(); - }, - 'simply-select': function(el,group,target,targetGroup) { - if (group) { - this.call('simply-deselect', this.app.container.querySelectorAll('[data-simply-group='+group+']')); - } - el.classList.add('simply-selected'); - if (target) { - this.call('simply-select',target,targetGroup); - } - return Promise.resolve(); - }, - 'simply-toggle-select': function(el,group,target,targetGroup) { - if (!el.classList.contains('simply-selected')) { - this.call('simply-select',el,group,target,targetGroup); - } else { - this.call('simply-deselect',el,target); - } - return Promise.resolve(); - }, - 'simply-toggle-class': function(el,className,target) { - if (!target) { - target = el; - } - return Promise.resolve(target.classList.toggle(className)); - }, - 'simply-deselect': function(el,target) { - if ( typeof el.length=='number' && typeof el.item=='function') { - el = Array.prototype.slice.call(el); - } - if ( Array.isArray(el) ) { - for (var i=0,l=el.length; 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
?v*MdKU_B!Q$rgrI_g1M+68GkUyp!ahv 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 I{5SRg0c(>dEC2ui diff --git a/www/simply-edit/bg2.jpg b/www/simply-edit/bg2.jpg deleted file mode 100644 index 3230b8a5c03e1bf713eb9102af5171eec2a97ca8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21158 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 B;@1EG diff --git a/www/simply-edit/checks.php b/www/simply-edit/checks.php deleted file mode 100755 index 659e1d5..0000000 --- a/www/simply-edit/checks.php +++ /dev/null @@ -1,287 +0,0 @@ - [ - 'title' => 'Checking data directory', - 'checks' => [ - 'exists' => [ - 'title' => 'Does it exist?', - 'check' => function() { - if ( filesystem::exists('/data/') ) { - return ok(); - } - return fail(filesystem::$basedir.'/data/ directory is missing'); - } - ], - 'readable' => [ - 'title' => 'Is it readable?', - 'check' => function() use ($user) { - if ( is_readable(filesystem::$basedir.'/data/') ) { - if ( is_dir(filesystem::$basedir.'/data/') ) { - return ok(); - } else { - return fail(filesystem::$basedir.'/data/ is not a directory'); - } - } else { - return fail(filesystem::$basedir.'/data/ directory is not readable. Grant read and write access for user '.$user); - } - } - ], - 'writable' => [ - 'title' => 'Is it writable?', - 'check' => function() use ($user) { - if ( is_writable(filesystem::$basedir.'/data/') ) { - return ok(); - } else { - return fail(filesystem::$basedir.'/data/ directory is not writable. Grant read and write access for user '.$user); - } - } - ] - ] - ], - 'img' => [ - 'title' => 'Checking img directory', - 'checks' => [ - 'exists' => [ - 'title' => 'Does it exist?', - 'check' => function() { - if ( filesystem::exists('/img/') ) { - return ok(); - } - return fail(filesystem::$basedir.'/img/ directory is missing'); - } - ], - 'readable' => [ - 'title' => 'Is it readable?', - 'check' => function() use ($user) { - if ( is_readable(filesystem::$basedir.'/img/') ) { - if ( is_dir(filesystem::$basedir.'/img/') ) { - return ok(); - } else { - return fail(filesystem::$basedir.'/img/ is not a directory'); - } - } else { - return fail(filesystem::$basedir.'/img/ directory is not readable. Grant read and write access for user '.$user); - } - } - ], - 'writable' => [ - 'title' => 'Is it writable?', - 'check' => function() use ($user) { - if ( is_writable(filesystem::$basedir.'/img/') ) { - return ok(); - } else { - return fail(filesystem::$basedir.'/img/ directory is not writable. Grant read and write access for user '.$user); - } - } - ] - ] - ], - 'files' => [ - 'title' => 'Checking files directory', - 'checks' => [ - 'exists' => [ - 'title' => 'Does it exist?', - 'check' => function() { - if ( filesystem::exists('/files/') ) { - return ok(); - } - return fail(filesystem::$basedir.'files directory is missing'); - } - ], - 'readable' => [ - 'title' => 'Is it readable?', - 'check' => function() use ($user) { - if ( is_readable(filesystem::$basedir.'/files/') ) { - if ( is_dir(filesystem::$basedir.'/files/') ) { - return ok(); - } else { - return fail(filesystem::$basedir.'/files/ is not a directory'); - } - } else { - return fail(filesystem::$basedir.'/files/ directory is not readable. Grant read and write access for user '.$user); - } - } - ], - 'writable' => [ - 'title' => 'Is it writable?', - 'check' => function() use ($user) { - if ( is_writable(filesystem::$basedir.'/files/') ) { - return ok(); - } else { - return fail(filesystem::$basedir.'/files/ directory is not writable. Grant read and write access for user '.$user); - } - } - ] - ] - ], - '.htaccess' => [ - 'title' => '.htaccess (Apache configuration)', - 'checks' => [ - 'exists' => [ - 'title' => 'Checking if .htaccess file exists', - 'check' => function() { - $contents = filesystem::get('/', '.htaccess'); - if ($contents && strlen($contents)) { - return ok(); - } else { - return fail('Missing or empty .htaccess file in the document root.'); - } - } - ] - ] - ], - '.htpasswd' => [ - 'title' => '.htpasswd (users and passwords file)', - 'checks' => [ - 'exists' => [ - 'title' => 'Checking if .htpasswd file exists', - 'check' => function() { - $contents = filesystem::get('/data/', '.htpasswd'); - if ($contents && strlen($contents)) { - return ok(); - } else { - return fail('Missing or empty .htpasswd file in the document root.'); - } - } - ], - 'user' => [ - 'title' => 'Checking if it contains a valid user.', - 'check' => function() { - htpasswd::load('/data/','.htpasswd'); - if ( htpasswd::$users && count(htpasswd::$users)) { - return ok(); - } else { - return fail('No users defined in .htpasswd file. Please add at least one user through the "Users" dialog.'); - } - } - ], - 'simplyedit' => [ - 'title' => 'Checking if simplyedit user has been disabled.', - 'check' => function() { - if ( htpasswd::$users['simplyedit'] ) { - return fail('Please delete the user simplyedit and replace it with a personal account.'); - } - return ok(); - } - ] - ] - ], - 'key' => [ - 'title' => 'Checking API keys', - 'check' => function() { - $fails = []; - $files = []; - // check index.html or index.php - if ( !is_readable(filesystem::$basedir.'/index.html') && !is_readable(filesystem::$basedir.'/index.php')) { - $fails[] = fail(filesystem::$basedir.'/ has no readable index.php or index.html. Create one and grant read access for user '.$user); - } else if (is_readable(filesystem::$basedir.'/index.html')) { - $files[] = filesystem::$basedir.'/index.html'; - } - // check templates/ - if ( is_dir(filesystem::$basedir.'/templates/') ) { - if ( !is_readable(filesystem::$basedir.'/templates/') ) { - $fails[] = fail(filesystem::$basedir.'/templates/ directory is not readable. Grant read access for user '.$user); - } else { - $dir = opendir(filesystem::$basedir.'/templates/'); - } - if ( $dir ) { - while (false !== ($entry = readdir($dir))) { - $entry = filesystem::$basedir.'/templates/'.$entry; - if (is_file($entry) && is_readable($entry)) { - $files[] = $entry; - } - } - } - } - foreach ( $files as $file ) { - $error = checkKey($file); - if ( $error ) { - $fails[] = fail($error); - } - } - if ( !count($fails) ) { - return ok(); - } else { - return join("
\n",$fails); - } - } - ] - ]; - - function checkKey($file) { - global $user; - $contents = file_get_contents($file); - if ( $contents === false ) { - return 'Could not read '.$file.'. Grant read access for user '.$user; - } - if (!preg_match('/data-api-key\s*=\s*"([^"]*)"/',$contents, $matches)) { - return $file.' has no data-api-key attribute.'; - } - if ($matches[1]=='localhost') { - return $file.' has API key "localhost", which will only work locally.'; - } - if ($matches[1]=='simplyedit') { - return $file.' has an invalid API key "simplyedit", please grab a license key and enter it.'; - } - } - - function ok() { - return true; - } - - function fail($msg) { - return '
'.$msg.'
'; - } - - function run_check($check) { - if ( $check['checks'] ) { - $result = run_checks($check['checks']); - } else { - try { - $result = $check['check'](); - } catch(\Exception $e) { - $result = fail($check['title'].': '.$e->getMessage()); - } - } - return $result; - } - - function run_checks($checks) { - $results = []; - foreach ($checks as $name => $check) { - $results[$name] = run_check($check); - } - return $results; - } - - function flatten($array) { - $flat = []; - array_walk_recursive( $array, function($value) use(&$flat) { - $flat[] = $value; - }); - return $flat; - } - - $results = flatten(run_checks($checks)); - $errors = array_filter($results, function($value) { - return $value !== true; - }); - $percentage = 100; - if ( count($errors) ) { - $percentage = 100 - round(( count($errors) / count($results) ) * 100); - } \ No newline at end of file diff --git a/www/simply-edit/config.php b/www/simply-edit/config.php deleted file mode 100644 index 56d74d3..0000000 --- a/www/simply-edit/config.php +++ /dev/null @@ -1,38 +0,0 @@ - $mimetypes ) { - if ( strpos($dirname, $path)===0 ) { - $allowed = true; - break; - } - } - if ( !$allowed ) { - throw new fsException('Access denied for '.$dirname.$filename, 106); - } - $finfo = new finfo(FILEINFO_MIME); - $mimetype = $finfo->file($tempfile); - $mimetypes[]= 'inode/x-empty'; - $mimetypeRe = '{'.implode('|', $mimetypes).'}i'; - if ( !preg_match($mimetypeRe, $mimetype) ) { - throw new fsException('Files with mimetype '.$mimetype.' are not allowed in '.$dirname, 108); - } - return true; - } - - private static function runChecks($method, $filename, $tempfile) - { - if ( !isset(self::$checks[$method]) ) { - return; - } - foreach ( self::$checks[$method] as $path => $checks ) { - foreach ( $checks as $callback ) { - if ( strpos($filename, $path)===0 ) { - $callback($filename, $tempfile); - } - } - } - } - - private static function dirNotWritable($dirname) - { - // FIXME: try to find out why it is not writable - // check if dir exists - // check if dir is writable - // check if dirname is a directory - // check permissions on dirname - // check owner and current user - throw new fsException('Directory '.$dirname.' is not writable', 102); - } - - private static function fileNotWritable($file) - { - // FIXME: try to find out why it is not writable - throw new fsException('File '.$file.' is not writeable', 103); - } - - private static function renameFailed($file, $tempfile) - { - // FIXME: try to find out why the rename failed - unlink($tempfile); - throw new fsException('Could not move file contents to '.$file, 104); - } - - public static function exists($filename) { - $realfile = realpath(self::$basedir . $filename ); - return file_exists($realfile); - } - - private static function passthru($dirname, $filename, $hash=null) - { - list($realdir,$realfile)=self::realpaths($dirname,$filename); - $lock = self::lock($realfile); - if ( !$lock ) { - throw new fsException('Could not lock '.$dirname.$filename.' for writing', 109); - } - /* PUT data comes in on the stdin stream */ - $in = fopen("php://input", "r"); - - /* Open a file for writing */ - $tempfile = tempnam($realdir, 'put-'); - chmod($tempfile, 0644); - $out = fopen($tempfile, "w"); - $res = stream_copy_to_stream($in,$out); - - /* Close the streams */ - fclose($out); - fclose($in); - - $exception = false; - try { - if ($res!==false) { - if ( !self::isAllowed($dirname, $filename, $tempfile) ) { - throw new fsException('Access denied for '.self::append($dirname,$filename), 106); - } - self::runChecks('put', self::append($dirname,$filename), $tempfile); - $res = rename($tempfile, $realfile); - if ($res == false) { - self::renameFailed(self::append($dirname,$filename), $tempfile); - } - } else { - } - } catch( \Exception $e ) { - $exception = $e; - } finally { - self::unlock($lock); - @unlink($tempfile); - } - if ( $exception ) { - throw $exception; - } - return true; - } - - private static function lock($filename) - { - $fp = fopen($filename.'.lock', 'w'); - if ( $fp && flock($fp, LOCK_EX ) ) { - return [ - 'resource' => $fp, - 'filename' => $filename - ]; - } - return false; - } - - private static function unlock($lock) - { - flock($lock['resource'], LOCK_UN); - fclose($lock['resource']); - unlink($lock['filename'].'.lock'); - } -} diff --git a/www/simply-edit/htpasswd.php b/www/simply-edit/htpasswd.php deleted file mode 100644 index 5f48dc3..0000000 --- a/www/simply-edit/htpasswd.php +++ /dev/null @@ -1,122 +0,0 @@ - -// based partly on https://elonen.iki.fi/code/misc-notes/htpasswd-php/ -// -// Copyright (C) 2004,2005 Jarno Elonen -// -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, this -// list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * The name of the author may not be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED -// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY -// AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR -// BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - class htpasswd { - static $users = []; - - public static function load($filename) { - $lines = preg_split('/\r\n|\r|\n/',filesystem::get('/', $filename)); - foreach ($lines as $line) { - list($user,$password) = array_map('trim', explode(':',$line)); - if ($user && $password) { - self::$users[$user] = $password; - } - } - } - - public static function check($user, $password) { - if ( !isset(self::$users[$user]) ) { - return false; - } - $checks = [ '{SSHA}' => 'saltedSHA1', '{SHA}' => 'SHA1', '$apr1$' => 'MD5', '$2y$' => 'bcrypt' ]; - $crypted = self::$users[$user]; - $check = 'crypt'; - foreach($checks as $match => $algorithm) { - if ( strpos($crypted, $match) === 0 ) { - $check = $algorithm; - break; - } - } - //echo $check; - return self::$check($crypted, $password); - } - - private static function crypt($crypted, $password) { - return (crypt( $password, substr($crypted,0,CRYPT_SALT_LENGTH) ) == $crypted); - } - - private static function saltedSHA1($crypted, $password) { - $hash = base64_decode(substr($crypted, 6)); - return (substr($hash, 0, 20) == pack('H*', sha1($password . substr($hash, 20)))); - } - - private static function SHA1($crypted, $password) { - $non_salted_sha1 = "{SHA}" . base64_encode(pack("H*", sha1($password))); - //echo "[".$crypted.' == '.$non_salted_sha1.']'; - return ($non_salted_sha1 == $crypted); - } - - private static function MD5($crypted, $password) { - // thanks to http://blog.ethlo.com/2013/02/01/using-php-and-existing-htpasswd-file-for-authentication.html - $passParts = explode('$', $crypted); - $salt = $passParts[2]; - $hashed = self::cryptApr1Md5($password, $salt); - return $hashed == $crypted; - } - - private static function bcrypt($crypted, $password) { - return password_verify($password, $crypted); - } - - private function cryptApr1Md5($plainpasswd, $salt) { - $len = strlen($plainpasswd); - $text = $plainpasswd.'$apr1$'.$salt; - $bin = pack("H32", md5($plainpasswd.$salt.$plainpasswd)); - for ($i = $len; $i > 0; $i -= 16) { - $text .= substr($bin, 0, min(16, $i)); - } - for ($i = $len; $i > 0; $i >>= 1) { - $text .= ($i & 1) ? chr(0) : $plainpasswd{0}; - } - $bin = pack("H32", md5($text)); - for ($i = 0; $i < 1000; $i++) { - $new = ($i & 1) ? $plainpasswd : $bin; - if ($i % 3) { - $new .= $salt; - } - if ($i % 7) { - $new .= $plainpasswd; - } - $new .= ($i & 1) ? $bin : $plainpasswd; - $bin = pack("H32", md5($new)); - } - $tmp = ''; - for ($i = 0; $i < 5; $i++) { - $k = $i + 6; - $j = $i + 12; - if ($j == 16) { - $j = 5; - } - $tmp = $bin[$i].$bin[$k].$bin[$j].$tmp; - } - $tmp = chr(0).chr(0).$bin[11].$tmp; - $tmp = strtr(strrev(substr(base64_encode($tmp), 2)), - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", - "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"); - return "$"."apr1"."$".$salt."$".$tmp; - } - } diff --git a/www/simply-edit/http.php b/www/simply-edit/http.php deleted file mode 100755 index 6ce1524..0000000 --- a/www/simply-edit/http.php +++ /dev/null @@ -1,128 +0,0 @@ - false ]; - } - foreach ( $list as $header => $extraInfo ) { - for ($i=$redirectLevel; $i>=0; $i--) { - $check = str_repeat($redirect, $i).$header; - if ( isset($_SERVER[$check]) ) { - return [$header, $_SERVER[$check]]; - } - } - } - return [false, '']; - } - - private static function parseAuthUser($auth) { - return explode(':',base64_decode(substr($auth, 6))); - } - - public static function getUser() - { - $checks = [ - 'PHP_AUTH_USER' => false, - 'REMOTE_USER' => false, - 'HTTP_AUTHORIZATION' => [self,parseAuthUser], - ]; - list($header, $headerValue) = self::getHeader($checks, 3); - if (is_array($checks[$header])) { - $headerValue = call_user_func($checks[$header], $headerValue)[0]; - } - return $headerValue; - } - - public static function getPassword() - { - $checks = [ - 'PHP_AUTH_PW' => false, - 'HTTP_AUTHORIZATION' => [self,parseAuthUser], - ]; - list($header, $headerValue) = self::getHeader($checks, 3); - if (is_array($checks[$header])) { - $headerValue = call_user_func($checks[$header], $headerValue)[1]; - } - return $headerValue; - } - - public static function getMethod() - { - list($header, $headerValue) = self::getHeader('REQUEST_METHOD',3); - if ($headerValue==='POST') { - if ($_GET['_method']=='PUT'||$_GET['_method']=='DELETE') { - $headerValue = $_GET['_method']; - } - } - return $headerValue; - } - - public static function request() - { - $target = preg_replace('@\?.*$@','',$_SERVER["REQUEST_URI"]); - $target = self::sanitizeTarget($target); - - preg_match('@(?.+/)?(?[^/]*)@',$target,$matches); - - $filename = isset($matches['filename']) ? $matches['filename'] : ''; - $dirname = ( isset($matches['dirname']) ? filesystem::path($matches['dirname']) : '/'); - $docroot = $_SERVER['DOCUMENT_ROOT']; - $subdir = filesystem::path( substr( dirname(dirname($_SERVER['SCRIPT_FILENAME'])), strlen($docroot) ) ); - $dirname = filesystem::path( substr($dirname, strlen($subdir) ) ); - $request = [ - 'protocol' => $_SERVER['SERVER_PROTOCOL']?:'HTTP/1.1', - 'method' => self::getMethod(), - 'target' => '/'.$target, - 'directory' => $dirname, - 'filename' => $filename, - 'user' => self::getUser(), - 'password' => self::getPassword(), - 'docroot' => $docroot - ]; - return $request; - } - - public static function response($status, $data='') - { - http_response_code($status); - switch(self::$format) { - case 'html': - echo $data; - break; - case 'json': - default: - echo json_encode($data, JSON_UNESCAPED_UNICODE); - break; - } - } - -} diff --git a/www/simply-edit/index.php b/www/simply-edit/index.php deleted file mode 100644 index 041de40..0000000 --- a/www/simply-edit/index.php +++ /dev/null @@ -1,1599 +0,0 @@ - vragen om op te slaan - en save button een saving animatie geven - - foutmelding als opslaan mislukt - */ - - ini_set('display_errors', 1); - ini_set('display_startup_errors', 1); - error_reporting(E_ALL); - require_once('config.php'); - - $statusCodes = [ - 1 => 412, - 2 => 403, - 3 => 403, - 102 => 412, // precondition failed - 103 => 412, - 104 => 412, - 105 => 404, // not found - 106 => 403, // access denied - 107 => 403, - 108 => 403, - 109 => 412, - 110 => 403 - ]; - - $request = http::request(); - - $result = []; - $status = 200; - - try { - htpasswd::load('/data/.htpasswd'); - } catch( \Exception $e) { - // ignore error, just use empty list - } - if (is_array($settings->managers)) { - foreach ((array)$settings->managers as $index => $manager) { - if (!htpasswd::$users[$manager]) { - unset($settings->managers[$index]); - } - } - } else { - $settings->managers = []; - } - $user = $request['user']; - $password = $request['password']; - if ( $_COOKIE['simply-logout'] - || (count(htpasswd::$users) && (!$user || !$password || !htpasswd::check($user, $password))) - || (count((array)$settings->managers) && !in_array($user,$settings->managers)) - ) { - setcookie('simply-logout','',1,'/'); // remove the 'i logged off' cookie - header('HTTP/1.1 401 Forced Logout'); - header('WWW-Authenticate: Basic realm="Simply Store"'); - echo ''; - echo '

401 Forced Logout

'; - die(); - } - - if ( !filesystem::exists('/.htaccess') ) { - $htaccess = << - - Order Allow,Deny - Deny from all - - -RewriteEngine on - - RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] - RewriteCond %{REQUEST_METHOD} PUT - RewriteRule .* simply-edit/store.php [L] - RewriteCond %{REQUEST_METHOD} DELETE - RewriteRule .* simply-edit/store.php [L] - RewriteCond %{QUERY_STRING} _method=(PUT|DELETE) - RewriteRule .* simply-edit/store.php [L] - - - RewriteRule ^logout$ simply-edit/logout.php [L] - #RewriteRule ^login$ simply-edit/login.php [L] - - - RewriteCond %{HTTP_USER_AGENT} Lynx|w3m|googlebot|baiduspider|facebookexternalhit|twitterbot|rogerbot|linkedinbot|embedly|quora\ link\ preview|showyoubot|outbrain|pinterest|slackbot|vkShare|Validator [NC,OR] - RewriteCond %{QUERY_STRING} _escaped_fragment_ - - # Only proxy the request to Prerender if it's a request for HTML - RewriteRule ^(?!.*?(\.js|\.css|\.xml|\.less|\.png|\.jpg|\.jpeg|\.gif|\.pdf|\.doc|\.txt|\.ico|\.rss|\.zip|\.mp3|\.rar|\.exe|\.wmv|\.doc|\.avi|\.ppt|\.mpg|\.mpeg|\.tif|\.wav|\.mov|\.psd|\.ai|\.xls|\.mp4|\.m4a|\.swf|\.dat|\.dmg|\.iso|\.flv|\.m4v|\.torrent|\.ttf|\.woff))(.*) simply-edit/prerender.php [L] - - -Options +Indexes - -RewriteCond %{REQUEST_FILENAME} !-f -RewriteCond %{REQUEST_FILENAME} !-d -RewriteRule .* simply-edit/router.php [L] -EOF; - filesystem::allow('/','.*'); - try { - filesystem::write('/', '.htaccess', $htaccess); - } catch(\Exception $e) { - // visual check will display the error so ignore the exception - } - } - -?> - - - SimplyEdit dashboard - - - - - - - - - - - - - - - - - -
-
-
    -
  • - -
  • -
  • - -
  • -
  • - -
  • -
  • - -
  • -
  • - -
  • -
  • - -
  • -
  • - -
  • -
-
-
-
-
-
- - - - - - - - - - - - diff --git a/www/simply-edit/login.php b/www/simply-edit/login.php deleted file mode 100644 index c6b383b..0000000 --- a/www/simply-edit/login.php +++ /dev/null @@ -1,22 +0,0 @@ - 405, 'message' => 'Access denied']; - } else { - $status = 200; - $result = 'OK'; - } - - http::response( $status, $result ); diff --git a/www/simply-edit/logout.php b/www/simply-edit/logout.php deleted file mode 100644 index 8418f4f..0000000 --- a/www/simply-edit/logout.php +++ /dev/null @@ -1,12 +0,0 @@ - - \ No newline at end of file diff --git a/www/simply-edit/mu.js b/www/simply-edit/mu.js deleted file mode 100644 index 59bffca..0000000 --- a/www/simply-edit/mu.js +++ /dev/null @@ -1,1045 +0,0 @@ -/******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; - -/******/ // The require function -/******/ function __webpack_require__(moduleId) { - -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; - -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ exports: {}, -/******/ id: moduleId, -/******/ loaded: false -/******/ }; - -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); - -/******/ // Flag the module as loaded -/******/ module.loaded = true; - -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } - - -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; - -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; - -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; - -/******/ // Load entry module and return exports -/******/ return __webpack_require__(0); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ function(module, exports, __webpack_require__) { - - window.mu = (function(mu) { - mu.app = function(options) { - if (!options.container) { - console.log('No mu application container element specified.'); - return; - } - - function muApp(options) { - this.container = options.container; - this.actions = mu.actions(this, options.actions); - this.commands = mu.commands(this, options.commands); - //this.keymap = mu.keymap(this, options.keymap); - this.sizes = { - 'mu-tiny' : 0, - 'mu-xsmall' : 480, - 'mu-small' : 768, - 'mu-medium' : 992, - 'mu-large' : 1200 - } - } - muApp.prototype.get = function(id) { - return this.container.querySelector('[data-mu-id='+id+']') || document.getElementById(id); - } - - var app = new muApp(options); - - if ( mu.toolbar ) { - var toolbars = app.container.querySelectorAll('.mu-toolbar'); - for ( var i=0,l=toolbars.length; i=0; i--) { - toolbars[i].style.transform = ''; - } - } - - if ( window.attachEvent ) { - app.container.attachEvent('onresize', resizeSniffer); - } else { - window.setInterval(resizeSniffer, 200); - } - - return app; - }; - - - return mu; - })(window.mu || {}); - - __webpack_require__(1); - mu.actions = __webpack_require__(5); - mu.commands = __webpack_require__(6); - mu.toolbar = __webpack_require__(7); - mu.keyboard = __webpack_require__(8); - mu.keymap = __webpack_require__(9); - - -/***/ }, -/* 1 */ -/***/ function(module, exports, __webpack_require__) { - - // style-loader: Adds some css to the DOM by adding a - - - Layer 1 - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/www/simply-edit/store.php b/www/simply-edit/store.php deleted file mode 100755 index a0b58d9..0000000 --- a/www/simply-edit/store.php +++ /dev/null @@ -1,78 +0,0 @@ - 412, - 2 => 403, - 3 => 403, - 102 => 412, // precondition failed - 103 => 412, - 104 => 412, - 105 => 404, // not found - 106 => 403, // access denied - 107 => 403, - 108 => 403, - 109 => 412, - 110 => 403 - ]; - - $request = http::request(); - - $result = []; - $status = 200; - - try { - htpasswd::load('/data/.htpasswd'); - } catch(\Exception $e) { - // if no htpasswd is set, accept anyone, should only happen during install - } - try { - $user = $request['user']; - $password = $request['password']; - if ( $_COOKIE['simply-logout'] - || (count(htpasswd::$users) && (!$user || !$password || !htpasswd::check($user, $password))) - ) { - setcookie('simply-logout','',1,'/'); // remove the 'i logged off' cookie - header('WWW-Authenticate: Basic realm="Simply Store"'); - $status = 401; - $result = ['error' => 405, 'message' => 'Access denied']; - } else if ( $request['method']=='PUT' ) { - if ($request['directory']=='/data/' && $request['filename']=='htpasswd') { - $request['filename'] = '.htpasswd'; - } - if ( $request['directory']=='/data/' && $request['filename']=='data.json') { - filesystem::copy('/data/','data.json','/data/','data.'.strftime('%Y-%m-%d-%H').'.json'); - // check number of backups vs max_backups - $list = glob('../data/data.*.json'); - if ( count($list) > $settings->max_backups ) { - // clean up old backups - sort($list); - while (count($list) > $settings->max_backups) { - $remove = basename(array_shift($list)); - filesystem::delete('/data/',$remove); - } - } - } - $result = filesystem::put($request['directory'], $request['filename']); - } else if ( $request['method']=='DELETE' ) { - $result = filesystem::delete($request['directory'], $request['filename']); - } else { - $status = 405; //Method not allowed - // why? - $explain = ''; - if ($request['method']!='PUT' && $request['method']!='DELETE') { - $explain .= 'Method "'.$request['method'].'" is unknown. '; - } - $result = [ 'error' => 405, 'message' => 'Method not allowed. '.$explain ]; - } - } catch( \Exception $e ) { - $code = $e->getCode(); - if ( isset($statusCodes[$code]) ) { - $status = $statusCodes[$code]; - } else { - $status = 500; // internal error - } - $result = [ 'error' => $code, 'message' => $e->getMessage() ]; - } - - http::response( $status, $result ); diff --git a/www/simply-edit/style.css b/www/simply-edit/style.css deleted file mode 100644 index 503d519..0000000 --- a/www/simply-edit/style.css +++ /dev/null @@ -1,89 +0,0 @@ -html, -body { - margin: 0; - padding: 0; - border: 0; - height: 100%; - background: linear-gradient(to bottom, #f4f4f4 0%,#fdfdfd 834px,#fdfdfd 100%); /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */ -} -#logo { - padding: 5px; - width: 50px; -} -#simplyedit button, -#simplyedit button * { - color: #666 !important; -} -#simplyedit .mu-toolbar { - border-top-color: #ea5922; -} -#simply-main-toolbar .mu-toolbar { - border-top-width: 5px; -} -#simplyedit .mu-dialog > footer .mu-toolbar { - border-top: 2px solid #ccc; -} -#simplyedit .mu-dialog > section { - overflow: auto; -} -#simplyedit .mu-button.mu-focus, -#simplyedit .mu-button.mu-hover, -#simplyedit .mu-button:focus, -#simplyedit .mu-button:hover { - border-bottom: 2px solid #ea5922 !important; -} -#simplyedit .mu-disabled .mu-button, -#simplyedit .mu-disabled .mu-button *, -#simplyedit .mu-button.mu-disabled, -#simplyedit .mu-button.mu-disabled * { - color: #888!important; - cursor: default; - border-bottom-color: transparent !important; -} -#simplyedit main { - height: 100%; - background-image: url(bg2.jpg); - background-repeat: no-repeat; -} -#simplyedit .mu-dialog>section { - box-shadow: 0 0 25px #666; - border-top-color: #ea5922; -} - - - .simplyedit-checks h1 { - clear: both !important; - font-size:18px !important; - line-height: 24px; - padding: 4px 20px; - background-color: #EEE; - margin: 10px 0 0 0; - } - .simplyedit-checks div { - padding-left: 20px; - } - .simplyedit-checks .simplyedit-checks h1 { - float: left; - clear: both !important; - font-weight: normal; - padding-left: 40px; - } - .simplyedit-checks .simplyedit-checks div { - font-size: 16px; - line-height: 24px; - padding-top: 6px; - } - .simplyedit-fail { - clear: both; - padding-left: 60px; - padding-top: 0; - color: red; - } - .simplyedit-ok { - color: green; - } - .simplyedit-ok::after { - content: ""; - display: block; - clear: both; - } diff --git a/www/simply/css/editor.v9.css b/www/simply/css/editor.v9.css deleted file mode 100644 index e8540d5..0000000 --- a/www/simply/css/editor.v9.css +++ /dev/null @@ -1,2265 +0,0 @@ - *[data-simply-hidden] { - display: none !important; - } - *[data-simply-field] { - outline: 2px dashed rgba(128,128,128,0.3); - transition: 0.6s outline-color ease, 0.6s background-color ease; - } - *[data-simply-field]:hover { - outline: 2px dashed rgba(128, 240, 210, 0.3); - } - *[data-simply-field]:focus { - outline: 2px dashed rgba(240, 210, 128, 0.3); - background-color: rgba(128,128,128,0.2); - } - - *[data-simply-field][data-simply-content=template] { - outline: 0px; - } - *[data-simply-htmlsource] { - outline: 1px dashed rgba(0, 0, 255, 0.3); - } - - *[data-simply-list]:not(.simply-empty):before, - *[data-simply-list-item]:before, - tr[data-simply-list-item] td:first-child:before, - *[data-simply-content='fixed']:before { - font-weight: normal; - font-style: normal; - font-family: FontAwesome; - border: 1px solid #ccc; - border-top: 2px solid #ea5922; - background-color: white; - color: #666; - border-bottom-left-radius: 3px; - border-bottom-right-radius: 3px; - padding: 5px; - position: absolute; - margin-top: -24px; - margin-left: 5px; - opacity: 0.2; - transition: 0.3s opacity ease; - box-shadow: 0px 0px 2px #ccc; - -webkit-box-shadow: 0px 0px 2px #ccc; - -moz-box-shadow: 0px 0px 2px #ccc; - font-size: 15px; - line-height: 15px; - } - *[data-simply-list]:not(.simply-empty):hover:before, - *[data-simply-list-item]:hover:before, - tr[data-simply-list-item]:hover td:first-child:before, - *[data-simply-content='fixed']:before { - opacity: 1; - } - *[data-simply-list-item]:before { - margin-left: 40px; - } - tr[data-simply-list-item] td:first-child:before { - margin-left: -40px; - margin-top: 0; - } - - *[data-simply-list-item]:not([data-simply-list-icon]):before, - tr[data-simply-list-item]:not([data-simply-list-icon]) td:first-child:before, - tr[data-simply-list-item] td:first-child:before { /* tr list item does not support icon override */ - content: "\f1b2"; /* cube */ - } - tr[data-simply-list-item]:before { - display: none; - } - *[data-simply-list-item][data-simply-list-icon]:not([data-simply-list-icon|="fa"]):before { - content: attr(data-simply-list-icon); - } - *[data-simply-list]:not(.simply-empty):before { - margin-left: 0px; - } - *[data-simply-list]:not(.simply-empty):not([data-simply-list-icon]):before { - content: "\f1b3"; /* cubes */ - } - *[data-simply-list][data-simply-list-icon]:not(.simply-empty):not([data-simply-list-icon|="fa"]):before { - content: attr(data-simply-list-icon); - } - *[data-simply-content='fixed']:before { - margin-left: 0px; - } - *[data-simply-content='fixed']:not([data-simply-list-icon]):before { - content: "\f148"; /* level-up */ - } - a[data-simply-content='fixed']:not([data-simply-list-icon]):before { - content: "\f0c1"; /* link */ - } - *[data-simply-content='fixed'][data-simply-list-icon]:not([data-simply-list-icon|="fa"]):before { - content: attr(data-simply-list-icon); - } - #simply-editor { - font-family: arial; - font-variant-caps: normal; - letter-spacing: initial; - text-transform: initial; - } - #simply-logo { - width: 60px; - -webkit-user-select: none; - -moz-user-select: none; - -ie-user-select: none; - user-select: none; - } - #simply-logo img { - display: inline-block; - position: absolute; - top: 16px; - left: 5px; - z-index: 10; - max-width: 50px; /* IE doesn't seem to like width on svg images */ - } - .simply-toolbar { - font-family: arial; - font-size: 11px; - color: #666; - background-color: white; - -webkit-border-radius: 0px 0px 3px 3px; - -moz-border-radius: 0px 0px 3px 3px; - border-radius: 0px 0px 3px 3px; - line-height: 0px; - position: relative; - border: 1px solid #aaa; - border-top: 5px solid #ea5922; - -webkit-box-shadow: 0px 0px 4px #CCC; - -moz-box-shadow: 0px 0px 4px #CCC; - box-shadow: 0px 0px 4px #CCC; - z-index: 1000; - -webkit-user-select: none; - -moz-user-select: none; - -ie-user-select: none; - user-select: none; - } - .simply-toolbar::after, .simply-toolbar > ul::after, .simply-toolbar-section > ul::after { - content: ""; - clear: both; - display: block; - } - .simply-toolbar .marker { - content: ""; - display: block; - position: absolute; - margin-top: -12px; - left: 50%; - margin-left: -12px; - width: 0; - border-bottom: 12px solid #ea5922; - border-top: 0px; - border-left: 12px solid transparent; - border-right: 12px solid transparent; - } - .simply-toolbar > ul { - background: linear-gradient(to bottom, white 0%, #FFF 95%, #DDD 100%); - min-width: 100%; - line-height: 0px; - } - .simply-toolbar > ul, - .simply-toolbar > ul > li, - .simply-toolbar-section > ul, - .simply-toolbar-section > ul > li { - margin: 0px; - padding: 0px; - border: 0px; - list-style: none; - white-space: nowrap; - } - .simply-toolbar-section > ul > li.simply-text-format { - margin-right: 4px; - } - .simply-toolbar li { - position: relative; - float: left; - } - #simply-main-toolbar .simply-toolbar { - min-height: 60px; - transform: translate3d(0,0,0); - } - #simply-main-toolbar .simply-buttons { - white-space: nowrap !important; - position: absolute; - } - #simply-main-toolbar .simply-toolbar li { - float: none; - display: inline-block; - } - - #vdTablePopup { - left: 40px; - top: 0px; - padding-bottom: 20px; - width: auto; - height: auto; - } - #vdTableText { - position: absolute; - bottom: 10px; - width: 100%; - } - #vdTablePreview table { - border-spacing: 2px; - border-collapse: separate; - width: 110px; - height: 110px; - } - - .simply-toolbar button { - border: 0px; - margin: 0px; - padding: 0px 2px; - background: transparent; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - position: relative; - min-width: 50px; - text-align: center; - height: 60px; - font-size: 11px; - color: #666 !important; - box-sizing: border-box; - font-weight: inherit; - letter-spacing: 0; - line-height: inherit; - text-transform: inherit; - font-family: inherit; - box-shadow: inherit; - border-radius: 0; - transition: inherit; - font-variant-caps: normal; - } - - @media (max-width: 480px) { - .simply-toolbar button { - min-width: 48px; - } - } - @media (max-width: 320px) { - .simply-toolbar button { - min-width: 40px; - } - } - #simply-main-toolbar button { - vertical-align: top; - } - .simply-toolbar button[disabled] { - opacity: 0.3; - } - .simply-toolbar button > i, - .simply-toolbar button > span.fa-stack { - line-height: 50px; - font-size: 19px; - display: inline-block; - padding: 0px 4px; - line-height: 38px; - display: block; - margin: -13px auto 0px; - position: relative; - } - .simply-toolbar button.simply-selected { - background-color: #EEE; - position: relative; - border-left: 1px solid #DDD; - border-right: 1px solid white; - } - .simply-toolbar button.simply-disabled { - opacity: 0.3; - } - - .simply-toolbar button:focus { - border-bottom: 2px solid orange !important; - } - .simply-toolbar label button:focus { - border-bottom: 0px !important; - } - button.simply-selected::first-child { - border-left: 0px; - } - button.simply-selected::last-child { - border-right: 0px; - } - - .simply-toolbar-section { - background-color: #EEE; - display: none; - clear: both; - } - section.simply-section.active { - opacity: 1; - z-index: 99999; - } - section.simply-section { - position: absolute; - opacity: 0; - -webkit-transition: opacity 0.2s ease-in-out; - -moz-transition: opacity 0.2s ease-in-out; - -ms-transition: opacity 0.2s ease-in-out; - -o-transition: opacity 0.2s ease-in-out; - transition: opacity 0.2s ease-in-out; - left: -10000px; /* position off screen initially */ - height: inherit; - } - .tagStack li { - padding-right: 5px; - } - .simply-toolbar-section ul { - background: linear-gradient(to bottom, #EEE 0%, #DDD 100%); - padding: 4px 2px; - } - .simply-toolbar-section.simply-selected { - display: block; - white-space: nowrap; - } - .simply-toolbar-section button { - height: 40px; - min-width: 23px; - border: 1px solid transparent; - line-height: 6px; - } - .simply-toolbar-section button > i, - .simply-toolbar-section button > span.fa-stack { - font-size: 14px; - line-height: 16px; - width: 23px; - margin: 0px auto 4px; - } - .simply-toolbar-section button.simply-selected { - background-color: #D7D7D7; - border: 1px solid #EEE; - border-left: 1px solid #888; - border-top: 1px solid #888; - border-radius: 2px; - } - section.simply-section { - margin-bottom: 150px; - } - section.simply-section h1 { - font-size: 16px; - font-weight: bold; - display: none; - } - button.simply-expands::after { - content: ""; - display: block; - position: absolute; - bottom: 6px; - left: 50%; - margin-left: -3px; - width: 0; - border-top: 3px solid #888; - border-bottom: 0px; - border-left: 3px solid transparent; - border-right: 3px solid transparent; - opacity: 1; - transform: inherit; - -webkit-transform: inherit; - top: inherit; - height: 0; - } - button.simply-selected.simply-expands::after { - display: none; - } - .simply-toolbar-section > div { - padding-left: 80px; - } - - .simply-toolbar-section label { - width: 60px; - font-size: 12px; - display: inline-block; - font-weight: normal; - padding-left: 10px; - margin: inherit; - margin-left: -80px; - color: inherit; - } - .simply-toolbar-section input, - .simply-toolbar-section select { - background-color: white; - color: black; - margin-top: 3px; - margin-bottom: 3px; - border: 1px solid #888; - border-bottom-color: #EEE; - border-right-color: #EEE; - border-radius: 2px; - line-height: 22px; - min-height: 22px; - width: 100%; - font-family: inherit; - font-size: inherit; - display: inline-block; - box-sizing: border-box !important; - padding: 2px 0 !important; - margin: 3px 0 !important; - } - .simply-toolbar-section select { - padding: 4px 0px !important; - } - .simply-toolbar button:focus { - outline: none; - } - .simply-context-html { - padding-left: 8px; - background-color: #EEE; - background: linear-gradient(to bottom, #EEE 0%, #DDD 100%); - overflow: hidden; - } - .simply-context-html ul, - .simply-context-html li { - display: block; - float: left; - } - a.simply-context-tag { - color: black; - font-size: 11px; - line-height: 12px; - padding: 0px 2px; - margin: 2px 0px; - display: inline-block; - cursor: pointer; - } - a.simply-context-tag.simply-selected { - background-color: #CCC; - border: 1px solid #EEE; - border-left: 1px solid #888; - border-top: 1px solid #888; - border-radius: 2px; - } - .simply-context-html li:last-child a.simply-context-tag::after { - content: ""; - } - - /* larger style html context */ - a.simply-context-tag { - font-size: 12px; - line-height: 14px; - display: block; - float: left; - padding: 2px; - margin: 2px; - border: 1px solid #666; - border-radius: 2px; - color: black; - background-color: #CCC; - } - a.simply-context-tag.simply-selected { - background-color: #FFFFCC; - } - .simply-float-right { - float: right; - } - .simply-toolbar button.simply-small > i, - .simply-toolbar button.simply-small > span.fa-stack { - line-height: 24px; - font-size: 14px; - margin: 0px; - } - .simply-toolbar button.simply-small { - height: auto; - width: auto; - min-width: 20px; - } - /* end */ - - li.simply-text-format { - line-height: 32px; - vertical-align: top; - width: 100%; - } - - li.simply-seperator label:before { - display: block; - position: absolute; - border-left: 1px solid #DDD; - border-right: 1px solid white; - height: 40px; - content: ""; - margin-top: -14px; - margin-left: -4px; - } - - label.simply-subsection { - text-align: center; - vertical-align: top; - line-height: 14px; - } - .simply-disabled { - color: #BBB; - } - #vdTextStyle { - height: auto; - width: auto; - overflow-x: inherit; - margin-left: auto; - padding: auto; - } - .simply-cell-width select, - .simply-cell-height select, - .simply-table-width select, - .simply-table-height select { - width: 40px; - } - button[data-simply-section=simply-clipboard], - .simply-clipboard { - display: none; - } - #editorPane, #vdMetaDataSlide { - -webkit-overflow-scrolling: touch !important; - } - /* simply dropdown list */ - .simply-list { - display: inline-block; - position: relative; - -webkit-user-select: none; - } - ul.simply-list-items { - position: absolute; - width: 100%; - min-width: 120px; - background-color: white; - box-sizing: border-box; - padding: 2px; - display: none; - margin: 0; - border: 1px solid #ccc; - } - .simply-list-items li { - list-style: none; - float: none; - padding: 2px 4px; - } - .simply-list-items input { - margin-right: 5px; - } - .simply-list-items label { - font-size: 13px; - line-height: 18px; - font-weight: normal; - display: block; - } - .simply-list.visible .simply-list-items { - display: block; - } - /* context menu */ - .simply-context-section { - position: absolute; - right: 20px; - top: 130px; - width: 210px; - height: 240px; - border: 1px solid #ccc; - box-shadow: 0px 0px 5px #888; - padding: 5px; - background: #F4F4F4; - display: none; - } - .simply-context-section.simply-selected { - display: block; - } - .simply-context-section .simply-close { - position: absolute; - top: -18px; - right: -18px; - width: 36px; - height: 36px; - background-image: url(' make_url(currentsite()); graphics/close.png'); - margin: 0px; - padding: 0px; - border: 0px; - min-width: 36px; - } - .simply-context-section iframe { - border: 0px; - margin: 0px; - padding: 0px; - width: 100%; - height: 100%; - } - .simply-context-section.simply-help { - top: 200px; - left: 50%; - width: 400px; - height: 250px; - margin-left: -200px; - } - -#simply-main-toolbar { - left: 0px !important; - opacity: 1 !important; - position: fixed; - margin-bottom: auto; - top: 0px; - right: 0px; - z-index: 100000; -} -#simply-main-toolbar .simply-toolbar { - position: static; -} -#simply-main-toolbar .simply-toolbar:before { - display: none; -} - -#simply-main-toolbar .simply-selected { - border: 0px; -} -#vdToolbars { - height: auto; - border: 0px; - margin-right: 0px; -} -#vdEditPane { - border: 0px; -} -#simply-main-toolbar .simply-buttons { - white-space: normal; -} -#simply-main-toolbar > .simply-toolbar > ul.simply-buttons > li.simply-seperator { - border-right: 1px solid #ddd; - height: 58px; - vertical-align: top; -} -#simply-main-toolbar i.simply-logo { - margin-bottom: 10px; - position: relative; - top: 4px; - width: 24px; - box-sizing: border-box; -} -.simply-hidden { - display: none !important; -} - -#simply-main-toolbar.simply-collapse .simply-toolbar .marker { - margin-top: -5px; - margin-left: 0px; - left: 0; - width: 0; - border-bottom: 0; - border-top: 25px solid #ea5922; - border-left: 0; - border-right: 25px solid transparent; -} -#simply-main-toolbar.simply-collapse .simply-toolbar { - border-top-color: transparent; -} - -#simply-main-toolbar.simply-collapse { - right: auto; -} -#simply-main-toolbar.simply-collapse li:nth-child(n+2) { - display: none; -} - - -/* Dialogs */ -.simply-dialog { - display: none; -} -.simply-dialog.active { - display: block; - border: 1px solid #aaa; - border-top: 5px solid #ea5922; - background-color: white; - font-family: arial, helvetica, sans-serif; - color: black; - padding: 0px; - position: fixed; - z-index: 100002; - box-shadow: 0px 0px 8px #444; -} - -.simply-dialog.simply-modal { - top: 50%; - height: 400px; - max-height: 80%; - margin-top: -200px; - - left: 50%; - width: 480px; - margin-left: -240px; - background-color: #EEE; -} -.simply-dialog.simply-modal.fullscreen { - top: 0px; - bottom: 0px; - left: 0px; - right: 0px; - max-width: 100%; - max-height: 100%; - height: auto; - width: auto; - margin-left: 0px; - margin-top: 0px; -} - - -@media (max-width: 641px) { - .simply-dialog, - .simply-dialog.simply-modal { - top: 0px; - bottom: 0px; - left: 0px; - right: 0px; - max-width: 100%; - max-height: 100%; - height: auto; - width: auto; - margin-left: 0px; - margin-top: 0px; - } - [data-simply-action="simply-dialog-fullscreen"] { - display: none; - } - .simply-dialog-body { - max-width: 100%; - } -} - -.simply-toolbar .simply-right { - float: right; -} -.simply-dialog .marker { - display: none; -} -.simply-dialog .simply-toolbar { - border: 0; - border-top: 1px solid #eee; - box-shadow: none; - width: 100%; -} - -.simply-dialog.simply-modal .simply-dialog-body { - overflow-y: scroll; - position: absolute; - top: 60px; - bottom: 0px; - padding: 11px 5px; - width: 100%; - box-sizing: border-box; -} -.simply-dialog-body:first-child { - top: 0px; -} -.simply-dialog-body:nth-child(2):last-child { - bottom: 0px; -} -.simply-dialog-body:nth-child(2):nth-last-child(2) { - bottom: 60px; -} - -.simply-dialog .simply-toolbar:first-child { - position: absolute; - top: 0px; -} -.simply-dialog .simply-toolbar:last-child { - position: absolute; - bottom: 0px; -} -.simply-dialog.simply-modal .simply-toolbar-section { - padding: 10px 5px; -} -.simply-empty[data-simply-list] { - min-height: 24px; - background-color: rgba(128,128,128,0.1); - outline: 2px dashed rgba(128,128,128,0.3); - text-align: center; -} -[data-simply-field]:not(input):not(textarea):not(img):empty { - min-height: 24px; - text-align: left; -} -.simply-empty[data-simply-list]:before, -[data-simply-field]:not(input):not(textarea):not(img):not([data-simply-list-item]):empty:before { - text-align: center; - font-family: FontAwesome; - font-size: 20px; - color: #888; - width: 100%; - line-height: 24px; - vertical-align: middle; - padding-top: 5px; - transition: 0.6s opacity ease; - opacity: 1; -} -.simply-empty[data-simply-list]:not([data-simply-list-icon]):before { - content: "\f1b3"; /* cubes */ -} -.simply-empty[data-simply-list][data-simply-list-icon]:not([data-simply-list-icon|="fa"]):before { - content: attr(data-simply-list-icon); -} -.simply-empty[data-simply-list]:after { - content: "(Empty list)"; - text-align: center; - font-family: arial; - font-size: 12px; - color: #888; - width: 100%; - line-height: 24px; - vertical-align: middle; - padding-bottom: 5px; - margin-left: 4px; -} -[data-simply-field]:not([data-simply-list-item]):empty:hover:before, -[data-simply-field]:not([data-simply-list-item]):empty:hover:after { - opacity: 0.3; -} - -[data-simply-field]:not(input):not(textarea):empty:not([data-simply-field-icon]):not([data-simply-list-item]):before { - content: "\f044"; /* pencil-square-o */ -} -[data-simply-field][data-simply-field-icon]:not(input):not(textarea):empty:not([data-simply-field-icon|="fa"]):not([data-simply-list-item]):before { - content: attr(data-simply-field-icon); -} -[data-simply-field]:not(input):not(textarea):empty:after { - content: "(Empty)"; - text-align: center; - font-family: arial; - font-size: 12px; - color: #888; - width: 100%; - line-height: 24px; - vertical-align: middle; - padding-bottom: 5px; - margin-left: 4px; - opacity: 1; - transition: 0.6s opacity ease; -} -body[data-simply-edit] [data-simply-collapsed] { - display: inline-block; -} -body[data-simply-edit] [data-simply-hope] { - min-height: 1.2em; - min-width: 1.2em; -} - -/* plain view */ -body.simply-plain [data-simply-field], -body.simply-plain [data-simply-list], -body.simply-plain [data-simply-list-item] { - display: block !important; - position: static !important; - vertical-align: top; - margin-left: 20px; -} -body.simply-plain [data-simply-field]:before { - content: "(Field) " attr(data-simply-field); -} -body.simply-plain [data-simply-list]:before { - content: "(List) " attr(data-simply-list); - position: static; - opacity: 1; -} -body.simply-plain [data-simply-list-item]:before, -body.simply-plain tr[data-simply-list-item] td:first-child:before { - content: "(List item) " attr(data-simply-template); - position: static; - opacity: 1; -} - -body.simply-plain [data-simply-list]:before, -body.simply-plain [data-simply-list-item]:before, -body.simply-plain tr[data-simply-list-item] td:first-child:before, -body.simply-plain [data-simply-field]:before { - border: 1px solid #999; - border-radius: 24px; - background-color: #eee; - color: #333; - display: inline-block; - width: auto; - margin: 5px; - padding: 5px; - font-size: 12px; - font-family: arial; - font-weight: normal; - font-style: normal; -} - -.simply-gadget { - position: relative; -} -.simply-gadget *[data-simply-list]:before { - display: none; -} -.simply-gadget > *:before, -.simply-gadget *[data-simply-list]:before { - display: block; - content: ""; - position: absolute; - top: 0; - bottom: 0; - left: 0; - right: 0; - z-index: 1000; - opacity: 0 !important; - border:0; - margin: 0; -} - -.simply-gadget *[data-simply-field] { - outline: 0; -} -.simply-gadget *[data-simply-list-item]:before { - display: none; -} -.simply-gadget *[data-simply-field]:hover { - outline: 0; -} -.simply-gadget[data-simply-selectable] { - outline: 2px dashed rgba(128,128,128,0.3); -} - - -/* Font awesome icons mapping */ -[data-simply-list-icon="fa-glass"]:before{content:"\f000"} -[data-simply-list-icon="fa-music"]:before{content:"\f001"} -[data-simply-list-icon="fa-search"]:before{content:"\f002"} -[data-simply-list-icon="fa-envelope-o"]:before{content:"\f003"} -[data-simply-list-icon="fa-heart"]:before{content:"\f004"} -[data-simply-list-icon="fa-star"]:before{content:"\f005"} -[data-simply-list-icon="fa-star-o"]:before{content:"\f006"} -[data-simply-list-icon="fa-user"]:before{content:"\f007"} -[data-simply-list-icon="fa-film"]:before{content:"\f008"} -[data-simply-list-icon="fa-th-large"]:before{content:"\f009"} -[data-simply-list-icon="fa-th"]:before{content:"\f00a"} -[data-simply-list-icon="fa-th-list"]:before{content:"\f00b"} -[data-simply-list-icon="fa-check"]:before{content:"\f00c"} -[data-simply-list-icon="fa-remove"]:before, -[data-simply-list-icon="fa-close"]:before, -[data-simply-list-icon="fa-times"]:before{content:"\f00d"} -[data-simply-list-icon="fa-search-plus"]:before{content:"\f00e"} -[data-simply-list-icon="fa-search-minus"]:before{content:"\f010"} -[data-simply-list-icon="fa-power-off"]:before{content:"\f011"} -[data-simply-list-icon="fa-signal"]:before{content:"\f012"} -[data-simply-list-icon="fa-gear"]:before, -[data-simply-list-icon="fa-cog"]:before{content:"\f013"} -[data-simply-list-icon="fa-trash-o"]:before{content:"\f014"} -[data-simply-list-icon="fa-home"]:before{content:"\f015"} -[data-simply-list-icon="fa-file-o"]:before{content:"\f016"} -[data-simply-list-icon="fa-clock-o"]:before{content:"\f017"} -[data-simply-list-icon="fa-road"]:before{content:"\f018"} -[data-simply-list-icon="fa-download"]:before{content:"\f019"} -[data-simply-list-icon="fa-arrow-circle-o-down"]:before{content:"\f01a"} -[data-simply-list-icon="fa-arrow-circle-o-up"]:before{content:"\f01b"} -[data-simply-list-icon="fa-inbox"]:before{content:"\f01c"} -[data-simply-list-icon="fa-play-circle-o"]:before{content:"\f01d"} -[data-simply-list-icon="fa-rotate-right"]:before, -[data-simply-list-icon="fa-repeat"]:before{content:"\f01e"} -[data-simply-list-icon="fa-refresh"]:before{content:"\f021"} -[data-simply-list-icon="fa-list-alt"]:before{content:"\f022"} -[data-simply-list-icon="fa-lock"]:before{content:"\f023"} -[data-simply-list-icon="fa-flag"]:before{content:"\f024"} -[data-simply-list-icon="fa-headphones"]:before{content:"\f025"} -[data-simply-list-icon="fa-volume-off"]:before{content:"\f026"} -[data-simply-list-icon="fa-volume-down"]:before{content:"\f027"} -[data-simply-list-icon="fa-volume-up"]:before{content:"\f028"} -[data-simply-list-icon="fa-qrcode"]:before{content:"\f029"} -[data-simply-list-icon="fa-barcode"]:before{content:"\f02a"} -[data-simply-list-icon="fa-tag"]:before{content:"\f02b"} -[data-simply-list-icon="fa-tags"]:before{content:"\f02c"} -[data-simply-list-icon="fa-book"]:before{content:"\f02d"} -[data-simply-list-icon="fa-bookmark"]:before{content:"\f02e"} -[data-simply-list-icon="fa-print"]:before{content:"\f02f"} -[data-simply-list-icon="fa-camera"]:before{content:"\f030"} -[data-simply-list-icon="fa-font"]:before{content:"\f031"} -[data-simply-list-icon="fa-bold"]:before{content:"\f032"} -[data-simply-list-icon="fa-italic"]:before{content:"\f033"} -[data-simply-list-icon="fa-text-height"]:before{content:"\f034"} -[data-simply-list-icon="fa-text-width"]:before{content:"\f035"} -[data-simply-list-icon="fa-align-left"]:before{content:"\f036"} -[data-simply-list-icon="fa-align-center"]:before{content:"\f037"} -[data-simply-list-icon="fa-align-right"]:before{content:"\f038"} -[data-simply-list-icon="fa-align-justify"]:before{content:"\f039"} -[data-simply-list-icon="fa-list"]:before{content:"\f03a"} -[data-simply-list-icon="fa-dedent"]:before, -[data-simply-list-icon="fa-outdent"]:before{content:"\f03b"} -[data-simply-list-icon="fa-indent"]:before{content:"\f03c"} -[data-simply-list-icon="fa-video-camera"]:before{content:"\f03d"} -[data-simply-list-icon="fa-photo"]:before, -[data-simply-list-icon="fa-image"]:before, -[data-simply-list-icon="fa-picture-o"]:before{content:"\f03e"} -[data-simply-list-icon="fa-pencil"]:before{content:"\f040"} -[data-simply-list-icon="fa-map-marker"]:before{content:"\f041"} -[data-simply-list-icon="fa-adjust"]:before{content:"\f042"} -[data-simply-list-icon="fa-tint"]:before{content:"\f043"} -[data-simply-list-icon="fa-edit"]:before, -[data-simply-list-icon="fa-pencil-square-o"]:before{content:"\f044"} -[data-simply-list-icon="fa-share-square-o"]:before{content:"\f045"} -[data-simply-list-icon="fa-check-square-o"]:before{content:"\f046"} -[data-simply-list-icon="fa-arrows"]:before{content:"\f047"} -[data-simply-list-icon="fa-step-backward"]:before{content:"\f048"} -[data-simply-list-icon="fa-fast-backward"]:before{content:"\f049"} -[data-simply-list-icon="fa-backward"]:before{content:"\f04a"} -[data-simply-list-icon="fa-play"]:before{content:"\f04b"} -[data-simply-list-icon="fa-pause"]:before{content:"\f04c"} -[data-simply-list-icon="fa-stop"]:before{content:"\f04d"} -[data-simply-list-icon="fa-forward"]:before{content:"\f04e"} -[data-simply-list-icon="fa-fast-forward"]:before{content:"\f050"} -[data-simply-list-icon="fa-step-forward"]:before{content:"\f051"} -[data-simply-list-icon="fa-eject"]:before{content:"\f052"} -[data-simply-list-icon="fa-chevron-left"]:before{content:"\f053"} -[data-simply-list-icon="fa-chevron-right"]:before{content:"\f054"} -[data-simply-list-icon="fa-plus-circle"]:before{content:"\f055"} -[data-simply-list-icon="fa-minus-circle"]:before{content:"\f056"} -[data-simply-list-icon="fa-times-circle"]:before{content:"\f057"} -[data-simply-list-icon="fa-check-circle"]:before{content:"\f058"} -[data-simply-list-icon="fa-question-circle"]:before{content:"\f059"} -[data-simply-list-icon="fa-info-circle"]:before{content:"\f05a"} -[data-simply-list-icon="fa-crosshairs"]:before{content:"\f05b"} -[data-simply-list-icon="fa-times-circle-o"]:before{content:"\f05c"} -[data-simply-list-icon="fa-check-circle-o"]:before{content:"\f05d"} -[data-simply-list-icon="fa-ban"]:before{content:"\f05e"} -[data-simply-list-icon="fa-arrow-left"]:before{content:"\f060"} -[data-simply-list-icon="fa-arrow-right"]:before{content:"\f061"} -[data-simply-list-icon="fa-arrow-up"]:before{content:"\f062"} -[data-simply-list-icon="fa-arrow-down"]:before{content:"\f063"} -[data-simply-list-icon="fa-mail-forward"]:before, -[data-simply-list-icon="fa-share"]:before{content:"\f064"} -[data-simply-list-icon="fa-expand"]:before{content:"\f065"} -[data-simply-list-icon="fa-compress"]:before{content:"\f066"} -[data-simply-list-icon="fa-plus"]:before{content:"\f067"} -[data-simply-list-icon="fa-minus"]:before{content:"\f068"} -[data-simply-list-icon="fa-asterisk"]:before{content:"\f069"} -[data-simply-list-icon="fa-exclamation-circle"]:before{content:"\f06a"} -[data-simply-list-icon="fa-gift"]:before{content:"\f06b"} -[data-simply-list-icon="fa-leaf"]:before{content:"\f06c"} -[data-simply-list-icon="fa-fire"]:before{content:"\f06d"} -[data-simply-list-icon="fa-eye"]:before{content:"\f06e"} -[data-simply-list-icon="fa-eye-slash"]:before{content:"\f070"} -[data-simply-list-icon="fa-warning"]:before, -[data-simply-list-icon="fa-exclamation-triangle"]:before{content:"\f071"} -[data-simply-list-icon="fa-plane"]:before{content:"\f072"} -[data-simply-list-icon="fa-calendar"]:before{content:"\f073"} -[data-simply-list-icon="fa-random"]:before{content:"\f074"} -[data-simply-list-icon="fa-comment"]:before{content:"\f075"} -[data-simply-list-icon="fa-magnet"]:before{content:"\f076"} -[data-simply-list-icon="fa-chevron-up"]:before{content:"\f077"} -[data-simply-list-icon="fa-chevron-down"]:before{content:"\f078"} -[data-simply-list-icon="fa-retweet"]:before{content:"\f079"} -[data-simply-list-icon="fa-shopping-cart"]:before{content:"\f07a"} -[data-simply-list-icon="fa-folder"]:before{content:"\f07b"} -[data-simply-list-icon="fa-folder-open"]:before{content:"\f07c"} -[data-simply-list-icon="fa-arrows-v"]:before{content:"\f07d"} -[data-simply-list-icon="fa-arrows-h"]:before{content:"\f07e"} -[data-simply-list-icon="fa-bar-chart-o"]:before, -[data-simply-list-icon="fa-bar-chart"]:before{content:"\f080"} -[data-simply-list-icon="fa-twitter-square"]:before{content:"\f081"} -[data-simply-list-icon="fa-facebook-square"]:before{content:"\f082"} -[data-simply-list-icon="fa-camera-retro"]:before{content:"\f083"} -[data-simply-list-icon="fa-key"]:before{content:"\f084"} -[data-simply-list-icon="fa-gears"]:before, -[data-simply-list-icon="fa-cogs"]:before{content:"\f085"} -[data-simply-list-icon="fa-comments"]:before{content:"\f086"} -[data-simply-list-icon="fa-thumbs-o-up"]:before{content:"\f087"} -[data-simply-list-icon="fa-thumbs-o-down"]:before{content:"\f088"} -[data-simply-list-icon="fa-star-half"]:before{content:"\f089"} -[data-simply-list-icon="fa-heart-o"]:before{content:"\f08a"} -[data-simply-list-icon="fa-sign-out"]:before{content:"\f08b"} -[data-simply-list-icon="fa-linkedin-square"]:before{content:"\f08c"} -[data-simply-list-icon="fa-thumb-tack"]:before{content:"\f08d"} -[data-simply-list-icon="fa-external-link"]:before{content:"\f08e"} -[data-simply-list-icon="fa-sign-in"]:before{content:"\f090"} -[data-simply-list-icon="fa-trophy"]:before{content:"\f091"} -[data-simply-list-icon="fa-github-square"]:before{content:"\f092"} -[data-simply-list-icon="fa-upload"]:before{content:"\f093"} -[data-simply-list-icon="fa-lemon-o"]:before{content:"\f094"} -[data-simply-list-icon="fa-phone"]:before{content:"\f095"} -[data-simply-list-icon="fa-square-o"]:before{content:"\f096"} -[data-simply-list-icon="fa-bookmark-o"]:before{content:"\f097"} -[data-simply-list-icon="fa-phone-square"]:before{content:"\f098"} -[data-simply-list-icon="fa-twitter"]:before{content:"\f099"} -[data-simply-list-icon="fa-facebook-f"]:before, -[data-simply-list-icon="fa-facebook"]:before{content:"\f09a"} -[data-simply-list-icon="fa-github"]:before{content:"\f09b"} -[data-simply-list-icon="fa-unlock"]:before{content:"\f09c"} -[data-simply-list-icon="fa-credit-card"]:before{content:"\f09d"} -[data-simply-list-icon="fa-feed"]:before, -[data-simply-list-icon="fa-rss"]:before{content:"\f09e"} -[data-simply-list-icon="fa-hdd-o"]:before{content:"\f0a0"} -[data-simply-list-icon="fa-bullhorn"]:before{content:"\f0a1"} -[data-simply-list-icon="fa-bell"]:before{content:"\f0f3"} -[data-simply-list-icon="fa-certificate"]:before{content:"\f0a3"} -[data-simply-list-icon="fa-hand-o-right"]:before{content:"\f0a4"} -[data-simply-list-icon="fa-hand-o-left"]:before{content:"\f0a5"} -[data-simply-list-icon="fa-hand-o-up"]:before{content:"\f0a6"} -[data-simply-list-icon="fa-hand-o-down"]:before{content:"\f0a7"} -[data-simply-list-icon="fa-arrow-circle-left"]:before{content:"\f0a8"} -[data-simply-list-icon="fa-arrow-circle-right"]:before{content:"\f0a9"} -[data-simply-list-icon="fa-arrow-circle-up"]:before{content:"\f0aa"} -[data-simply-list-icon="fa-arrow-circle-down"]:before{content:"\f0ab"} -[data-simply-list-icon="fa-globe"]:before{content:"\f0ac"} -[data-simply-list-icon="fa-wrench"]:before{content:"\f0ad"} -[data-simply-list-icon="fa-tasks"]:before{content:"\f0ae"} -[data-simply-list-icon="fa-filter"]:before{content:"\f0b0"} -[data-simply-list-icon="fa-briefcase"]:before{content:"\f0b1"} -[data-simply-list-icon="fa-arrows-alt"]:before{content:"\f0b2"} -[data-simply-list-icon="fa-group"]:before, -[data-simply-list-icon="fa-users"]:before{content:"\f0c0"} -[data-simply-list-icon="fa-chain"]:before, -[data-simply-list-icon="fa-link"]:before{content:"\f0c1"} -[data-simply-list-icon="fa-cloud"]:before{content:"\f0c2"} -[data-simply-list-icon="fa-flask"]:before{content:"\f0c3"} -[data-simply-list-icon="fa-cut"]:before, -[data-simply-list-icon="fa-scissors"]:before{content:"\f0c4"} -[data-simply-list-icon="fa-copy"]:before, -[data-simply-list-icon="fa-files-o"]:before{content:"\f0c5"} -[data-simply-list-icon="fa-paperclip"]:before{content:"\f0c6"} -[data-simply-list-icon="fa-save"]:before, -[data-simply-list-icon="fa-floppy-o"]:before{content:"\f0c7"} -[data-simply-list-icon="fa-square"]:before{content:"\f0c8"} -[data-simply-list-icon="fa-navicon"]:before, -[data-simply-list-icon="fa-reorder"]:before, -[data-simply-list-icon="fa-bars"]:before{content:"\f0c9"} -[data-simply-list-icon="fa-list-ul"]:before{content:"\f0ca"} -[data-simply-list-icon="fa-list-ol"]:before{content:"\f0cb"} -[data-simply-list-icon="fa-strikethrough"]:before{content:"\f0cc"} -[data-simply-list-icon="fa-underline"]:before{content:"\f0cd"} -[data-simply-list-icon="fa-table"]:before{content:"\f0ce"} -[data-simply-list-icon="fa-magic"]:before{content:"\f0d0"} -[data-simply-list-icon="fa-truck"]:before{content:"\f0d1"} -[data-simply-list-icon="fa-pinterest"]:before{content:"\f0d2"} -[data-simply-list-icon="fa-pinterest-square"]:before{content:"\f0d3"} -[data-simply-list-icon="fa-google-plus-square"]:before{content:"\f0d4"} -[data-simply-list-icon="fa-google-plus"]:before{content:"\f0d5"} -[data-simply-list-icon="fa-money"]:before{content:"\f0d6"} -[data-simply-list-icon="fa-caret-down"]:before{content:"\f0d7"} -[data-simply-list-icon="fa-caret-up"]:before{content:"\f0d8"} -[data-simply-list-icon="fa-caret-left"]:before{content:"\f0d9"} -[data-simply-list-icon="fa-caret-right"]:before{content:"\f0da"} -[data-simply-list-icon="fa-columns"]:before{content:"\f0db"} -[data-simply-list-icon="fa-unsorted"]:before, -[data-simply-list-icon="fa-sort"]:before{content:"\f0dc"} -[data-simply-list-icon="fa-sort-down"]:before, -[data-simply-list-icon="fa-sort-desc"]:before{content:"\f0dd"} -[data-simply-list-icon="fa-sort-up"]:before, -[data-simply-list-icon="fa-sort-asc"]:before{content:"\f0de"} -[data-simply-list-icon="fa-envelope"]:before{content:"\f0e0"} -[data-simply-list-icon="fa-linkedin"]:before{content:"\f0e1"} -[data-simply-list-icon="fa-rotate-left"]:before, -[data-simply-list-icon="fa-undo"]:before{content:"\f0e2"} -[data-simply-list-icon="fa-legal"]:before, -[data-simply-list-icon="fa-gavel"]:before{content:"\f0e3"} -[data-simply-list-icon="fa-dashboard"]:before, -[data-simply-list-icon="fa-tachometer"]:before{content:"\f0e4"} -[data-simply-list-icon="fa-comment-o"]:before{content:"\f0e5"} -[data-simply-list-icon="fa-comments-o"]:before{content:"\f0e6"} -[data-simply-list-icon="fa-flash"]:before, -[data-simply-list-icon="fa-bolt"]:before{content:"\f0e7"} -[data-simply-list-icon="fa-sitemap"]:before{content:"\f0e8"} -[data-simply-list-icon="fa-umbrella"]:before{content:"\f0e9"} -[data-simply-list-icon="fa-paste"]:before, -[data-simply-list-icon="fa-clipboard"]:before{content:"\f0ea"} -[data-simply-list-icon="fa-lightbulb-o"]:before{content:"\f0eb"} -[data-simply-list-icon="fa-exchange"]:before{content:"\f0ec"} -[data-simply-list-icon="fa-cloud-download"]:before{content:"\f0ed"} -[data-simply-list-icon="fa-cloud-upload"]:before{content:"\f0ee"} -[data-simply-list-icon="fa-user-md"]:before{content:"\f0f0"} -[data-simply-list-icon="fa-stethoscope"]:before{content:"\f0f1"} -[data-simply-list-icon="fa-suitcase"]:before{content:"\f0f2"} -[data-simply-list-icon="fa-bell-o"]:before{content:"\f0a2"} -[data-simply-list-icon="fa-coffee"]:before{content:"\f0f4"} -[data-simply-list-icon="fa-cutlery"]:before{content:"\f0f5"} -[data-simply-list-icon="fa-file-text-o"]:before{content:"\f0f6"} -[data-simply-list-icon="fa-building-o"]:before{content:"\f0f7"} -[data-simply-list-icon="fa-hospital-o"]:before{content:"\f0f8"} -[data-simply-list-icon="fa-ambulance"]:before{content:"\f0f9"} -[data-simply-list-icon="fa-medkit"]:before{content:"\f0fa"} -[data-simply-list-icon="fa-fighter-jet"]:before{content:"\f0fb"} -[data-simply-list-icon="fa-beer"]:before{content:"\f0fc"} -[data-simply-list-icon="fa-h-square"]:before{content:"\f0fd"} -[data-simply-list-icon="fa-plus-square"]:before{content:"\f0fe"} -[data-simply-list-icon="fa-angle-double-left"]:before{content:"\f100"} -[data-simply-list-icon="fa-angle-double-right"]:before{content:"\f101"} -[data-simply-list-icon="fa-angle-double-up"]:before{content:"\f102"} -[data-simply-list-icon="fa-angle-double-down"]:before{content:"\f103"} -[data-simply-list-icon="fa-angle-left"]:before{content:"\f104"} -[data-simply-list-icon="fa-angle-right"]:before{content:"\f105"} -[data-simply-list-icon="fa-angle-up"]:before{content:"\f106"} -[data-simply-list-icon="fa-angle-down"]:before{content:"\f107"} -[data-simply-list-icon="fa-desktop"]:before{content:"\f108"} -[data-simply-list-icon="fa-laptop"]:before{content:"\f109"} -[data-simply-list-icon="fa-tablet"]:before{content:"\f10a"} -[data-simply-list-icon="fa-mobile-phone"]:before, -[data-simply-list-icon="fa-mobile"]:before{content:"\f10b"} -[data-simply-list-icon="fa-circle-o"]:before{content:"\f10c"} -[data-simply-list-icon="fa-quote-left"]:before{content:"\f10d"} -[data-simply-list-icon="fa-quote-right"]:before{content:"\f10e"} -[data-simply-list-icon="fa-spinner"]:before{content:"\f110"} -[data-simply-list-icon="fa-circle"]:before{content:"\f111"} -[data-simply-list-icon="fa-mail-reply"]:before, -[data-simply-list-icon="fa-reply"]:before{content:"\f112"} -[data-simply-list-icon="fa-github-alt"]:before{content:"\f113"} -[data-simply-list-icon="fa-folder-o"]:before{content:"\f114"} -[data-simply-list-icon="fa-folder-open-o"]:before{content:"\f115"} -[data-simply-list-icon="fa-smile-o"]:before{content:"\f118"} -[data-simply-list-icon="fa-frown-o"]:before{content:"\f119"} -[data-simply-list-icon="fa-meh-o"]:before{content:"\f11a"} -[data-simply-list-icon="fa-gamepad"]:before{content:"\f11b"} -[data-simply-list-icon="fa-keyboard-o"]:before{content:"\f11c"} -[data-simply-list-icon="fa-flag-o"]:before{content:"\f11d"} -[data-simply-list-icon="fa-flag-checkered"]:before{content:"\f11e"} -[data-simply-list-icon="fa-terminal"]:before{content:"\f120"} -[data-simply-list-icon="fa-code"]:before{content:"\f121"} -[data-simply-list-icon="fa-mail-reply-all"]:before, -[data-simply-list-icon="fa-reply-all"]:before{content:"\f122"} -[data-simply-list-icon="fa-star-half-empty"]:before, -[data-simply-list-icon="fa-star-half-full"]:before, -[data-simply-list-icon="fa-star-half-o"]:before{content:"\f123"} -[data-simply-list-icon="fa-location-arrow"]:before{content:"\f124"} -[data-simply-list-icon="fa-crop"]:before{content:"\f125"} -[data-simply-list-icon="fa-code-fork"]:before{content:"\f126"} -[data-simply-list-icon="fa-unlink"]:before, -[data-simply-list-icon="fa-chain-broken"]:before{content:"\f127"} -[data-simply-list-icon="fa-question"]:before{content:"\f128"} -[data-simply-list-icon="fa-info"]:before{content:"\f129"} -[data-simply-list-icon="fa-exclamation"]:before{content:"\f12a"} -[data-simply-list-icon="fa-superscript"]:before{content:"\f12b"} -[data-simply-list-icon="fa-subscript"]:before{content:"\f12c"} -[data-simply-list-icon="fa-eraser"]:before{content:"\f12d"} -[data-simply-list-icon="fa-puzzle-piece"]:before{content:"\f12e"} -[data-simply-list-icon="fa-microphone"]:before{content:"\f130"} -[data-simply-list-icon="fa-microphone-slash"]:before{content:"\f131"} -[data-simply-list-icon="fa-shield"]:before{content:"\f132"} -[data-simply-list-icon="fa-calendar-o"]:before{content:"\f133"} -[data-simply-list-icon="fa-fire-extinguisher"]:before{content:"\f134"} -[data-simply-list-icon="fa-rocket"]:before{content:"\f135"} -[data-simply-list-icon="fa-maxcdn"]:before{content:"\f136"} -[data-simply-list-icon="fa-chevron-circle-left"]:before{content:"\f137"} -[data-simply-list-icon="fa-chevron-circle-right"]:before{content:"\f138"} -[data-simply-list-icon="fa-chevron-circle-up"]:before{content:"\f139"} -[data-simply-list-icon="fa-chevron-circle-down"]:before{content:"\f13a"} -[data-simply-list-icon="fa-html5"]:before{content:"\f13b"} -[data-simply-list-icon="fa-css3"]:before{content:"\f13c"} -[data-simply-list-icon="fa-anchor"]:before{content:"\f13d"} -[data-simply-list-icon="fa-unlock-alt"]:before{content:"\f13e"} -[data-simply-list-icon="fa-bullseye"]:before{content:"\f140"} -[data-simply-list-icon="fa-ellipsis-h"]:before{content:"\f141"} -[data-simply-list-icon="fa-ellipsis-v"]:before{content:"\f142"} -[data-simply-list-icon="fa-rss-square"]:before{content:"\f143"} -[data-simply-list-icon="fa-play-circle"]:before{content:"\f144"} -[data-simply-list-icon="fa-ticket"]:before{content:"\f145"} -[data-simply-list-icon="fa-minus-square"]:before{content:"\f146"} -[data-simply-list-icon="fa-minus-square-o"]:before{content:"\f147"} -[data-simply-list-icon="fa-level-up"]:before{content:"\f148"} -[data-simply-list-icon="fa-level-down"]:before{content:"\f149"} -[data-simply-list-icon="fa-check-square"]:before{content:"\f14a"} -[data-simply-list-icon="fa-pencil-square"]:before{content:"\f14b"} -[data-simply-list-icon="fa-external-link-square"]:before{content:"\f14c"} -[data-simply-list-icon="fa-share-square"]:before{content:"\f14d"} -[data-simply-list-icon="fa-compass"]:before{content:"\f14e"} -[data-simply-list-icon="fa-toggle-down"]:before, -[data-simply-list-icon="fa-caret-square-o-down"]:before{content:"\f150"} -[data-simply-list-icon="fa-toggle-up"]:before, -[data-simply-list-icon="fa-caret-square-o-up"]:before{content:"\f151"} -[data-simply-list-icon="fa-toggle-right"]:before, -[data-simply-list-icon="fa-caret-square-o-right"]:before{content:"\f152"} -[data-simply-list-icon="fa-euro"]:before, -[data-simply-list-icon="fa-eur"]:before{content:"\f153"} -[data-simply-list-icon="fa-gbp"]:before{content:"\f154"} -[data-simply-list-icon="fa-dollar"]:before, -[data-simply-list-icon="fa-usd"]:before{content:"\f155"} -[data-simply-list-icon="fa-rupee"]:before, -[data-simply-list-icon="fa-inr"]:before{content:"\f156"} -[data-simply-list-icon="fa-cny"]:before, -[data-simply-list-icon="fa-rmb"]:before, -[data-simply-list-icon="fa-yen"]:before, -[data-simply-list-icon="fa-jpy"]:before{content:"\f157"} -[data-simply-list-icon="fa-ruble"]:before, -[data-simply-list-icon="fa-rouble"]:before, -[data-simply-list-icon="fa-rub"]:before{content:"\f158"} -[data-simply-list-icon="fa-won"]:before, -[data-simply-list-icon="fa-krw"]:before{content:"\f159"} -[data-simply-list-icon="fa-bitcoin"]:before, -[data-simply-list-icon="fa-btc"]:before{content:"\f15a"} -[data-simply-list-icon="fa-file"]:before{content:"\f15b"} -[data-simply-list-icon="fa-file-text"]:before{content:"\f15c"} -[data-simply-list-icon="fa-sort-alpha-asc"]:before{content:"\f15d"} -[data-simply-list-icon="fa-sort-alpha-desc"]:before{content:"\f15e"} -[data-simply-list-icon="fa-sort-amount-asc"]:before{content:"\f160"} -[data-simply-list-icon="fa-sort-amount-desc"]:before{content:"\f161"} -[data-simply-list-icon="fa-sort-numeric-asc"]:before{content:"\f162"} -[data-simply-list-icon="fa-sort-numeric-desc"]:before{content:"\f163"} -[data-simply-list-icon="fa-thumbs-up"]:before{content:"\f164"} -[data-simply-list-icon="fa-thumbs-down"]:before{content:"\f165"} -[data-simply-list-icon="fa-youtube-square"]:before{content:"\f166"} -[data-simply-list-icon="fa-youtube"]:before{content:"\f167"} -[data-simply-list-icon="fa-xing"]:before{content:"\f168"} -[data-simply-list-icon="fa-xing-square"]:before{content:"\f169"} -[data-simply-list-icon="fa-youtube-play"]:before{content:"\f16a"} -[data-simply-list-icon="fa-dropbox"]:before{content:"\f16b"} -[data-simply-list-icon="fa-stack-overflow"]:before{content:"\f16c"} -[data-simply-list-icon="fa-instagram"]:before{content:"\f16d"} -[data-simply-list-icon="fa-flickr"]:before{content:"\f16e"} -[data-simply-list-icon="fa-adn"]:before{content:"\f170"} -[data-simply-list-icon="fa-bitbucket"]:before{content:"\f171"} -[data-simply-list-icon="fa-bitbucket-square"]:before{content:"\f172"} -[data-simply-list-icon="fa-tumblr"]:before{content:"\f173"} -[data-simply-list-icon="fa-tumblr-square"]:before{content:"\f174"} -[data-simply-list-icon="fa-long-arrow-down"]:before{content:"\f175"} -[data-simply-list-icon="fa-long-arrow-up"]:before{content:"\f176"} -[data-simply-list-icon="fa-long-arrow-left"]:before{content:"\f177"} -[data-simply-list-icon="fa-long-arrow-right"]:before{content:"\f178"} -[data-simply-list-icon="fa-apple"]:before{content:"\f179"} -[data-simply-list-icon="fa-windows"]:before{content:"\f17a"} -[data-simply-list-icon="fa-android"]:before{content:"\f17b"} -[data-simply-list-icon="fa-linux"]:before{content:"\f17c"} -[data-simply-list-icon="fa-dribbble"]:before{content:"\f17d"} -[data-simply-list-icon="fa-skype"]:before{content:"\f17e"} -[data-simply-list-icon="fa-foursquare"]:before{content:"\f180"} -[data-simply-list-icon="fa-trello"]:before{content:"\f181"} -[data-simply-list-icon="fa-female"]:before{content:"\f182"} -[data-simply-list-icon="fa-male"]:before{content:"\f183"} -[data-simply-list-icon="fa-gittip"]:before, -[data-simply-list-icon="fa-gratipay"]:before{content:"\f184"} -[data-simply-list-icon="fa-sun-o"]:before{content:"\f185"} -[data-simply-list-icon="fa-moon-o"]:before{content:"\f186"} -[data-simply-list-icon="fa-archive"]:before{content:"\f187"} -[data-simply-list-icon="fa-bug"]:before{content:"\f188"} -[data-simply-list-icon="fa-vk"]:before{content:"\f189"} -[data-simply-list-icon="fa-weibo"]:before{content:"\f18a"} -[data-simply-list-icon="fa-renren"]:before{content:"\f18b"} -[data-simply-list-icon="fa-pagelines"]:before{content:"\f18c"} -[data-simply-list-icon="fa-stack-exchange"]:before{content:"\f18d"} -[data-simply-list-icon="fa-arrow-circle-o-right"]:before{content:"\f18e"} -[data-simply-list-icon="fa-arrow-circle-o-left"]:before{content:"\f190"} -[data-simply-list-icon="fa-toggle-left"]:before, -[data-simply-list-icon="fa-caret-square-o-left"]:before{content:"\f191"} -[data-simply-list-icon="fa-dot-circle-o"]:before{content:"\f192"} -[data-simply-list-icon="fa-wheelchair"]:before{content:"\f193"} -[data-simply-list-icon="fa-vimeo-square"]:before{content:"\f194"} -[data-simply-list-icon="fa-turkish-lira"]:before, -[data-simply-list-icon="fa-try"]:before{content:"\f195"} -[data-simply-list-icon="fa-plus-square-o"]:before{content:"\f196"} -[data-simply-list-icon="fa-space-shuttle"]:before{content:"\f197"} -[data-simply-list-icon="fa-slack"]:before{content:"\f198"} -[data-simply-list-icon="fa-envelope-square"]:before{content:"\f199"} -[data-simply-list-icon="fa-wordpress"]:before{content:"\f19a"} -[data-simply-list-icon="fa-openid"]:before{content:"\f19b"} -[data-simply-list-icon="fa-institution"]:before, -[data-simply-list-icon="fa-bank"]:before, -[data-simply-list-icon="fa-university"]:before{content:"\f19c"} -[data-simply-list-icon="fa-mortar-board"]:before, -[data-simply-list-icon="fa-graduation-cap"]:before{content:"\f19d"} -[data-simply-list-icon="fa-yahoo"]:before{content:"\f19e"} -[data-simply-list-icon="fa-google"]:before{content:"\f1a0"} -[data-simply-list-icon="fa-reddit"]:before{content:"\f1a1"} -[data-simply-list-icon="fa-reddit-square"]:before{content:"\f1a2"} -[data-simply-list-icon="fa-stumbleupon-circle"]:before{content:"\f1a3"} -[data-simply-list-icon="fa-stumbleupon"]:before{content:"\f1a4"} -[data-simply-list-icon="fa-delicious"]:before{content:"\f1a5"} -[data-simply-list-icon="fa-digg"]:before{content:"\f1a6"} -[data-simply-list-icon="fa-pied-piper"]:before{content:"\f1a7"} -[data-simply-list-icon="fa-pied-piper-alt"]:before{content:"\f1a8"} -[data-simply-list-icon="fa-drupal"]:before{content:"\f1a9"} -[data-simply-list-icon="fa-joomla"]:before{content:"\f1aa"} -[data-simply-list-icon="fa-language"]:before{content:"\f1ab"} -[data-simply-list-icon="fa-fax"]:before{content:"\f1ac"} -[data-simply-list-icon="fa-building"]:before{content:"\f1ad"} -[data-simply-list-icon="fa-child"]:before{content:"\f1ae"} -[data-simply-list-icon="fa-paw"]:before{content:"\f1b0"} -[data-simply-list-icon="fa-spoon"]:before{content:"\f1b1"} -[data-simply-list-icon="fa-cube"]:before{content:"\f1b2"} -[data-simply-list-icon="fa-cubes"]:before{content:"\f1b3"} -[data-simply-list-icon="fa-behance"]:before{content:"\f1b4"} -[data-simply-list-icon="fa-behance-square"]:before{content:"\f1b5"} -[data-simply-list-icon="fa-steam"]:before{content:"\f1b6"} -[data-simply-list-icon="fa-steam-square"]:before{content:"\f1b7"} -[data-simply-list-icon="fa-recycle"]:before{content:"\f1b8"} -[data-simply-list-icon="fa-automobile"]:before, -[data-simply-list-icon="fa-car"]:before{content:"\f1b9"} -[data-simply-list-icon="fa-cab"]:before, -[data-simply-list-icon="fa-taxi"]:before{content:"\f1ba"} -[data-simply-list-icon="fa-tree"]:before{content:"\f1bb"} -[data-simply-list-icon="fa-spotify"]:before{content:"\f1bc"} -[data-simply-list-icon="fa-deviantart"]:before{content:"\f1bd"} -[data-simply-list-icon="fa-soundcloud"]:before{content:"\f1be"} -[data-simply-list-icon="fa-database"]:before{content:"\f1c0"} -[data-simply-list-icon="fa-file-pdf-o"]:before{content:"\f1c1"} -[data-simply-list-icon="fa-file-word-o"]:before{content:"\f1c2"} -[data-simply-list-icon="fa-file-excel-o"]:before{content:"\f1c3"} -[data-simply-list-icon="fa-file-powerpoint-o"]:before{content:"\f1c4"} -[data-simply-list-icon="fa-file-photo-o"]:before, -[data-simply-list-icon="fa-file-picture-o"]:before, -[data-simply-list-icon="fa-file-image-o"]:before{content:"\f1c5"} -[data-simply-list-icon="fa-file-zip-o"]:before, -[data-simply-list-icon="fa-file-archive-o"]:before{content:"\f1c6"} -[data-simply-list-icon="fa-file-sound-o"]:before, -[data-simply-list-icon="fa-file-audio-o"]:before{content:"\f1c7"} -[data-simply-list-icon="fa-file-movie-o"]:before, -[data-simply-list-icon="fa-file-video-o"]:before{content:"\f1c8"} -[data-simply-list-icon="fa-file-code-o"]:before{content:"\f1c9"} -[data-simply-list-icon="fa-vine"]:before{content:"\f1ca"} -[data-simply-list-icon="fa-codepen"]:before{content:"\f1cb"} -[data-simply-list-icon="fa-jsfiddle"]:before{content:"\f1cc"} -[data-simply-list-icon="fa-life-bouy"]:before, -[data-simply-list-icon="fa-life-buoy"]:before, -[data-simply-list-icon="fa-life-saver"]:before, -[data-simply-list-icon="fa-support"]:before, -[data-simply-list-icon="fa-life-ring"]:before{content:"\f1cd"} -[data-simply-list-icon="fa-circle-o-notch"]:before{content:"\f1ce"} -[data-simply-list-icon="fa-ra"]:before, -[data-simply-list-icon="fa-rebel"]:before{content:"\f1d0"} -[data-simply-list-icon="fa-ge"]:before, -[data-simply-list-icon="fa-empire"]:before{content:"\f1d1"} -[data-simply-list-icon="fa-git-square"]:before{content:"\f1d2"} -[data-simply-list-icon="fa-git"]:before{content:"\f1d3"} -[data-simply-list-icon="fa-y-combinator-square"]:before, -[data-simply-list-icon="fa-yc-square"]:before, -[data-simply-list-icon="fa-hacker-news"]:before{content:"\f1d4"} -[data-simply-list-icon="fa-tencent-weibo"]:before{content:"\f1d5"} -[data-simply-list-icon="fa-qq"]:before{content:"\f1d6"} -[data-simply-list-icon="fa-wechat"]:before, -[data-simply-list-icon="fa-weixin"]:before{content:"\f1d7"} -[data-simply-list-icon="fa-send"]:before, -[data-simply-list-icon="fa-paper-plane"]:before{content:"\f1d8"} -[data-simply-list-icon="fa-send-o"]:before, -[data-simply-list-icon="fa-paper-plane-o"]:before{content:"\f1d9"} -[data-simply-list-icon="fa-history"]:before{content:"\f1da"} -[data-simply-list-icon="fa-circle-thin"]:before{content:"\f1db"} -[data-simply-list-icon="fa-header"]:before{content:"\f1dc"} -[data-simply-list-icon="fa-paragraph"]:before{content:"\f1dd"} -[data-simply-list-icon="fa-sliders"]:before{content:"\f1de"} -[data-simply-list-icon="fa-share-alt"]:before{content:"\f1e0"} -[data-simply-list-icon="fa-share-alt-square"]:before{content:"\f1e1"} -[data-simply-list-icon="fa-bomb"]:before{content:"\f1e2"} -[data-simply-list-icon="fa-soccer-ball-o"]:before, -[data-simply-list-icon="fa-futbol-o"]:before{content:"\f1e3"} -[data-simply-list-icon="fa-tty"]:before{content:"\f1e4"} -[data-simply-list-icon="fa-binoculars"]:before{content:"\f1e5"} -[data-simply-list-icon="fa-plug"]:before{content:"\f1e6"} -[data-simply-list-icon="fa-slideshare"]:before{content:"\f1e7"} -[data-simply-list-icon="fa-twitch"]:before{content:"\f1e8"} -[data-simply-list-icon="fa-yelp"]:before{content:"\f1e9"} -[data-simply-list-icon="fa-newspaper-o"]:before{content:"\f1ea"} -[data-simply-list-icon="fa-wifi"]:before{content:"\f1eb"} -[data-simply-list-icon="fa-calculator"]:before{content:"\f1ec"} -[data-simply-list-icon="fa-paypal"]:before{content:"\f1ed"} -[data-simply-list-icon="fa-google-wallet"]:before{content:"\f1ee"} -[data-simply-list-icon="fa-cc-visa"]:before{content:"\f1f0"} -[data-simply-list-icon="fa-cc-mastercard"]:before{content:"\f1f1"} -[data-simply-list-icon="fa-cc-discover"]:before{content:"\f1f2"} -[data-simply-list-icon="fa-cc-amex"]:before{content:"\f1f3"} -[data-simply-list-icon="fa-cc-paypal"]:before{content:"\f1f4"} -[data-simply-list-icon="fa-cc-stripe"]:before{content:"\f1f5"} -[data-simply-list-icon="fa-bell-slash"]:before{content:"\f1f6"} -[data-simply-list-icon="fa-bell-slash-o"]:before{content:"\f1f7"} -[data-simply-list-icon="fa-trash"]:before{content:"\f1f8"} -[data-simply-list-icon="fa-copyright"]:before{content:"\f1f9"} -[data-simply-list-icon="fa-at"]:before{content:"\f1fa"} -[data-simply-list-icon="fa-eyedropper"]:before{content:"\f1fb"} -[data-simply-list-icon="fa-paint-brush"]:before{content:"\f1fc"} -[data-simply-list-icon="fa-birthday-cake"]:before{content:"\f1fd"} -[data-simply-list-icon="fa-area-chart"]:before{content:"\f1fe"} -[data-simply-list-icon="fa-pie-chart"]:before{content:"\f200"} -[data-simply-list-icon="fa-line-chart"]:before{content:"\f201"} -[data-simply-list-icon="fa-lastfm"]:before{content:"\f202"} -[data-simply-list-icon="fa-lastfm-square"]:before{content:"\f203"} -[data-simply-list-icon="fa-toggle-off"]:before{content:"\f204"} -[data-simply-list-icon="fa-toggle-on"]:before{content:"\f205"} -[data-simply-list-icon="fa-bicycle"]:before{content:"\f206"} -[data-simply-list-icon="fa-bus"]:before{content:"\f207"} -[data-simply-list-icon="fa-ioxhost"]:before{content:"\f208"} -[data-simply-list-icon="fa-angellist"]:before{content:"\f209"} -[data-simply-list-icon="fa-cc"]:before{content:"\f20a"} -[data-simply-list-icon="fa-shekel"]:before, -[data-simply-list-icon="fa-sheqel"]:before, -[data-simply-list-icon="fa-ils"]:before{content:"\f20b"} -[data-simply-list-icon="fa-meanpath"]:before{content:"\f20c"} -[data-simply-list-icon="fa-buysellads"]:before{content:"\f20d"} -[data-simply-list-icon="fa-connectdevelop"]:before{content:"\f20e"} -[data-simply-list-icon="fa-dashcube"]:before{content:"\f210"} -[data-simply-list-icon="fa-forumbee"]:before{content:"\f211"} -[data-simply-list-icon="fa-leanpub"]:before{content:"\f212"} -[data-simply-list-icon="fa-sellsy"]:before{content:"\f213"} -[data-simply-list-icon="fa-shirtsinbulk"]:before{content:"\f214"} -[data-simply-list-icon="fa-simplybuilt"]:before{content:"\f215"} -[data-simply-list-icon="fa-skyatlas"]:before{content:"\f216"} -[data-simply-list-icon="fa-cart-plus"]:before{content:"\f217"} -[data-simply-list-icon="fa-cart-arrow-down"]:before{content:"\f218"} -[data-simply-list-icon="fa-diamond"]:before{content:"\f219"} -[data-simply-list-icon="fa-ship"]:before{content:"\f21a"} -[data-simply-list-icon="fa-user-secret"]:before{content:"\f21b"} -[data-simply-list-icon="fa-motorcycle"]:before{content:"\f21c"} -[data-simply-list-icon="fa-street-view"]:before{content:"\f21d"} -[data-simply-list-icon="fa-heartbeat"]:before{content:"\f21e"} -[data-simply-list-icon="fa-venus"]:before{content:"\f221"} -[data-simply-list-icon="fa-mars"]:before{content:"\f222"} -[data-simply-list-icon="fa-mercury"]:before{content:"\f223"} -[data-simply-list-icon="fa-intersex"]:before, -[data-simply-list-icon="fa-transgender"]:before{content:"\f224"} -[data-simply-list-icon="fa-transgender-alt"]:before{content:"\f225"} -[data-simply-list-icon="fa-venus-double"]:before{content:"\f226"} -[data-simply-list-icon="fa-mars-double"]:before{content:"\f227"} -[data-simply-list-icon="fa-venus-mars"]:before{content:"\f228"} -[data-simply-list-icon="fa-mars-stroke"]:before{content:"\f229"} -[data-simply-list-icon="fa-mars-stroke-v"]:before{content:"\f22a"} -[data-simply-list-icon="fa-mars-stroke-h"]:before{content:"\f22b"} -[data-simply-list-icon="fa-neuter"]:before{content:"\f22c"} -[data-simply-list-icon="fa-genderless"]:before{content:"\f22d"} -[data-simply-list-icon="fa-facebook-official"]:before{content:"\f230"} -[data-simply-list-icon="fa-pinterest-p"]:before{content:"\f231"} -[data-simply-list-icon="fa-whatsapp"]:before{content:"\f232"} -[data-simply-list-icon="fa-server"]:before{content:"\f233"} -[data-simply-list-icon="fa-user-plus"]:before{content:"\f234"} -[data-simply-list-icon="fa-user-times"]:before{content:"\f235"} -[data-simply-list-icon="fa-hotel"]:before, -[data-simply-list-icon="fa-bed"]:before{content:"\f236"} -[data-simply-list-icon="fa-viacoin"]:before{content:"\f237"} -[data-simply-list-icon="fa-train"]:before{content:"\f238"} -[data-simply-list-icon="fa-subway"]:before{content:"\f239"} -[data-simply-list-icon="fa-medium"]:before{content:"\f23a"} -[data-simply-list-icon="fa-yc"]:before, -[data-simply-list-icon="fa-y-combinator"]:before{content:"\f23b"} -[data-simply-list-icon="fa-optin-monster"]:before{content:"\f23c"} -[data-simply-list-icon="fa-opencart"]:before{content:"\f23d"} -[data-simply-list-icon="fa-expeditedssl"]:before{content:"\f23e"} -[data-simply-list-icon="fa-battery-4"]:before, -[data-simply-list-icon="fa-battery-full"]:before{content:"\f240"} -[data-simply-list-icon="fa-battery-3"]:before, -[data-simply-list-icon="fa-battery-three-quarters"]:before{content:"\f241"} -[data-simply-list-icon="fa-battery-2"]:before, -[data-simply-list-icon="fa-battery-half"]:before{content:"\f242"} -[data-simply-list-icon="fa-battery-1"]:before, -[data-simply-list-icon="fa-battery-quarter"]:before{content:"\f243"} -[data-simply-list-icon="fa-battery-0"]:before, -[data-simply-list-icon="fa-battery-empty"]:before{content:"\f244"} -[data-simply-list-icon="fa-mouse-pointer"]:before{content:"\f245"} -[data-simply-list-icon="fa-i-cursor"]:before{content:"\f246"} -[data-simply-list-icon="fa-object-group"]:before{content:"\f247"} -[data-simply-list-icon="fa-object-ungroup"]:before{content:"\f248"} -[data-simply-list-icon="fa-sticky-note"]:before{content:"\f249"} -[data-simply-list-icon="fa-sticky-note-o"]:before{content:"\f24a"} -[data-simply-list-icon="fa-cc-jcb"]:before{content:"\f24b"} -[data-simply-list-icon="fa-cc-diners-club"]:before{content:"\f24c"} -[data-simply-list-icon="fa-clone"]:before{content:"\f24d"} -[data-simply-list-icon="fa-balance-scale"]:before{content:"\f24e"} -[data-simply-list-icon="fa-hourglass-o"]:before{content:"\f250"} -[data-simply-list-icon="fa-hourglass-1"]:before, -[data-simply-list-icon="fa-hourglass-start"]:before{content:"\f251"} -[data-simply-list-icon="fa-hourglass-2"]:before, -[data-simply-list-icon="fa-hourglass-half"]:before{content:"\f252"} -[data-simply-list-icon="fa-hourglass-3"]:before, -[data-simply-list-icon="fa-hourglass-end"]:before{content:"\f253"} -[data-simply-list-icon="fa-hourglass"]:before{content:"\f254"} -[data-simply-list-icon="fa-hand-grab-o"]:before, -[data-simply-list-icon="fa-hand-rock-o"]:before{content:"\f255"} -[data-simply-list-icon="fa-hand-stop-o"]:before, -[data-simply-list-icon="fa-hand-paper-o"]:before{content:"\f256"} -[data-simply-list-icon="fa-hand-scissors-o"]:before{content:"\f257"} -[data-simply-list-icon="fa-hand-lizard-o"]:before{content:"\f258"} -[data-simply-list-icon="fa-hand-spock-o"]:before{content:"\f259"} -[data-simply-list-icon="fa-hand-pointer-o"]:before{content:"\f25a"} -[data-simply-list-icon="fa-hand-peace-o"]:before{content:"\f25b"} -[data-simply-list-icon="fa-trademark"]:before{content:"\f25c"} -[data-simply-list-icon="fa-registered"]:before{content:"\f25d"} -[data-simply-list-icon="fa-creative-commons"]:before{content:"\f25e"} -[data-simply-list-icon="fa-gg"]:before{content:"\f260"} -[data-simply-list-icon="fa-gg-circle"]:before{content:"\f261"} -[data-simply-list-icon="fa-tripadvisor"]:before{content:"\f262"} -[data-simply-list-icon="fa-odnoklassniki"]:before{content:"\f263"} -[data-simply-list-icon="fa-odnoklassniki-square"]:before{content:"\f264"} -[data-simply-list-icon="fa-get-pocket"]:before{content:"\f265"} -[data-simply-list-icon="fa-wikipedia-w"]:before{content:"\f266"} -[data-simply-list-icon="fa-safari"]:before{content:"\f267"} -[data-simply-list-icon="fa-chrome"]:before{content:"\f268"} -[data-simply-list-icon="fa-firefox"]:before{content:"\f269"} -[data-simply-list-icon="fa-opera"]:before{content:"\f26a"} -[data-simply-list-icon="fa-internet-explorer"]:before{content:"\f26b"} -[data-simply-list-icon="fa-tv"]:before, -[data-simply-list-icon="fa-television"]:before{content:"\f26c"} -[data-simply-list-icon="fa-contao"]:before{content:"\f26d"} -[data-simply-list-icon="fa-500px"]:before{content:"\f26e"} -[data-simply-list-icon="fa-amazon"]:before{content:"\f270"} -[data-simply-list-icon="fa-calendar-plus-o"]:before{content:"\f271"} -[data-simply-list-icon="fa-calendar-minus-o"]:before{content:"\f272"} -[data-simply-list-icon="fa-calendar-times-o"]:before{content:"\f273"} -[data-simply-list-icon="fa-calendar-check-o"]:before{content:"\f274"} -[data-simply-list-icon="fa-industry"]:before{content:"\f275"} -[data-simply-list-icon="fa-map-pin"]:before{content:"\f276"} -[data-simply-list-icon="fa-map-signs"]:before{content:"\f277"} -[data-simply-list-icon="fa-map-o"]:before{content:"\f278"} -[data-simply-list-icon="fa-map"]:before{content:"\f279"} -[data-simply-list-icon="fa-commenting"]:before{content:"\f27a"} -[data-simply-list-icon="fa-commenting-o"]:before{content:"\f27b"} -[data-simply-list-icon="fa-houzz"]:before{content:"\f27c"} -[data-simply-list-icon="fa-vimeo"]:before{content:"\f27d"} -[data-simply-list-icon="fa-black-tie"]:before{content:"\f27e"} -[data-simply-list-icon="fa-fonticons"]:before{content:"\f280"} - -tr[data-simply-list-icon]:before{content:''} -tr[data-simply-list-icon="fa-glass"] td:first-child:before{content:"\f000"} -tr[data-simply-list-icon="fa-music"] td:first-child:before{content:"\f001"} -tr[data-simply-list-icon="fa-search"] td:first-child:before{content:"\f002"} -tr[data-simply-list-icon="fa-envelope-o"] td:first-child:before{content:"\f003"} -tr[data-simply-list-icon="fa-heart"] td:first-child:before{content:"\f004"} -tr[data-simply-list-icon="fa-star"] td:first-child:before{content:"\f005"} -tr[data-simply-list-icon="fa-star-o"] td:first-child:before{content:"\f006"} -tr[data-simply-list-icon="fa-user"] td:first-child:before{content:"\f007"} -tr[data-simply-list-icon="fa-film"] td:first-child:before{content:"\f008"} -tr[data-simply-list-icon="fa-th-large"] td:first-child:before{content:"\f009"} -tr[data-simply-list-icon="fa-th"] td:first-child:before{content:"\f00a"} -tr[data-simply-list-icon="fa-th-list"] td:first-child:before{content:"\f00b"} -tr[data-simply-list-icon="fa-check"] td:first-child:before{content:"\f00c"} -tr[data-simply-list-icon="fa-remove"] td:first-child:before, -tr[data-simply-list-icon="fa-close"] td:first-child:before, -tr[data-simply-list-icon="fa-times"] td:first-child:before{content:"\f00d"} -tr[data-simply-list-icon="fa-search-plus"] td:first-child:before{content:"\f00e"} -tr[data-simply-list-icon="fa-search-minus"] td:first-child:before{content:"\f010"} -tr[data-simply-list-icon="fa-power-off"] td:first-child:before{content:"\f011"} -tr[data-simply-list-icon="fa-signal"] td:first-child:before{content:"\f012"} -tr[data-simply-list-icon="fa-gear"] td:first-child:before, -tr[data-simply-list-icon="fa-cog"] td:first-child:before{content:"\f013"} -tr[data-simply-list-icon="fa-trash-o"] td:first-child:before{content:"\f014"} -tr[data-simply-list-icon="fa-home"] td:first-child:before{content:"\f015"} -tr[data-simply-list-icon="fa-file-o"] td:first-child:before{content:"\f016"} -tr[data-simply-list-icon="fa-clock-o"] td:first-child:before{content:"\f017"} -tr[data-simply-list-icon="fa-road"] td:first-child:before{content:"\f018"} -tr[data-simply-list-icon="fa-download"] td:first-child:before{content:"\f019"} -tr[data-simply-list-icon="fa-arrow-circle-o-down"] td:first-child:before{content:"\f01a"} -tr[data-simply-list-icon="fa-arrow-circle-o-up"] td:first-child:before{content:"\f01b"} -tr[data-simply-list-icon="fa-inbox"] td:first-child:before{content:"\f01c"} -tr[data-simply-list-icon="fa-play-circle-o"] td:first-child:before{content:"\f01d"} -tr[data-simply-list-icon="fa-rotate-right"] td:first-child:before, -tr[data-simply-list-icon="fa-repeat"] td:first-child:before{content:"\f01e"} -tr[data-simply-list-icon="fa-refresh"] td:first-child:before{content:"\f021"} -tr[data-simply-list-icon="fa-list-alt"] td:first-child:before{content:"\f022"} -tr[data-simply-list-icon="fa-lock"] td:first-child:before{content:"\f023"} -tr[data-simply-list-icon="fa-flag"] td:first-child:before{content:"\f024"} -tr[data-simply-list-icon="fa-headphones"] td:first-child:before{content:"\f025"} -tr[data-simply-list-icon="fa-volume-off"] td:first-child:before{content:"\f026"} -tr[data-simply-list-icon="fa-volume-down"] td:first-child:before{content:"\f027"} -tr[data-simply-list-icon="fa-volume-up"] td:first-child:before{content:"\f028"} -tr[data-simply-list-icon="fa-qrcode"] td:first-child:before{content:"\f029"} -tr[data-simply-list-icon="fa-barcode"] td:first-child:before{content:"\f02a"} -tr[data-simply-list-icon="fa-tag"] td:first-child:before{content:"\f02b"} -tr[data-simply-list-icon="fa-tags"] td:first-child:before{content:"\f02c"} -tr[data-simply-list-icon="fa-book"] td:first-child:before{content:"\f02d"} -tr[data-simply-list-icon="fa-bookmark"] td:first-child:before{content:"\f02e"} -tr[data-simply-list-icon="fa-print"] td:first-child:before{content:"\f02f"} -tr[data-simply-list-icon="fa-camera"] td:first-child:before{content:"\f030"} -tr[data-simply-list-icon="fa-font"] td:first-child:before{content:"\f031"} -tr[data-simply-list-icon="fa-bold"] td:first-child:before{content:"\f032"} -tr[data-simply-list-icon="fa-italic"] td:first-child:before{content:"\f033"} -tr[data-simply-list-icon="fa-text-height"] td:first-child:before{content:"\f034"} -tr[data-simply-list-icon="fa-text-width"] td:first-child:before{content:"\f035"} -tr[data-simply-list-icon="fa-align-left"] td:first-child:before{content:"\f036"} -tr[data-simply-list-icon="fa-align-center"] td:first-child:before{content:"\f037"} -tr[data-simply-list-icon="fa-align-right"] td:first-child:before{content:"\f038"} -tr[data-simply-list-icon="fa-align-justify"] td:first-child:before{content:"\f039"} -tr[data-simply-list-icon="fa-list"] td:first-child:before{content:"\f03a"} -tr[data-simply-list-icon="fa-dedent"] td:first-child:before, -tr[data-simply-list-icon="fa-outdent"] td:first-child:before{content:"\f03b"} -tr[data-simply-list-icon="fa-indent"] td:first-child:before{content:"\f03c"} -tr[data-simply-list-icon="fa-video-camera"] td:first-child:before{content:"\f03d"} -tr[data-simply-list-icon="fa-photo"] td:first-child:before, -tr[data-simply-list-icon="fa-image"] td:first-child:before, -tr[data-simply-list-icon="fa-picture-o"] td:first-child:before{content:"\f03e"} -tr[data-simply-list-icon="fa-pencil"] td:first-child:before{content:"\f040"} -tr[data-simply-list-icon="fa-map-marker"] td:first-child:before{content:"\f041"} -tr[data-simply-list-icon="fa-adjust"] td:first-child:before{content:"\f042"} -tr[data-simply-list-icon="fa-tint"] td:first-child:before{content:"\f043"} -tr[data-simply-list-icon="fa-edit"] td:first-child:before, -tr[data-simply-list-icon="fa-pencil-square-o"] td:first-child:before{content:"\f044"} -tr[data-simply-list-icon="fa-share-square-o"] td:first-child:before{content:"\f045"} -tr[data-simply-list-icon="fa-check-square-o"] td:first-child:before{content:"\f046"} -tr[data-simply-list-icon="fa-arrows"] td:first-child:before{content:"\f047"} -tr[data-simply-list-icon="fa-step-backward"] td:first-child:before{content:"\f048"} -tr[data-simply-list-icon="fa-fast-backward"] td:first-child:before{content:"\f049"} -tr[data-simply-list-icon="fa-backward"] td:first-child:before{content:"\f04a"} -tr[data-simply-list-icon="fa-play"] td:first-child:before{content:"\f04b"} -tr[data-simply-list-icon="fa-pause"] td:first-child:before{content:"\f04c"} -tr[data-simply-list-icon="fa-stop"] td:first-child:before{content:"\f04d"} -tr[data-simply-list-icon="fa-forward"] td:first-child:before{content:"\f04e"} -tr[data-simply-list-icon="fa-fast-forward"] td:first-child:before{content:"\f050"} -tr[data-simply-list-icon="fa-step-forward"] td:first-child:before{content:"\f051"} -tr[data-simply-list-icon="fa-eject"] td:first-child:before{content:"\f052"} -tr[data-simply-list-icon="fa-chevron-left"] td:first-child:before{content:"\f053"} -tr[data-simply-list-icon="fa-chevron-right"] td:first-child:before{content:"\f054"} -tr[data-simply-list-icon="fa-plus-circle"] td:first-child:before{content:"\f055"} -tr[data-simply-list-icon="fa-minus-circle"] td:first-child:before{content:"\f056"} -tr[data-simply-list-icon="fa-times-circle"] td:first-child:before{content:"\f057"} -tr[data-simply-list-icon="fa-check-circle"] td:first-child:before{content:"\f058"} -tr[data-simply-list-icon="fa-question-circle"] td:first-child:before{content:"\f059"} -tr[data-simply-list-icon="fa-info-circle"] td:first-child:before{content:"\f05a"} -tr[data-simply-list-icon="fa-crosshairs"] td:first-child:before{content:"\f05b"} -tr[data-simply-list-icon="fa-times-circle-o"] td:first-child:before{content:"\f05c"} -tr[data-simply-list-icon="fa-check-circle-o"] td:first-child:before{content:"\f05d"} -tr[data-simply-list-icon="fa-ban"] td:first-child:before{content:"\f05e"} -tr[data-simply-list-icon="fa-arrow-left"] td:first-child:before{content:"\f060"} -tr[data-simply-list-icon="fa-arrow-right"] td:first-child:before{content:"\f061"} -tr[data-simply-list-icon="fa-arrow-up"] td:first-child:before{content:"\f062"} -tr[data-simply-list-icon="fa-arrow-down"] td:first-child:before{content:"\f063"} -tr[data-simply-list-icon="fa-mail-forward"] td:first-child:before, -tr[data-simply-list-icon="fa-share"] td:first-child:before{content:"\f064"} -tr[data-simply-list-icon="fa-expand"] td:first-child:before{content:"\f065"} -tr[data-simply-list-icon="fa-compress"] td:first-child:before{content:"\f066"} -tr[data-simply-list-icon="fa-plus"] td:first-child:before{content:"\f067"} -tr[data-simply-list-icon="fa-minus"] td:first-child:before{content:"\f068"} -tr[data-simply-list-icon="fa-asterisk"] td:first-child:before{content:"\f069"} -tr[data-simply-list-icon="fa-exclamation-circle"] td:first-child:before{content:"\f06a"} -tr[data-simply-list-icon="fa-gift"] td:first-child:before{content:"\f06b"} -tr[data-simply-list-icon="fa-leaf"] td:first-child:before{content:"\f06c"} -tr[data-simply-list-icon="fa-fire"] td:first-child:before{content:"\f06d"} -tr[data-simply-list-icon="fa-eye"] td:first-child:before{content:"\f06e"} -tr[data-simply-list-icon="fa-eye-slash"] td:first-child:before{content:"\f070"} -tr[data-simply-list-icon="fa-warning"] td:first-child:before, -tr[data-simply-list-icon="fa-exclamation-triangle"] td:first-child:before{content:"\f071"} -tr[data-simply-list-icon="fa-plane"] td:first-child:before{content:"\f072"} -tr[data-simply-list-icon="fa-calendar"] td:first-child:before{content:"\f073"} -tr[data-simply-list-icon="fa-random"] td:first-child:before{content:"\f074"} -tr[data-simply-list-icon="fa-comment"] td:first-child:before{content:"\f075"} -tr[data-simply-list-icon="fa-magnet"] td:first-child:before{content:"\f076"} -tr[data-simply-list-icon="fa-chevron-up"] td:first-child:before{content:"\f077"} -tr[data-simply-list-icon="fa-chevron-down"] td:first-child:before{content:"\f078"} -tr[data-simply-list-icon="fa-retweet"] td:first-child:before{content:"\f079"} -tr[data-simply-list-icon="fa-shopping-cart"] td:first-child:before{content:"\f07a"} -tr[data-simply-list-icon="fa-folder"] td:first-child:before{content:"\f07b"} -tr[data-simply-list-icon="fa-folder-open"] td:first-child:before{content:"\f07c"} -tr[data-simply-list-icon="fa-arrows-v"] td:first-child:before{content:"\f07d"} -tr[data-simply-list-icon="fa-arrows-h"] td:first-child:before{content:"\f07e"} -tr[data-simply-list-icon="fa-bar-chart-o"] td:first-child:before, -tr[data-simply-list-icon="fa-bar-chart"] td:first-child:before{content:"\f080"} -tr[data-simply-list-icon="fa-twitter-square"] td:first-child:before{content:"\f081"} -tr[data-simply-list-icon="fa-facebook-square"] td:first-child:before{content:"\f082"} -tr[data-simply-list-icon="fa-camera-retro"] td:first-child:before{content:"\f083"} -tr[data-simply-list-icon="fa-key"] td:first-child:before{content:"\f084"} -tr[data-simply-list-icon="fa-gears"] td:first-child:before, -tr[data-simply-list-icon="fa-cogs"] td:first-child:before{content:"\f085"} -tr[data-simply-list-icon="fa-comments"] td:first-child:before{content:"\f086"} -tr[data-simply-list-icon="fa-thumbs-o-up"] td:first-child:before{content:"\f087"} -tr[data-simply-list-icon="fa-thumbs-o-down"] td:first-child:before{content:"\f088"} -tr[data-simply-list-icon="fa-star-half"] td:first-child:before{content:"\f089"} -tr[data-simply-list-icon="fa-heart-o"] td:first-child:before{content:"\f08a"} -tr[data-simply-list-icon="fa-sign-out"] td:first-child:before{content:"\f08b"} -tr[data-simply-list-icon="fa-linkedin-square"] td:first-child:before{content:"\f08c"} -tr[data-simply-list-icon="fa-thumb-tack"] td:first-child:before{content:"\f08d"} -tr[data-simply-list-icon="fa-external-link"] td:first-child:before{content:"\f08e"} -tr[data-simply-list-icon="fa-sign-in"] td:first-child:before{content:"\f090"} -tr[data-simply-list-icon="fa-trophy"] td:first-child:before{content:"\f091"} -tr[data-simply-list-icon="fa-github-square"] td:first-child:before{content:"\f092"} -tr[data-simply-list-icon="fa-upload"] td:first-child:before{content:"\f093"} -tr[data-simply-list-icon="fa-lemon-o"] td:first-child:before{content:"\f094"} -tr[data-simply-list-icon="fa-phone"] td:first-child:before{content:"\f095"} -tr[data-simply-list-icon="fa-square-o"] td:first-child:before{content:"\f096"} -tr[data-simply-list-icon="fa-bookmark-o"] td:first-child:before{content:"\f097"} -tr[data-simply-list-icon="fa-phone-square"] td:first-child:before{content:"\f098"} -tr[data-simply-list-icon="fa-twitter"] td:first-child:before{content:"\f099"} -tr[data-simply-list-icon="fa-facebook-f"] td:first-child:before, -tr[data-simply-list-icon="fa-facebook"] td:first-child:before{content:"\f09a"} -tr[data-simply-list-icon="fa-github"] td:first-child:before{content:"\f09b"} -tr[data-simply-list-icon="fa-unlock"] td:first-child:before{content:"\f09c"} -tr[data-simply-list-icon="fa-credit-card"] td:first-child:before{content:"\f09d"} -tr[data-simply-list-icon="fa-feed"] td:first-child:before, -tr[data-simply-list-icon="fa-rss"] td:first-child:before{content:"\f09e"} -tr[data-simply-list-icon="fa-hdd-o"] td:first-child:before{content:"\f0a0"} -tr[data-simply-list-icon="fa-bullhorn"] td:first-child:before{content:"\f0a1"} -tr[data-simply-list-icon="fa-bell"] td:first-child:before{content:"\f0f3"} -tr[data-simply-list-icon="fa-certificate"] td:first-child:before{content:"\f0a3"} -tr[data-simply-list-icon="fa-hand-o-right"] td:first-child:before{content:"\f0a4"} -tr[data-simply-list-icon="fa-hand-o-left"] td:first-child:before{content:"\f0a5"} -tr[data-simply-list-icon="fa-hand-o-up"] td:first-child:before{content:"\f0a6"} -tr[data-simply-list-icon="fa-hand-o-down"] td:first-child:before{content:"\f0a7"} -tr[data-simply-list-icon="fa-arrow-circle-left"] td:first-child:before{content:"\f0a8"} -tr[data-simply-list-icon="fa-arrow-circle-right"] td:first-child:before{content:"\f0a9"} -tr[data-simply-list-icon="fa-arrow-circle-up"] td:first-child:before{content:"\f0aa"} -tr[data-simply-list-icon="fa-arrow-circle-down"] td:first-child:before{content:"\f0ab"} -tr[data-simply-list-icon="fa-globe"] td:first-child:before{content:"\f0ac"} -tr[data-simply-list-icon="fa-wrench"] td:first-child:before{content:"\f0ad"} -tr[data-simply-list-icon="fa-tasks"] td:first-child:before{content:"\f0ae"} -tr[data-simply-list-icon="fa-filter"] td:first-child:before{content:"\f0b0"} -tr[data-simply-list-icon="fa-briefcase"] td:first-child:before{content:"\f0b1"} -tr[data-simply-list-icon="fa-arrows-alt"] td:first-child:before{content:"\f0b2"} -tr[data-simply-list-icon="fa-group"] td:first-child:before, -tr[data-simply-list-icon="fa-users"] td:first-child:before{content:"\f0c0"} -tr[data-simply-list-icon="fa-chain"] td:first-child:before, -tr[data-simply-list-icon="fa-link"] td:first-child:before{content:"\f0c1"} -tr[data-simply-list-icon="fa-cloud"] td:first-child:before{content:"\f0c2"} -tr[data-simply-list-icon="fa-flask"] td:first-child:before{content:"\f0c3"} -tr[data-simply-list-icon="fa-cut"] td:first-child:before, -tr[data-simply-list-icon="fa-scissors"] td:first-child:before{content:"\f0c4"} -tr[data-simply-list-icon="fa-copy"] td:first-child:before, -tr[data-simply-list-icon="fa-files-o"] td:first-child:before{content:"\f0c5"} -tr[data-simply-list-icon="fa-paperclip"] td:first-child:before{content:"\f0c6"} -tr[data-simply-list-icon="fa-save"] td:first-child:before, -tr[data-simply-list-icon="fa-floppy-o"] td:first-child:before{content:"\f0c7"} -tr[data-simply-list-icon="fa-square"] td:first-child:before{content:"\f0c8"} -tr[data-simply-list-icon="fa-navicon"] td:first-child:before, -tr[data-simply-list-icon="fa-reorder"] td:first-child:before, -tr[data-simply-list-icon="fa-bars"] td:first-child:before{content:"\f0c9"} -tr[data-simply-list-icon="fa-list-ul"] td:first-child:before{content:"\f0ca"} -tr[data-simply-list-icon="fa-list-ol"] td:first-child:before{content:"\f0cb"} -tr[data-simply-list-icon="fa-strikethrough"] td:first-child:before{content:"\f0cc"} -tr[data-simply-list-icon="fa-underline"] td:first-child:before{content:"\f0cd"} -tr[data-simply-list-icon="fa-table"] td:first-child:before{content:"\f0ce"} -tr[data-simply-list-icon="fa-magic"] td:first-child:before{content:"\f0d0"} -tr[data-simply-list-icon="fa-truck"] td:first-child:before{content:"\f0d1"} -tr[data-simply-list-icon="fa-pinterest"] td:first-child:before{content:"\f0d2"} -tr[data-simply-list-icon="fa-pinterest-square"] td:first-child:before{content:"\f0d3"} -tr[data-simply-list-icon="fa-google-plus-square"] td:first-child:before{content:"\f0d4"} -tr[data-simply-list-icon="fa-google-plus"] td:first-child:before{content:"\f0d5"} -tr[data-simply-list-icon="fa-money"] td:first-child:before{content:"\f0d6"} -tr[data-simply-list-icon="fa-caret-down"] td:first-child:before{content:"\f0d7"} -tr[data-simply-list-icon="fa-caret-up"] td:first-child:before{content:"\f0d8"} -tr[data-simply-list-icon="fa-caret-left"] td:first-child:before{content:"\f0d9"} -tr[data-simply-list-icon="fa-caret-right"] td:first-child:before{content:"\f0da"} -tr[data-simply-list-icon="fa-columns"] td:first-child:before{content:"\f0db"} -tr[data-simply-list-icon="fa-unsorted"] td:first-child:before, -tr[data-simply-list-icon="fa-sort"] td:first-child:before{content:"\f0dc"} -tr[data-simply-list-icon="fa-sort-down"] td:first-child:before, -tr[data-simply-list-icon="fa-sort-desc"] td:first-child:before{content:"\f0dd"} -tr[data-simply-list-icon="fa-sort-up"] td:first-child:before, -tr[data-simply-list-icon="fa-sort-asc"] td:first-child:before{content:"\f0de"} -tr[data-simply-list-icon="fa-envelope"] td:first-child:before{content:"\f0e0"} -tr[data-simply-list-icon="fa-linkedin"] td:first-child:before{content:"\f0e1"} -tr[data-simply-list-icon="fa-rotate-left"] td:first-child:before, -tr[data-simply-list-icon="fa-undo"] td:first-child:before{content:"\f0e2"} -tr[data-simply-list-icon="fa-legal"] td:first-child:before, -tr[data-simply-list-icon="fa-gavel"] td:first-child:before{content:"\f0e3"} -tr[data-simply-list-icon="fa-dashboard"] td:first-child:before, -tr[data-simply-list-icon="fa-tachometer"] td:first-child:before{content:"\f0e4"} -tr[data-simply-list-icon="fa-comment-o"] td:first-child:before{content:"\f0e5"} -tr[data-simply-list-icon="fa-comments-o"] td:first-child:before{content:"\f0e6"} -tr[data-simply-list-icon="fa-flash"] td:first-child:before, -tr[data-simply-list-icon="fa-bolt"] td:first-child:before{content:"\f0e7"} -tr[data-simply-list-icon="fa-sitemap"] td:first-child:before{content:"\f0e8"} -tr[data-simply-list-icon="fa-umbrella"] td:first-child:before{content:"\f0e9"} -tr[data-simply-list-icon="fa-paste"] td:first-child:before, -tr[data-simply-list-icon="fa-clipboard"] td:first-child:before{content:"\f0ea"} -tr[data-simply-list-icon="fa-lightbulb-o"] td:first-child:before{content:"\f0eb"} -tr[data-simply-list-icon="fa-exchange"] td:first-child:before{content:"\f0ec"} -tr[data-simply-list-icon="fa-cloud-download"] td:first-child:before{content:"\f0ed"} -tr[data-simply-list-icon="fa-cloud-upload"] td:first-child:before{content:"\f0ee"} -tr[data-simply-list-icon="fa-user-md"] td:first-child:before{content:"\f0f0"} -tr[data-simply-list-icon="fa-stethoscope"] td:first-child:before{content:"\f0f1"} -tr[data-simply-list-icon="fa-suitcase"] td:first-child:before{content:"\f0f2"} -tr[data-simply-list-icon="fa-bell-o"] td:first-child:before{content:"\f0a2"} -tr[data-simply-list-icon="fa-coffee"] td:first-child:before{content:"\f0f4"} -tr[data-simply-list-icon="fa-cutlery"] td:first-child:before{content:"\f0f5"} -tr[data-simply-list-icon="fa-file-text-o"] td:first-child:before{content:"\f0f6"} -tr[data-simply-list-icon="fa-building-o"] td:first-child:before{content:"\f0f7"} -tr[data-simply-list-icon="fa-hospital-o"] td:first-child:before{content:"\f0f8"} -tr[data-simply-list-icon="fa-ambulance"] td:first-child:before{content:"\f0f9"} -tr[data-simply-list-icon="fa-medkit"] td:first-child:before{content:"\f0fa"} -tr[data-simply-list-icon="fa-fighter-jet"] td:first-child:before{content:"\f0fb"} -tr[data-simply-list-icon="fa-beer"] td:first-child:before{content:"\f0fc"} -tr[data-simply-list-icon="fa-h-square"] td:first-child:before{content:"\f0fd"} -tr[data-simply-list-icon="fa-plus-square"] td:first-child:before{content:"\f0fe"} -tr[data-simply-list-icon="fa-angle-double-left"] td:first-child:before{content:"\f100"} -tr[data-simply-list-icon="fa-angle-double-right"] td:first-child:before{content:"\f101"} -tr[data-simply-list-icon="fa-angle-double-up"] td:first-child:before{content:"\f102"} -tr[data-simply-list-icon="fa-angle-double-down"] td:first-child:before{content:"\f103"} -tr[data-simply-list-icon="fa-angle-left"] td:first-child:before{content:"\f104"} -tr[data-simply-list-icon="fa-angle-right"] td:first-child:before{content:"\f105"} -tr[data-simply-list-icon="fa-angle-up"] td:first-child:before{content:"\f106"} -tr[data-simply-list-icon="fa-angle-down"] td:first-child:before{content:"\f107"} -tr[data-simply-list-icon="fa-desktop"] td:first-child:before{content:"\f108"} -tr[data-simply-list-icon="fa-laptop"] td:first-child:before{content:"\f109"} -tr[data-simply-list-icon="fa-tablet"] td:first-child:before{content:"\f10a"} -tr[data-simply-list-icon="fa-mobile-phone"] td:first-child:before, -tr[data-simply-list-icon="fa-mobile"] td:first-child:before{content:"\f10b"} -tr[data-simply-list-icon="fa-circle-o"] td:first-child:before{content:"\f10c"} -tr[data-simply-list-icon="fa-quote-left"] td:first-child:before{content:"\f10d"} -tr[data-simply-list-icon="fa-quote-right"] td:first-child:before{content:"\f10e"} -tr[data-simply-list-icon="fa-spinner"] td:first-child:before{content:"\f110"} -tr[data-simply-list-icon="fa-circle"] td:first-child:before{content:"\f111"} -tr[data-simply-list-icon="fa-mail-reply"] td:first-child:before, -tr[data-simply-list-icon="fa-reply"] td:first-child:before{content:"\f112"} -tr[data-simply-list-icon="fa-github-alt"] td:first-child:before{content:"\f113"} -tr[data-simply-list-icon="fa-folder-o"] td:first-child:before{content:"\f114"} -tr[data-simply-list-icon="fa-folder-open-o"] td:first-child:before{content:"\f115"} -tr[data-simply-list-icon="fa-smile-o"] td:first-child:before{content:"\f118"} -tr[data-simply-list-icon="fa-frown-o"] td:first-child:before{content:"\f119"} -tr[data-simply-list-icon="fa-meh-o"] td:first-child:before{content:"\f11a"} -tr[data-simply-list-icon="fa-gamepad"] td:first-child:before{content:"\f11b"} -tr[data-simply-list-icon="fa-keyboard-o"] td:first-child:before{content:"\f11c"} -tr[data-simply-list-icon="fa-flag-o"] td:first-child:before{content:"\f11d"} -tr[data-simply-list-icon="fa-flag-checkered"] td:first-child:before{content:"\f11e"} -tr[data-simply-list-icon="fa-terminal"] td:first-child:before{content:"\f120"} -tr[data-simply-list-icon="fa-code"] td:first-child:before{content:"\f121"} -tr[data-simply-list-icon="fa-mail-reply-all"] td:first-child:before, -tr[data-simply-list-icon="fa-reply-all"] td:first-child:before{content:"\f122"} -tr[data-simply-list-icon="fa-star-half-empty"] td:first-child:before, -tr[data-simply-list-icon="fa-star-half-full"] td:first-child:before, -tr[data-simply-list-icon="fa-star-half-o"] td:first-child:before{content:"\f123"} -tr[data-simply-list-icon="fa-location-arrow"] td:first-child:before{content:"\f124"} -tr[data-simply-list-icon="fa-crop"] td:first-child:before{content:"\f125"} -tr[data-simply-list-icon="fa-code-fork"] td:first-child:before{content:"\f126"} -tr[data-simply-list-icon="fa-unlink"] td:first-child:before, -tr[data-simply-list-icon="fa-chain-broken"] td:first-child:before{content:"\f127"} -tr[data-simply-list-icon="fa-question"] td:first-child:before{content:"\f128"} -tr[data-simply-list-icon="fa-info"] td:first-child:before{content:"\f129"} -tr[data-simply-list-icon="fa-exclamation"] td:first-child:before{content:"\f12a"} -tr[data-simply-list-icon="fa-superscript"] td:first-child:before{content:"\f12b"} -tr[data-simply-list-icon="fa-subscript"] td:first-child:before{content:"\f12c"} -tr[data-simply-list-icon="fa-eraser"] td:first-child:before{content:"\f12d"} -tr[data-simply-list-icon="fa-puzzle-piece"] td:first-child:before{content:"\f12e"} -tr[data-simply-list-icon="fa-microphone"] td:first-child:before{content:"\f130"} -tr[data-simply-list-icon="fa-microphone-slash"] td:first-child:before{content:"\f131"} -tr[data-simply-list-icon="fa-shield"] td:first-child:before{content:"\f132"} -tr[data-simply-list-icon="fa-calendar-o"] td:first-child:before{content:"\f133"} -tr[data-simply-list-icon="fa-fire-extinguisher"] td:first-child:before{content:"\f134"} -tr[data-simply-list-icon="fa-rocket"] td:first-child:before{content:"\f135"} -tr[data-simply-list-icon="fa-maxcdn"] td:first-child:before{content:"\f136"} -tr[data-simply-list-icon="fa-chevron-circle-left"] td:first-child:before{content:"\f137"} -tr[data-simply-list-icon="fa-chevron-circle-right"] td:first-child:before{content:"\f138"} -tr[data-simply-list-icon="fa-chevron-circle-up"] td:first-child:before{content:"\f139"} -tr[data-simply-list-icon="fa-chevron-circle-down"] td:first-child:before{content:"\f13a"} -tr[data-simply-list-icon="fa-html5"] td:first-child:before{content:"\f13b"} -tr[data-simply-list-icon="fa-css3"] td:first-child:before{content:"\f13c"} -tr[data-simply-list-icon="fa-anchor"] td:first-child:before{content:"\f13d"} -tr[data-simply-list-icon="fa-unlock-alt"] td:first-child:before{content:"\f13e"} -tr[data-simply-list-icon="fa-bullseye"] td:first-child:before{content:"\f140"} -tr[data-simply-list-icon="fa-ellipsis-h"] td:first-child:before{content:"\f141"} -tr[data-simply-list-icon="fa-ellipsis-v"] td:first-child:before{content:"\f142"} -tr[data-simply-list-icon="fa-rss-square"] td:first-child:before{content:"\f143"} -tr[data-simply-list-icon="fa-play-circle"] td:first-child:before{content:"\f144"} -tr[data-simply-list-icon="fa-ticket"] td:first-child:before{content:"\f145"} -tr[data-simply-list-icon="fa-minus-square"] td:first-child:before{content:"\f146"} -tr[data-simply-list-icon="fa-minus-square-o"] td:first-child:before{content:"\f147"} -tr[data-simply-list-icon="fa-level-up"] td:first-child:before{content:"\f148"} -tr[data-simply-list-icon="fa-level-down"] td:first-child:before{content:"\f149"} -tr[data-simply-list-icon="fa-check-square"] td:first-child:before{content:"\f14a"} -tr[data-simply-list-icon="fa-pencil-square"] td:first-child:before{content:"\f14b"} -tr[data-simply-list-icon="fa-external-link-square"] td:first-child:before{content:"\f14c"} -tr[data-simply-list-icon="fa-share-square"] td:first-child:before{content:"\f14d"} -tr[data-simply-list-icon="fa-compass"] td:first-child:before{content:"\f14e"} -tr[data-simply-list-icon="fa-toggle-down"] td:first-child:before, -tr[data-simply-list-icon="fa-caret-square-o-down"] td:first-child:before{content:"\f150"} -tr[data-simply-list-icon="fa-toggle-up"] td:first-child:before, -tr[data-simply-list-icon="fa-caret-square-o-up"] td:first-child:before{content:"\f151"} -tr[data-simply-list-icon="fa-toggle-right"] td:first-child:before, -tr[data-simply-list-icon="fa-caret-square-o-right"] td:first-child:before{content:"\f152"} -tr[data-simply-list-icon="fa-euro"] td:first-child:before, -tr[data-simply-list-icon="fa-eur"] td:first-child:before{content:"\f153"} -tr[data-simply-list-icon="fa-gbp"] td:first-child:before{content:"\f154"} -tr[data-simply-list-icon="fa-dollar"] td:first-child:before, -tr[data-simply-list-icon="fa-usd"] td:first-child:before{content:"\f155"} -tr[data-simply-list-icon="fa-rupee"] td:first-child:before, -tr[data-simply-list-icon="fa-inr"] td:first-child:before{content:"\f156"} -tr[data-simply-list-icon="fa-cny"] td:first-child:before, -tr[data-simply-list-icon="fa-rmb"] td:first-child:before, -tr[data-simply-list-icon="fa-yen"] td:first-child:before, -tr[data-simply-list-icon="fa-jpy"] td:first-child:before{content:"\f157"} -tr[data-simply-list-icon="fa-ruble"] td:first-child:before, -tr[data-simply-list-icon="fa-rouble"] td:first-child:before, -tr[data-simply-list-icon="fa-rub"] td:first-child:before{content:"\f158"} -tr[data-simply-list-icon="fa-won"] td:first-child:before, -tr[data-simply-list-icon="fa-krw"] td:first-child:before{content:"\f159"} -tr[data-simply-list-icon="fa-bitcoin"] td:first-child:before, -tr[data-simply-list-icon="fa-btc"] td:first-child:before{content:"\f15a"} -tr[data-simply-list-icon="fa-file"] td:first-child:before{content:"\f15b"} -tr[data-simply-list-icon="fa-file-text"] td:first-child:before{content:"\f15c"} -tr[data-simply-list-icon="fa-sort-alpha-asc"] td:first-child:before{content:"\f15d"} -tr[data-simply-list-icon="fa-sort-alpha-desc"] td:first-child:before{content:"\f15e"} -tr[data-simply-list-icon="fa-sort-amount-asc"] td:first-child:before{content:"\f160"} -tr[data-simply-list-icon="fa-sort-amount-desc"] td:first-child:before{content:"\f161"} -tr[data-simply-list-icon="fa-sort-numeric-asc"] td:first-child:before{content:"\f162"} -tr[data-simply-list-icon="fa-sort-numeric-desc"] td:first-child:before{content:"\f163"} -tr[data-simply-list-icon="fa-thumbs-up"] td:first-child:before{content:"\f164"} -tr[data-simply-list-icon="fa-thumbs-down"] td:first-child:before{content:"\f165"} -tr[data-simply-list-icon="fa-youtube-square"] td:first-child:before{content:"\f166"} -tr[data-simply-list-icon="fa-youtube"] td:first-child:before{content:"\f167"} -tr[data-simply-list-icon="fa-xing"] td:first-child:before{content:"\f168"} -tr[data-simply-list-icon="fa-xing-square"] td:first-child:before{content:"\f169"} -tr[data-simply-list-icon="fa-youtube-play"] td:first-child:before{content:"\f16a"} -tr[data-simply-list-icon="fa-dropbox"] td:first-child:before{content:"\f16b"} -tr[data-simply-list-icon="fa-stack-overflow"] td:first-child:before{content:"\f16c"} -tr[data-simply-list-icon="fa-instagram"] td:first-child:before{content:"\f16d"} -tr[data-simply-list-icon="fa-flickr"] td:first-child:before{content:"\f16e"} -tr[data-simply-list-icon="fa-adn"] td:first-child:before{content:"\f170"} -tr[data-simply-list-icon="fa-bitbucket"] td:first-child:before{content:"\f171"} -tr[data-simply-list-icon="fa-bitbucket-square"] td:first-child:before{content:"\f172"} -tr[data-simply-list-icon="fa-tumblr"] td:first-child:before{content:"\f173"} -tr[data-simply-list-icon="fa-tumblr-square"] td:first-child:before{content:"\f174"} -tr[data-simply-list-icon="fa-long-arrow-down"] td:first-child:before{content:"\f175"} -tr[data-simply-list-icon="fa-long-arrow-up"] td:first-child:before{content:"\f176"} -tr[data-simply-list-icon="fa-long-arrow-left"] td:first-child:before{content:"\f177"} -tr[data-simply-list-icon="fa-long-arrow-right"] td:first-child:before{content:"\f178"} -tr[data-simply-list-icon="fa-apple"] td:first-child:before{content:"\f179"} -tr[data-simply-list-icon="fa-windows"] td:first-child:before{content:"\f17a"} -tr[data-simply-list-icon="fa-android"] td:first-child:before{content:"\f17b"} -tr[data-simply-list-icon="fa-linux"] td:first-child:before{content:"\f17c"} -tr[data-simply-list-icon="fa-dribbble"] td:first-child:before{content:"\f17d"} -tr[data-simply-list-icon="fa-skype"] td:first-child:before{content:"\f17e"} -tr[data-simply-list-icon="fa-foursquare"] td:first-child:before{content:"\f180"} -tr[data-simply-list-icon="fa-trello"] td:first-child:before{content:"\f181"} -tr[data-simply-list-icon="fa-female"] td:first-child:before{content:"\f182"} -tr[data-simply-list-icon="fa-male"] td:first-child:before{content:"\f183"} -tr[data-simply-list-icon="fa-gittip"] td:first-child:before, -tr[data-simply-list-icon="fa-gratipay"] td:first-child:before{content:"\f184"} -tr[data-simply-list-icon="fa-sun-o"] td:first-child:before{content:"\f185"} -tr[data-simply-list-icon="fa-moon-o"] td:first-child:before{content:"\f186"} -tr[data-simply-list-icon="fa-archive"] td:first-child:before{content:"\f187"} -tr[data-simply-list-icon="fa-bug"] td:first-child:before{content:"\f188"} -tr[data-simply-list-icon="fa-vk"] td:first-child:before{content:"\f189"} -tr[data-simply-list-icon="fa-weibo"] td:first-child:before{content:"\f18a"} -tr[data-simply-list-icon="fa-renren"] td:first-child:before{content:"\f18b"} -tr[data-simply-list-icon="fa-pagelines"] td:first-child:before{content:"\f18c"} -tr[data-simply-list-icon="fa-stack-exchange"] td:first-child:before{content:"\f18d"} -tr[data-simply-list-icon="fa-arrow-circle-o-right"] td:first-child:before{content:"\f18e"} -tr[data-simply-list-icon="fa-arrow-circle-o-left"] td:first-child:before{content:"\f190"} -tr[data-simply-list-icon="fa-toggle-left"] td:first-child:before, -tr[data-simply-list-icon="fa-caret-square-o-left"] td:first-child:before{content:"\f191"} -tr[data-simply-list-icon="fa-dot-circle-o"] td:first-child:before{content:"\f192"} -tr[data-simply-list-icon="fa-wheelchair"] td:first-child:before{content:"\f193"} -tr[data-simply-list-icon="fa-vimeo-square"] td:first-child:before{content:"\f194"} -tr[data-simply-list-icon="fa-turkish-lira"] td:first-child:before, -tr[data-simply-list-icon="fa-try"] td:first-child:before{content:"\f195"} -tr[data-simply-list-icon="fa-plus-square-o"] td:first-child:before{content:"\f196"} -tr[data-simply-list-icon="fa-space-shuttle"] td:first-child:before{content:"\f197"} -tr[data-simply-list-icon="fa-slack"] td:first-child:before{content:"\f198"} -tr[data-simply-list-icon="fa-envelope-square"] td:first-child:before{content:"\f199"} -tr[data-simply-list-icon="fa-wordpress"] td:first-child:before{content:"\f19a"} -tr[data-simply-list-icon="fa-openid"] td:first-child:before{content:"\f19b"} -tr[data-simply-list-icon="fa-institution"] td:first-child:before, -tr[data-simply-list-icon="fa-bank"] td:first-child:before, -tr[data-simply-list-icon="fa-university"] td:first-child:before{content:"\f19c"} -tr[data-simply-list-icon="fa-mortar-board"] td:first-child:before, -tr[data-simply-list-icon="fa-graduation-cap"] td:first-child:before{content:"\f19d"} -tr[data-simply-list-icon="fa-yahoo"] td:first-child:before{content:"\f19e"} -tr[data-simply-list-icon="fa-google"] td:first-child:before{content:"\f1a0"} -tr[data-simply-list-icon="fa-reddit"] td:first-child:before{content:"\f1a1"} -tr[data-simply-list-icon="fa-reddit-square"] td:first-child:before{content:"\f1a2"} -tr[data-simply-list-icon="fa-stumbleupon-circle"] td:first-child:before{content:"\f1a3"} -tr[data-simply-list-icon="fa-stumbleupon"] td:first-child:before{content:"\f1a4"} -tr[data-simply-list-icon="fa-delicious"] td:first-child:before{content:"\f1a5"} -tr[data-simply-list-icon="fa-digg"] td:first-child:before{content:"\f1a6"} -tr[data-simply-list-icon="fa-pied-piper"] td:first-child:before{content:"\f1a7"} -tr[data-simply-list-icon="fa-pied-piper-alt"] td:first-child:before{content:"\f1a8"} -tr[data-simply-list-icon="fa-drupal"] td:first-child:before{content:"\f1a9"} -tr[data-simply-list-icon="fa-joomla"] td:first-child:before{content:"\f1aa"} -tr[data-simply-list-icon="fa-language"] td:first-child:before{content:"\f1ab"} -tr[data-simply-list-icon="fa-fax"] td:first-child:before{content:"\f1ac"} -tr[data-simply-list-icon="fa-building"] td:first-child:before{content:"\f1ad"} -tr[data-simply-list-icon="fa-child"] td:first-child:before{content:"\f1ae"} -tr[data-simply-list-icon="fa-paw"] td:first-child:before{content:"\f1b0"} -tr[data-simply-list-icon="fa-spoon"] td:first-child:before{content:"\f1b1"} -tr[data-simply-list-icon="fa-cube"] td:first-child:before{content:"\f1b2"} -tr[data-simply-list-icon="fa-cubes"] td:first-child:before{content:"\f1b3"} -tr[data-simply-list-icon="fa-behance"] td:first-child:before{content:"\f1b4"} -tr[data-simply-list-icon="fa-behance-square"] td:first-child:before{content:"\f1b5"} -tr[data-simply-list-icon="fa-steam"] td:first-child:before{content:"\f1b6"} -tr[data-simply-list-icon="fa-steam-square"] td:first-child:before{content:"\f1b7"} -tr[data-simply-list-icon="fa-recycle"] td:first-child:before{content:"\f1b8"} -tr[data-simply-list-icon="fa-automobile"] td:first-child:before, -tr[data-simply-list-icon="fa-car"] td:first-child:before{content:"\f1b9"} -tr[data-simply-list-icon="fa-cab"] td:first-child:before, -tr[data-simply-list-icon="fa-taxi"] td:first-child:before{content:"\f1ba"} -tr[data-simply-list-icon="fa-tree"] td:first-child:before{content:"\f1bb"} -tr[data-simply-list-icon="fa-spotify"] td:first-child:before{content:"\f1bc"} -tr[data-simply-list-icon="fa-deviantart"] td:first-child:before{content:"\f1bd"} -tr[data-simply-list-icon="fa-soundcloud"] td:first-child:before{content:"\f1be"} -tr[data-simply-list-icon="fa-database"] td:first-child:before{content:"\f1c0"} -tr[data-simply-list-icon="fa-file-pdf-o"] td:first-child:before{content:"\f1c1"} -tr[data-simply-list-icon="fa-file-word-o"] td:first-child:before{content:"\f1c2"} -tr[data-simply-list-icon="fa-file-excel-o"] td:first-child:before{content:"\f1c3"} -tr[data-simply-list-icon="fa-file-powerpoint-o"] td:first-child:before{content:"\f1c4"} -tr[data-simply-list-icon="fa-file-photo-o"] td:first-child:before, -tr[data-simply-list-icon="fa-file-picture-o"] td:first-child:before, -tr[data-simply-list-icon="fa-file-image-o"] td:first-child:before{content:"\f1c5"} -tr[data-simply-list-icon="fa-file-zip-o"] td:first-child:before, -tr[data-simply-list-icon="fa-file-archive-o"] td:first-child:before{content:"\f1c6"} -tr[data-simply-list-icon="fa-file-sound-o"] td:first-child:before, -tr[data-simply-list-icon="fa-file-audio-o"] td:first-child:before{content:"\f1c7"} -tr[data-simply-list-icon="fa-file-movie-o"] td:first-child:before, -tr[data-simply-list-icon="fa-file-video-o"] td:first-child:before{content:"\f1c8"} -tr[data-simply-list-icon="fa-file-code-o"] td:first-child:before{content:"\f1c9"} -tr[data-simply-list-icon="fa-vine"] td:first-child:before{content:"\f1ca"} -tr[data-simply-list-icon="fa-codepen"] td:first-child:before{content:"\f1cb"} -tr[data-simply-list-icon="fa-jsfiddle"] td:first-child:before{content:"\f1cc"} -tr[data-simply-list-icon="fa-life-bouy"] td:first-child:before, -tr[data-simply-list-icon="fa-life-buoy"] td:first-child:before, -tr[data-simply-list-icon="fa-life-saver"] td:first-child:before, -tr[data-simply-list-icon="fa-support"] td:first-child:before, -tr[data-simply-list-icon="fa-life-ring"] td:first-child:before{content:"\f1cd"} -tr[data-simply-list-icon="fa-circle-o-notch"] td:first-child:before{content:"\f1ce"} -tr[data-simply-list-icon="fa-ra"] td:first-child:before, -tr[data-simply-list-icon="fa-rebel"] td:first-child:before{content:"\f1d0"} -tr[data-simply-list-icon="fa-ge"] td:first-child:before, -tr[data-simply-list-icon="fa-empire"] td:first-child:before{content:"\f1d1"} -tr[data-simply-list-icon="fa-git-square"] td:first-child:before{content:"\f1d2"} -tr[data-simply-list-icon="fa-git"] td:first-child:before{content:"\f1d3"} -tr[data-simply-list-icon="fa-y-combinator-square"] td:first-child:before, -tr[data-simply-list-icon="fa-yc-square"] td:first-child:before, -tr[data-simply-list-icon="fa-hacker-news"] td:first-child:before{content:"\f1d4"} -tr[data-simply-list-icon="fa-tencent-weibo"] td:first-child:before{content:"\f1d5"} -tr[data-simply-list-icon="fa-qq"] td:first-child:before{content:"\f1d6"} -tr[data-simply-list-icon="fa-wechat"] td:first-child:before, -tr[data-simply-list-icon="fa-weixin"] td:first-child:before{content:"\f1d7"} -tr[data-simply-list-icon="fa-send"] td:first-child:before, -tr[data-simply-list-icon="fa-paper-plane"] td:first-child:before{content:"\f1d8"} -tr[data-simply-list-icon="fa-send-o"] td:first-child:before, -tr[data-simply-list-icon="fa-paper-plane-o"] td:first-child:before{content:"\f1d9"} -tr[data-simply-list-icon="fa-history"] td:first-child:before{content:"\f1da"} -tr[data-simply-list-icon="fa-circle-thin"] td:first-child:before{content:"\f1db"} -tr[data-simply-list-icon="fa-header"] td:first-child:before{content:"\f1dc"} -tr[data-simply-list-icon="fa-paragraph"] td:first-child:before{content:"\f1dd"} -tr[data-simply-list-icon="fa-sliders"] td:first-child:before{content:"\f1de"} -tr[data-simply-list-icon="fa-share-alt"] td:first-child:before{content:"\f1e0"} -tr[data-simply-list-icon="fa-share-alt-square"] td:first-child:before{content:"\f1e1"} -tr[data-simply-list-icon="fa-bomb"] td:first-child:before{content:"\f1e2"} -tr[data-simply-list-icon="fa-soccer-ball-o"] td:first-child:before, -tr[data-simply-list-icon="fa-futbol-o"] td:first-child:before{content:"\f1e3"} -tr[data-simply-list-icon="fa-tty"] td:first-child:before{content:"\f1e4"} -tr[data-simply-list-icon="fa-binoculars"] td:first-child:before{content:"\f1e5"} -tr[data-simply-list-icon="fa-plug"] td:first-child:before{content:"\f1e6"} -tr[data-simply-list-icon="fa-slideshare"] td:first-child:before{content:"\f1e7"} -tr[data-simply-list-icon="fa-twitch"] td:first-child:before{content:"\f1e8"} -tr[data-simply-list-icon="fa-yelp"] td:first-child:before{content:"\f1e9"} -tr[data-simply-list-icon="fa-newspaper-o"] td:first-child:before{content:"\f1ea"} -tr[data-simply-list-icon="fa-wifi"] td:first-child:before{content:"\f1eb"} -tr[data-simply-list-icon="fa-calculator"] td:first-child:before{content:"\f1ec"} -tr[data-simply-list-icon="fa-paypal"] td:first-child:before{content:"\f1ed"} -tr[data-simply-list-icon="fa-google-wallet"] td:first-child:before{content:"\f1ee"} -tr[data-simply-list-icon="fa-cc-visa"] td:first-child:before{content:"\f1f0"} -tr[data-simply-list-icon="fa-cc-mastercard"] td:first-child:before{content:"\f1f1"} -tr[data-simply-list-icon="fa-cc-discover"] td:first-child:before{content:"\f1f2"} -tr[data-simply-list-icon="fa-cc-amex"] td:first-child:before{content:"\f1f3"} -tr[data-simply-list-icon="fa-cc-paypal"] td:first-child:before{content:"\f1f4"} -tr[data-simply-list-icon="fa-cc-stripe"] td:first-child:before{content:"\f1f5"} -tr[data-simply-list-icon="fa-bell-slash"] td:first-child:before{content:"\f1f6"} -tr[data-simply-list-icon="fa-bell-slash-o"] td:first-child:before{content:"\f1f7"} -tr[data-simply-list-icon="fa-trash"] td:first-child:before{content:"\f1f8"} -tr[data-simply-list-icon="fa-copyright"] td:first-child:before{content:"\f1f9"} -tr[data-simply-list-icon="fa-at"] td:first-child:before{content:"\f1fa"} -tr[data-simply-list-icon="fa-eyedropper"] td:first-child:before{content:"\f1fb"} -tr[data-simply-list-icon="fa-paint-brush"] td:first-child:before{content:"\f1fc"} -tr[data-simply-list-icon="fa-birthday-cake"] td:first-child:before{content:"\f1fd"} -tr[data-simply-list-icon="fa-area-chart"] td:first-child:before{content:"\f1fe"} -tr[data-simply-list-icon="fa-pie-chart"] td:first-child:before{content:"\f200"} -tr[data-simply-list-icon="fa-line-chart"] td:first-child:before{content:"\f201"} -tr[data-simply-list-icon="fa-lastfm"] td:first-child:before{content:"\f202"} -tr[data-simply-list-icon="fa-lastfm-square"] td:first-child:before{content:"\f203"} -tr[data-simply-list-icon="fa-toggle-off"] td:first-child:before{content:"\f204"} -tr[data-simply-list-icon="fa-toggle-on"] td:first-child:before{content:"\f205"} -tr[data-simply-list-icon="fa-bicycle"] td:first-child:before{content:"\f206"} -tr[data-simply-list-icon="fa-bus"] td:first-child:before{content:"\f207"} -tr[data-simply-list-icon="fa-ioxhost"] td:first-child:before{content:"\f208"} -tr[data-simply-list-icon="fa-angellist"] td:first-child:before{content:"\f209"} -tr[data-simply-list-icon="fa-cc"] td:first-child:before{content:"\f20a"} -tr[data-simply-list-icon="fa-shekel"] td:first-child:before, -tr[data-simply-list-icon="fa-sheqel"] td:first-child:before, -tr[data-simply-list-icon="fa-ils"] td:first-child:before{content:"\f20b"} -tr[data-simply-list-icon="fa-meanpath"] td:first-child:before{content:"\f20c"} -tr[data-simply-list-icon="fa-buysellads"] td:first-child:before{content:"\f20d"} -tr[data-simply-list-icon="fa-connectdevelop"] td:first-child:before{content:"\f20e"} -tr[data-simply-list-icon="fa-dashcube"] td:first-child:before{content:"\f210"} -tr[data-simply-list-icon="fa-forumbee"] td:first-child:before{content:"\f211"} -tr[data-simply-list-icon="fa-leanpub"] td:first-child:before{content:"\f212"} -tr[data-simply-list-icon="fa-sellsy"] td:first-child:before{content:"\f213"} -tr[data-simply-list-icon="fa-shirtsinbulk"] td:first-child:before{content:"\f214"} -tr[data-simply-list-icon="fa-simplybuilt"] td:first-child:before{content:"\f215"} -tr[data-simply-list-icon="fa-skyatlas"] td:first-child:before{content:"\f216"} -tr[data-simply-list-icon="fa-cart-plus"] td:first-child:before{content:"\f217"} -tr[data-simply-list-icon="fa-cart-arrow-down"] td:first-child:before{content:"\f218"} -tr[data-simply-list-icon="fa-diamond"] td:first-child:before{content:"\f219"} -tr[data-simply-list-icon="fa-ship"] td:first-child:before{content:"\f21a"} -tr[data-simply-list-icon="fa-user-secret"] td:first-child:before{content:"\f21b"} -tr[data-simply-list-icon="fa-motorcycle"] td:first-child:before{content:"\f21c"} -tr[data-simply-list-icon="fa-street-view"] td:first-child:before{content:"\f21d"} -tr[data-simply-list-icon="fa-heartbeat"] td:first-child:before{content:"\f21e"} -tr[data-simply-list-icon="fa-venus"] td:first-child:before{content:"\f221"} -tr[data-simply-list-icon="fa-mars"] td:first-child:before{content:"\f222"} -tr[data-simply-list-icon="fa-mercury"] td:first-child:before{content:"\f223"} -tr[data-simply-list-icon="fa-intersex"] td:first-child:before, -tr[data-simply-list-icon="fa-transgender"] td:first-child:before{content:"\f224"} -tr[data-simply-list-icon="fa-transgender-alt"] td:first-child:before{content:"\f225"} -tr[data-simply-list-icon="fa-venus-double"] td:first-child:before{content:"\f226"} -tr[data-simply-list-icon="fa-mars-double"] td:first-child:before{content:"\f227"} -tr[data-simply-list-icon="fa-venus-mars"] td:first-child:before{content:"\f228"} -tr[data-simply-list-icon="fa-mars-stroke"] td:first-child:before{content:"\f229"} -tr[data-simply-list-icon="fa-mars-stroke-v"] td:first-child:before{content:"\f22a"} -tr[data-simply-list-icon="fa-mars-stroke-h"] td:first-child:before{content:"\f22b"} -tr[data-simply-list-icon="fa-neuter"] td:first-child:before{content:"\f22c"} -tr[data-simply-list-icon="fa-genderless"] td:first-child:before{content:"\f22d"} -tr[data-simply-list-icon="fa-facebook-official"] td:first-child:before{content:"\f230"} -tr[data-simply-list-icon="fa-pinterest-p"] td:first-child:before{content:"\f231"} -tr[data-simply-list-icon="fa-whatsapp"] td:first-child:before{content:"\f232"} -tr[data-simply-list-icon="fa-server"] td:first-child:before{content:"\f233"} -tr[data-simply-list-icon="fa-user-plus"] td:first-child:before{content:"\f234"} -tr[data-simply-list-icon="fa-user-times"] td:first-child:before{content:"\f235"} -tr[data-simply-list-icon="fa-hotel"] td:first-child:before, -tr[data-simply-list-icon="fa-bed"] td:first-child:before{content:"\f236"} -tr[data-simply-list-icon="fa-viacoin"] td:first-child:before{content:"\f237"} -tr[data-simply-list-icon="fa-train"] td:first-child:before{content:"\f238"} -tr[data-simply-list-icon="fa-subway"] td:first-child:before{content:"\f239"} -tr[data-simply-list-icon="fa-medium"] td:first-child:before{content:"\f23a"} -tr[data-simply-list-icon="fa-yc"] td:first-child:before, -tr[data-simply-list-icon="fa-y-combinator"] td:first-child:before{content:"\f23b"} -tr[data-simply-list-icon="fa-optin-monster"] td:first-child:before{content:"\f23c"} -tr[data-simply-list-icon="fa-opencart"] td:first-child:before{content:"\f23d"} -tr[data-simply-list-icon="fa-expeditedssl"] td:first-child:before{content:"\f23e"} -tr[data-simply-list-icon="fa-battery-4"] td:first-child:before, -tr[data-simply-list-icon="fa-battery-full"] td:first-child:before{content:"\f240"} -tr[data-simply-list-icon="fa-battery-3"] td:first-child:before, -tr[data-simply-list-icon="fa-battery-three-quarters"] td:first-child:before{content:"\f241"} -tr[data-simply-list-icon="fa-battery-2"] td:first-child:before, -tr[data-simply-list-icon="fa-battery-half"] td:first-child:before{content:"\f242"} -tr[data-simply-list-icon="fa-battery-1"] td:first-child:before, -tr[data-simply-list-icon="fa-battery-quarter"] td:first-child:before{content:"\f243"} -tr[data-simply-list-icon="fa-battery-0"] td:first-child:before, -tr[data-simply-list-icon="fa-battery-empty"] td:first-child:before{content:"\f244"} -tr[data-simply-list-icon="fa-mouse-pointer"] td:first-child:before{content:"\f245"} -tr[data-simply-list-icon="fa-i-cursor"] td:first-child:before{content:"\f246"} -tr[data-simply-list-icon="fa-object-group"] td:first-child:before{content:"\f247"} -tr[data-simply-list-icon="fa-object-ungroup"] td:first-child:before{content:"\f248"} -tr[data-simply-list-icon="fa-sticky-note"] td:first-child:before{content:"\f249"} -tr[data-simply-list-icon="fa-sticky-note-o"] td:first-child:before{content:"\f24a"} -tr[data-simply-list-icon="fa-cc-jcb"] td:first-child:before{content:"\f24b"} -tr[data-simply-list-icon="fa-cc-diners-club"] td:first-child:before{content:"\f24c"} -tr[data-simply-list-icon="fa-clone"] td:first-child:before{content:"\f24d"} -tr[data-simply-list-icon="fa-balance-scale"] td:first-child:before{content:"\f24e"} -tr[data-simply-list-icon="fa-hourglass-o"] td:first-child:before{content:"\f250"} -tr[data-simply-list-icon="fa-hourglass-1"] td:first-child:before, -tr[data-simply-list-icon="fa-hourglass-start"] td:first-child:before{content:"\f251"} -tr[data-simply-list-icon="fa-hourglass-2"] td:first-child:before, -tr[data-simply-list-icon="fa-hourglass-half"] td:first-child:before{content:"\f252"} -tr[data-simply-list-icon="fa-hourglass-3"] td:first-child:before, -tr[data-simply-list-icon="fa-hourglass-end"] td:first-child:before{content:"\f253"} -tr[data-simply-list-icon="fa-hourglass"] td:first-child:before{content:"\f254"} -tr[data-simply-list-icon="fa-hand-grab-o"] td:first-child:before, -tr[data-simply-list-icon="fa-hand-rock-o"] td:first-child:before{content:"\f255"} -tr[data-simply-list-icon="fa-hand-stop-o"] td:first-child:before, -tr[data-simply-list-icon="fa-hand-paper-o"] td:first-child:before{content:"\f256"} -tr[data-simply-list-icon="fa-hand-scissors-o"] td:first-child:before{content:"\f257"} -tr[data-simply-list-icon="fa-hand-lizard-o"] td:first-child:before{content:"\f258"} -tr[data-simply-list-icon="fa-hand-spock-o"] td:first-child:before{content:"\f259"} -tr[data-simply-list-icon="fa-hand-pointer-o"] td:first-child:before{content:"\f25a"} -tr[data-simply-list-icon="fa-hand-peace-o"] td:first-child:before{content:"\f25b"} -tr[data-simply-list-icon="fa-trademark"] td:first-child:before{content:"\f25c"} -tr[data-simply-list-icon="fa-registered"] td:first-child:before{content:"\f25d"} -tr[data-simply-list-icon="fa-creative-commons"] td:first-child:before{content:"\f25e"} -tr[data-simply-list-icon="fa-gg"] td:first-child:before{content:"\f260"} -tr[data-simply-list-icon="fa-gg-circle"] td:first-child:before{content:"\f261"} -tr[data-simply-list-icon="fa-tripadvisor"] td:first-child:before{content:"\f262"} -tr[data-simply-list-icon="fa-odnoklassniki"] td:first-child:before{content:"\f263"} -tr[data-simply-list-icon="fa-odnoklassniki-square"] td:first-child:before{content:"\f264"} -tr[data-simply-list-icon="fa-get-pocket"] td:first-child:before{content:"\f265"} -tr[data-simply-list-icon="fa-wikipedia-w"] td:first-child:before{content:"\f266"} -tr[data-simply-list-icon="fa-safari"] td:first-child:before{content:"\f267"} -tr[data-simply-list-icon="fa-chrome"] td:first-child:before{content:"\f268"} -tr[data-simply-list-icon="fa-firefox"] td:first-child:before{content:"\f269"} -tr[data-simply-list-icon="fa-opera"] td:first-child:before{content:"\f26a"} -tr[data-simply-list-icon="fa-internet-explorer"] td:first-child:before{content:"\f26b"} -tr[data-simply-list-icon="fa-tv"] td:first-child:before, -tr[data-simply-list-icon="fa-television"] td:first-child:before{content:"\f26c"} -tr[data-simply-list-icon="fa-contao"] td:first-child:before{content:"\f26d"} -tr[data-simply-list-icon="fa-500px"] td:first-child:before{content:"\f26e"} -tr[data-simply-list-icon="fa-amazon"] td:first-child:before{content:"\f270"} -tr[data-simply-list-icon="fa-calendar-plus-o"] td:first-child:before{content:"\f271"} -tr[data-simply-list-icon="fa-calendar-minus-o"] td:first-child:before{content:"\f272"} -tr[data-simply-list-icon="fa-calendar-times-o"] td:first-child:before{content:"\f273"} -tr[data-simply-list-icon="fa-calendar-check-o"] td:first-child:before{content:"\f274"} -tr[data-simply-list-icon="fa-industry"] td:first-child:before{content:"\f275"} -tr[data-simply-list-icon="fa-map-pin"] td:first-child:before{content:"\f276"} -tr[data-simply-list-icon="fa-map-signs"] td:first-child:before{content:"\f277"} -tr[data-simply-list-icon="fa-map-o"] td:first-child:before{content:"\f278"} -tr[data-simply-list-icon="fa-map"] td:first-child:before{content:"\f279"} -tr[data-simply-list-icon="fa-commenting"] td:first-child:before{content:"\f27a"} -tr[data-simply-list-icon="fa-commenting-o"] td:first-child:before{content:"\f27b"} -tr[data-simply-list-icon="fa-houzz"] td:first-child:before{content:"\f27c"} -tr[data-simply-list-icon="fa-vimeo"] td:first-child:before{content:"\f27d"} -tr[data-simply-list-icon="fa-black-tie"] td:first-child:before{content:"\f27e"} -tr[data-simply-list-icon="fa-fonticons"] td:first-child:before{content:"\f280"} diff --git a/www/simply/databind.js b/www/simply/databind.js deleted file mode 100644 index 70ddf12..0000000 --- a/www/simply/databind.js +++ /dev/null @@ -1,1037 +0,0 @@ -/* - Two way databinding between a data object and DOM element(s). - A databinding is attached to one data object. It can be bound to one or more elements. - Changes in the element are resolved every x ms; - Changes in the data are resolved to the element directly; - - config options: - data: the data object to be used for databinding. Note that this is the 'outer' object, the databinding itself will be set on data[key]; - key: the key within the data object to be bound - setter: a function that sets the data on the element. A simple example would take the provided value and set it as innerHTML. - getter: a function that fetches the data from an element. Simple example would be "return target.innerHTML"; - mode: "list" of "field"; the only difference between the two is the listeners that are applied to the supplied element. - "list" listens on attribute changes, node insertions and node removals. - "field" listens on attribute changes, subtree modifications. - parentKey: an additional pointer to where the data is bound without your datastructure; use this to keep track of nesting within your data. - attributeFilter: a blacklist of attributes that should not trigger a change in data; - resolve: a function that is called _after_ a change in data has been resolved. The arguments provided to the function are: dataBinding, key, value, oldValue - - Basic usage usage: - var data = { - "title" : "foo" - }; - - var dataBinding = new databinding({ - data : data, - key : title, - setter : function(value) { - this.innerHTML = value; - }, - getter: function() { - return this.innerHTML; - } - }); - - - dataBinding.bind(document.getElementById('title')); - - console.log(data.title); // "foo" - data.title = "Hello world"; // innerHTML for title is changed to 'Hello world'; - console.log(data.title); // "Hello world" - document.getElementById('title').innerHTML = "Bar"; - console.log(data.title); // "Bar" -*/ - -elementBinding = function(element, config, dataBinding) { - var self = this; - this.element = element; - this.dataBinding = dataBinding; - this.element.dataBinding = dataBinding; - this.element.elementBinding = this; - - this.dataBindingConfig = config; - this.unbind = function() { - if (this.dataBinding) { - this.dataBinding.unbind(this); - } - }; - element.dataBindingPaused = 0; - this.elementGetter = (config && typeof config.getter === "function") ? config.getter : this.dataBinding.getter; - this.elementSetter = (config && typeof config.setter === "function") ? config.setter : this.dataBinding.setter; - element.getter = this.elementGetter; - element.setter = this.elementSetter; - - this.getter = function() { - return this.elementGetter.call(element); - }; - this.setter = function(data) { - return this.elementSetter.call(element, data); - }; - - this.addListeners = function() { - this.removeListeners(); - if (typeof this.element.mutationObserver === "undefined") { - this.element.mutationHandler = this.getMutationHandler(this.element); - this.element.mutationObserver = new MutationObserver(this.element.mutationHandler); - } - if (this.dataBinding.mode == "field") { - if (this.element.mutationObserver) { - this.element.mutationObserverConfig = { - attributes: true, - characterData: true, - subtree: true, - childList: true - }; - if (this.element.dataBindingPaused === 0) { - this.element.mutationObserver.observe(this.element, this.element.mutationObserverConfig); - } - } - this.element.addEventListener("change", this.handleEvent); - } - if (this.dataBinding.mode == "list") { - if (this.element.mutationObserver) { - this.element.mutationObserverConfig = { - attributes: true, - childList: true - }; - if (this.element.dataBindingPaused === 0) { - this.element.mutationObserver.observe(this.element, this.element.mutationObserverConfig); - } - } - } - this.element.addEventListener("databinding:valuechanged", this.handleEvent); - this.element.addEventListener("databinding:pause", function() { - this.elementBinding.pauseListeners(); - }); - this.element.addEventListener("databinding:resume", function() { - this.elementBinding.resumeListeners(); - }); - this.element.addEventListener("databind:pause", function() { - this.elementBinding.pauseListeners(); - }); - this.element.addEventListener("databind:resume", function() { - this.elementBinding.resumeListeners(); - }); - }; - - this.removeListeners = function() { - if (this.dataBinding.mode == "field") { - if (this.element.mutationObserver) { - this.element.mutationObserver.disconnect(); - } - this.element.removeEventListener("change", this.handleEvent); - } - if (this.dataBinding.mode == "list") { - if (this.element.mutationObserver) { - this.element.mutationObserver.disconnect(); - } - } - this.element.removeEventListener("databinding:valuechanged", this.handleEvent); - }; - - this.resumeListeners = function() { - this.element.dataBindingPaused--; - if (this.element.dataBindingPaused < 0) { - console.log("Warning: resume called of non-paused databinding"); - this.element.dataBindingPaused = 0; - } - if (this.element.dataBindingPaused === 0) { - if (this.element.mutationObserver) { - this.element.mutationObserver.status = "observing"; - this.element.mutationObserver.observe(this.element, this.element.mutationObserverConfig); - } else { - console.log("Warning: no mutation observer found"); - } - } - }; - this.pauseListeners = function() { - if (this.element.mutationObserver) { - // Disconnecting will flush the queue of records and trash them - if we have things that we need to handle, do so. - this.element.mutationHandler(this.element.mutationObserver.takeRecords()); - this.element.mutationObserver.status = "disconnected"; - this.element.mutationObserver.disconnect(); - } - this.element.dataBindingPaused++; - }; - - this.getMutationHandler = function(target) { - return function(mutations) { - mutations.forEach(function(mutation) { - if (!target.dataBinding) { - return; - } - if (target.dataBindingPaused) { - return; - } - - if (target.dataBinding.paused) { - return; - } - var elementBinding = target.elementBinding; - elementBinding.pauseListeners(); - - if (target.dataBinding.mode == "field") { - switch (mutation.type) { - case "attributes": - if (target.dataBinding.attributeFilter.indexOf(mutation.attributeName) !== -1) { - break; // only handle the attribute mutation if the attribute changed is in our set - } - elementBinding.dataBinding.set(elementBinding.getter()); - break; - case "childList": - break; - default: - // there are needed to keep the focus in an element while typing; - dataBinding.set(elementBinding.getter()); - break; - } - } - if (target.dataBinding.mode == "list") { - switch (mutation.type) { - case "attributes": - if (target.dataBinding.attributeFilter.indexOf(mutation.attributeName) !== -1) { - break; // only handle the attribute mutation if the attribute changed is in our set - } - elementBinding.dataBinding.set(elementBinding.getter()); - break; - case "childList": - mutation.removedNodes.forEach(function(removedNode) { - if (removedNode.nodeType != document.ELEMENT_NODE) { - return; - } - if (removedNode.simplyRemoved) { - return; - } - if (typeof removedNode.simplyListIndex === "undefined") { - return; - } - removedNode.simplyRemoved = true; - // find the index of the removed target node; - data = target.dataBinding.get(); - items = target.querySelectorAll(":scope > [data-simply-list-item]"); - //for (i=0; i [data-simply-list-item]"); - for (i=0; i " + newparent); - value._bindings_[subbinding].parentKey = newparent; - if (value[subbinding] && value[subbinding].length && (typeof value[subbinding] !== "string")) { - for (var i=0; i 5) { - console.log("Warning: databinding resolve loop detected!"); - window.setTimeout(function() { - binding.resolveCounter = 0; - }, 300); // 300 is a guess; could be any other number. It needs to be long enough so that everyone can settle down before we start resolving again. - return true; - } - return false; - }; - - var setElements = function() { - if (binding.elementTimer) { - window.clearTimeout(binding.elementTimer); - } - for (var i=0; i -1) { - element.removeListeners(); - binding.elements.splice(binding.elements.indexOf(element), 1); - } - }; - - this.cleanupBindings = function() { - if (binding.elements.length < 2) { - return; - } - - binding.elements.forEach(function(element) { - if (!element.isInDocument()) { - element.markedForRemoval = true; - } else { - element.markedForRemoval = false; - } - }); - - if (binding.cleanupTimer) { - clearTimeout(binding.cleanupTimer); - } - - binding.cleanupTimer = window.setTimeout(function() { - binding.elements.filter(function(element) { - if (element.markedForRemoval && !element.isInDocument()) { - element.dataBinding.unbind(element); - return false; - } - element.markedForRemoval = false; - return true; - }); - }, 1000); // If after 1 second the element is still not in the dom, remove the binding; - }; - - initBindings(data, key); - // Call the custom init function, if it is there; - if (typeof binding.config.init === "function") { - binding.config.init.call(binding); - } - - if (binding.mode == "list") { - document.addEventListener("databind:resolved", function() { - if (!binding.skipOldValueUpdate) { - oldValue = dereference(binding.get()); - } - }); - } -}; - -dataBinding.prototype.resumeListeners = function(element) { - element.dataBindingPaused--; - if (element.dataBindingPaused < 0) { - console.log("Warning: resume called of non-paused databinding"); - element.dataBindingPaused = 0; - } - if (element.dataBindingPaused === 0) { - if (element.mutationObserver) { - element.mutationObserver.observe(element, element.mutationObserverConfig); - element.mutationObserver.status = "observing"; - } else { - console.log("Warning: no mutation observer found"); - } - } -}; -dataBinding.prototype.pauseListeners = function(element) { - element.dataBindingPaused++; - if (element.mutationObserver) { - element.mutationObserver.status = "disconnected"; - element.mutationObserver.disconnect(); - } -}; - -// Housekeeping, remove references to deleted nodes -var removalObserver = new MutationObserver(function(mutations) { - mutations.forEach(function(mutation) { - if (mutation.type == "childList") { - mutation.removedNodes.forEach(function(target) { - if (target.nodeType != document.ELEMENT_NODE) { // We don't care about removed text nodes; - return; - } - if (!target.dataBinding) { // nor any element that doesn't have a databinding; - return; - } - window.setTimeout(function() { // chrome sometimes 'helpfully' removes the element and then inserts it back, probably as a rendering optimalization. We're fine cleaning up in a bit, if still needed. - if (!target.parentNode && target.dataBinding && target.elementBinding) { - target.dataBinding.unbind(target.elementBinding); - // if (target.dataBinding.mode == "field") { - // target.dataBinding.set(); - // } - delete target.dataBinding; - } - }, 400); - }); - } - }); -}); - -removalObserver.observe(document.body, { - "childList" : true, - "subtree" : true -}); - -// polyfill to add :scope selector for IE -(function() { - if (!HTMLElement.prototype.querySelectorAll) { - throw new Error('rootedQuerySelectorAll: This polyfill can only be used with browsers that support querySelectorAll'); - } - - // A temporary element to query against for elements not currently in the DOM - // We'll also use this element to test for :scope support - var container = document.createElement('div'); - - // Check if the browser supports :scope - try { - // Browser supports :scope, do nothing - container.querySelectorAll(':scope *'); - } - catch (e) { - // Match usage of scope - var scopeRE = /\s*:scope/gi; - - // Overrides - function overrideNodeMethod(prototype, methodName) { - // Store the old method for use later - var oldMethod = prototype[methodName]; - - // Override the method - prototype[methodName] = function(query) { - var nodeList, - gaveId = false, - gaveContainer = false; - - if (query.match(scopeRE)) { - if (!this.parentNode) { - // Add to temporary container - container.appendChild(this); - gaveContainer = true; - } - - parentNode = this.parentNode; - - if (!this.id) { - // Give temporary ID - this.id = 'rootedQuerySelector_id_'+(new Date()).getTime(); - gaveId = true; - } - - // Remove :scope - query = query.replace(scopeRE, '#' + this.id + " "); - - // Find elements against parent node - // nodeList = oldMethod.call(parentNode, '#'+this.id+' '+query); - nodeList = parentNode[methodName](query); - // Reset the ID - if (gaveId) { - this.id = ''; - } - - // Remove from temporary container - if (gaveContainer) { - container.removeChild(this); - } - - return nodeList; - } - else { - // No immediate child selector used - return oldMethod.call(this, query); - } - }; - } - - // Browser doesn't support :scope, add polyfill - overrideNodeMethod(HTMLElement.prototype, 'querySelector'); - overrideNodeMethod(HTMLElement.prototype, 'querySelectorAll'); - } -}()); diff --git a/www/simply/diff_match_patch.js b/www/simply/diff_match_patch.js deleted file mode 100644 index 0428b18..0000000 --- a/www/simply/diff_match_patch.js +++ /dev/null @@ -1,76 +0,0 @@ -/** - * Diff Match and Patch - * - * Copyright 2006 Google Inc. - * http://code.google.com/p/google-diff-match-patch/ - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @fileoverview Computes the difference between two texts to create a patch. - * Applies the patch onto another text, allowing for errors. - * @author fraser@google.com (Neil Fraser) - */ - -// jshint ignore: start - -(function(){function diff_match_patch(){this.Diff_Timeout=1;this.Diff_EditCost=4;this.Match_Threshold=0.5;this.Match_Distance=1E3;this.Patch_DeleteThreshold=0.5;this.Patch_Margin=4;this.Match_MaxBits=32} -diff_match_patch.prototype.diff_main=function(a,b,c,d){"undefined"==typeof d&&(d=0>=this.Diff_Timeout?Number.MAX_VALUE:(new Date).getTime()+1E3*this.Diff_Timeout);if(null==a||null==b)throw Error("Null input. (diff_main)");if(a==b)return a?[[0,a]]:[];"undefined"==typeof c&&(c=!0);var e=c,f=this.diff_commonPrefix(a,b);c=a.substring(0,f);a=a.substring(f);b=b.substring(f);var f=this.diff_commonSuffix(a,b),g=a.substring(a.length-f);a=a.substring(0,a.length-f);b=b.substring(0,b.length-f);a=this.diff_compute_(a, -b,e,d);c&&a.unshift([0,c]);g&&a.push([0,g]);this.diff_cleanupMerge(a);return a}; -diff_match_patch.prototype.diff_compute_=function(a,b,c,d){if(!a)return[[1,b]];if(!b)return[[-1,a]];var e=a.length>b.length?a:b,f=a.length>b.length?b:a,g=e.indexOf(f);return-1!=g?(c=[[1,e.substring(0,g)],[0,f],[1,e.substring(g+f.length)]],a.length>b.length&&(c[0][0]=c[2][0]=-1),c):1==f.length?[[-1,a],[1,b]]:(e=this.diff_halfMatch_(a,b))?(f=e[0],a=e[1],g=e[2],b=e[3],e=e[4],f=this.diff_main(f,g,c,d),c=this.diff_main(a,b,c,d),f.concat([[0,e]],c)):c&&100c);v++){for(var n=-v+r;n<=v-t;n+=2){var l=g+n,m;m=n==-v||n!=v&&j[l-1]d)t+=2;else if(s>e)r+=2;else if(q&&(l=g+k-n,0<=l&&l= -u)return this.diff_bisectSplit_(a,b,m,s,c)}}for(n=-v+p;n<=v-w;n+=2){l=g+n;u=n==-v||n!=v&&i[l-1]d)w+=2;else if(m>e)p+=2;else if(!q&&(l=g+k-n,0<=l&&(l=u)))return this.diff_bisectSplit_(a,b,m,s,c)}}return[[-1,a],[1,b]]}; -diff_match_patch.prototype.diff_bisectSplit_=function(a,b,c,d,e){var f=a.substring(0,c),g=b.substring(0,d);a=a.substring(c);b=b.substring(d);f=this.diff_main(f,g,!1,e);e=this.diff_main(a,b,!1,e);return f.concat(e)}; -diff_match_patch.prototype.diff_linesToChars_=function(a,b){function c(a){for(var b="",c=0,f=-1,g=d.length;fd?a=a.substring(c-d):c=a.length?[h,j,n,l,g]:null}if(0>=this.Diff_Timeout)return null; -var d=a.length>b.length?a:b,e=a.length>b.length?b:a;if(4>d.length||2*e.lengthd[4].length?g:d:d:g;var j;a.length>b.length?(g=h[0],d=h[1],e=h[2],j=h[3]):(e=h[0],j=h[1],g=h[2],d=h[3]);h=h[4];return[g,d,e,j,h]}; -diff_match_patch.prototype.diff_cleanupSemantic=function(a){for(var b=!1,c=[],d=0,e=null,f=0,g=0,h=0,j=0,i=0;f=e){if(d>=b.length/2||d>=c.length/2)a.splice(f,0,[0,c.substring(0,d)]),a[f-1][1]=b.substring(0,b.length-d),a[f+1][1]=c.substring(d),f++}else if(e>=b.length/2||e>=c.length/2)a.splice(f,0,[0,b.substring(0,e)]),a[f-1][0]=1,a[f-1][1]=c.substring(0,c.length-e),a[f+1][0]=-1,a[f+1][1]=b.substring(e),f++;f++}f++}}; -diff_match_patch.prototype.diff_cleanupSemanticLossless=function(a){function b(a,b){if(!a||!b)return 6;var c=a.charAt(a.length-1),d=b.charAt(0),e=c.match(diff_match_patch.nonAlphaNumericRegex_),f=d.match(diff_match_patch.nonAlphaNumericRegex_),g=e&&c.match(diff_match_patch.whitespaceRegex_),h=f&&d.match(diff_match_patch.whitespaceRegex_),c=g&&c.match(diff_match_patch.linebreakRegex_),d=h&&d.match(diff_match_patch.linebreakRegex_),i=c&&a.match(diff_match_patch.blanklineEndRegex_),j=d&&b.match(diff_match_patch.blanklineStartRegex_); -return i||j?5:c||d?4:e&&!g&&h?3:g||h?2:e||f?1:0}for(var c=1;c=i&&(i=k,g=d,h=e,j=f)}a[c-1][1]!=g&&(g?a[c-1][1]=g:(a.splice(c-1,1),c--),a[c][1]= -h,j?a[c+1][1]=j:(a.splice(c+1,1),c--))}c++}};diff_match_patch.nonAlphaNumericRegex_=/[^a-zA-Z0-9]/;diff_match_patch.whitespaceRegex_=/\s/;diff_match_patch.linebreakRegex_=/[\r\n]/;diff_match_patch.blanklineEndRegex_=/\n\r?\n$/;diff_match_patch.blanklineStartRegex_=/^\r?\n\r?\n/; -diff_match_patch.prototype.diff_cleanupEfficiency=function(a){for(var b=!1,c=[],d=0,e=null,f=0,g=!1,h=!1,j=!1,i=!1;fb)break;e=c;f=d}return a.length!=g&&-1===a[g][0]?f:f+(b-e)}; -diff_match_patch.prototype.diff_prettyHtml=function(a){for(var b=[],c=/&/g,d=//g,f=/\n/g,g=0;g");switch(h){case 1:b[g]=''+j+"";break;case -1:b[g]=''+j+"";break;case 0:b[g]=""+j+""}}return b.join("")}; -diff_match_patch.prototype.diff_text1=function(a){for(var b=[],c=0;cthis.Match_MaxBits)throw Error("Pattern too long for this browser.");var e=this.match_alphabet_(b),f=this,g=this.Match_Threshold,h=a.indexOf(b,c);-1!=h&&(g=Math.min(d(0,h),g),h=a.lastIndexOf(b,c+b.length),-1!=h&&(g=Math.min(d(0,h),g)));for(var j=1<=i;p--){var w=e[a.charAt(p-1)];k[p]=0===t?(k[p+1]<<1|1)&w:(k[p+1]<<1|1)&w|((r[p+1]|r[p])<<1|1)|r[p+1];if(k[p]&j&&(w=d(t,p-1),w<=g))if(g=w,h=p-1,h>c)i=Math.max(1,2*c-h);else break}if(d(t+1,c)>g)break;r=k}return h}; -diff_match_patch.prototype.match_alphabet_=function(a){for(var b={},c=0;c=2*this.Patch_Margin&& -e&&(this.patch_addContext_(a,h),c.push(a),a=new diff_match_patch.patch_obj,e=0,h=d,f=g)}1!==i&&(f+=k.length);-1!==i&&(g+=k.length)}e&&(this.patch_addContext_(a,h),c.push(a));return c};diff_match_patch.prototype.patch_deepCopy=function(a){for(var b=[],c=0;cthis.Match_MaxBits){if(j=this.match_main(b,h.substring(0,this.Match_MaxBits),g),-1!=j&&(i=this.match_main(b,h.substring(h.length-this.Match_MaxBits),g+h.length-this.Match_MaxBits),-1==i||j>=i))j=-1}else j=this.match_main(b,h,g); -if(-1==j)e[f]=!1,d-=a[f].length2-a[f].length1;else if(e[f]=!0,d=j-g,g=-1==i?b.substring(j,j+h.length):b.substring(j,i+this.Match_MaxBits),h==g)b=b.substring(0,j)+this.diff_text2(a[f].diffs)+b.substring(j+h.length);else if(g=this.diff_main(h,g,!1),h.length>this.Match_MaxBits&&this.diff_levenshtein(g)/h.length>this.Patch_DeleteThreshold)e[f]=!1;else{this.diff_cleanupSemanticLossless(g);for(var h=0,k,i=0;ie[0][1].length){var f=b-e[0][1].length;e[0][1]=c.substring(e[0][1].length)+e[0][1];d.start1-=f;d.start2-=f;d.length1+=f;d.length2+=f}d=a[a.length-1];e=d.diffs;0==e.length||0!=e[e.length-1][0]?(e.push([0, -c]),d.length1+=b,d.length2+=b):b>e[e.length-1][1].length&&(f=b-e[e.length-1][1].length,e[e.length-1][1]+=c.substring(0,f),d.length1+=f,d.length2+=f);return c}; -diff_match_patch.prototype.patch_splitMax=function(a){for(var b=this.Match_MaxBits,c=0;c2*b?(h.length1+=i.length,e+=i.length,j=!1,h.diffs.push([g,i]),d.diffs.shift()):(i=i.substring(0,b-h.length1-this.Patch_Margin),h.length1+=i.length,e+=i.length,0===g?(h.length2+=i.length,f+=i.length):j=!1,h.diffs.push([g,i]),i==d.diffs[0][1]?d.diffs.shift():d.diffs[0][1]=d.diffs[0][1].substring(i.length))}g=this.diff_text2(h.diffs);g=g.substring(g.length-this.Patch_Margin);i=this.diff_text1(d.diffs).substring(0,this.Patch_Margin);""!==i&& -(h.length1+=i.length,h.length2+=i.length,0!==h.diffs.length&&0===h.diffs[h.diffs.length-1][0]?h.diffs[h.diffs.length-1][1]+=i:h.diffs.push([0,i]));j||a.splice(++c,0,h)}}};diff_match_patch.prototype.patch_toText=function(a){for(var b=[],c=0;c toolbar.simply-basepack.html \ No newline at end of file diff --git a/www/simply/plugin.simply-about.html b/www/simply/plugin.simply-about.html deleted file mode 100755 index 29f5a29..0000000 --- a/www/simply/plugin.simply-about.html +++ /dev/null @@ -1,191 +0,0 @@ -
-
-
    -
  • -
  • -
  • -
  • -
  • -
-
-
- -
-
-
Your key
-
Valid for
-
- -
-
-
- -
-
-
- - - -
- -
-
-
- - diff --git a/www/simply/plugin.simply-baseurl.html b/www/simply/plugin.simply-baseurl.html deleted file mode 100644 index cd4b12f..0000000 --- a/www/simply/plugin.simply-baseurl.html +++ /dev/null @@ -1,52 +0,0 @@ - \ No newline at end of file diff --git a/www/simply/plugin.simply-browse.html b/www/simply/plugin.simply-browse.html deleted file mode 100644 index fc7bd62..0000000 --- a/www/simply/plugin.simply-browse.html +++ /dev/null @@ -1,934 +0,0 @@ - -
-
-
    - -
  • -
  • -
  • -
  • - - -
  • - - -
  • -
  • -
-
-
-
-
- - diff --git a/www/simply/plugin.simply-diff.html b/www/simply/plugin.simply-diff.html deleted file mode 100644 index 8448424..0000000 --- a/www/simply/plugin.simply-diff.html +++ /dev/null @@ -1,284 +0,0 @@ - -
-
-
    -
  • -
  • -
  • -
  • - -
  • - -
-
-
-
-
Theirs
-
Mine
-
-
-
-
    -
  • Review the differences and choose which of them to use.
  • -
  • -
-
-
- diff --git a/www/simply/plugin.simply-dropbox.html b/www/simply/plugin.simply-dropbox.html deleted file mode 100644 index 60a86f8..0000000 --- a/www/simply/plugin.simply-dropbox.html +++ /dev/null @@ -1,48 +0,0 @@ - - \ No newline at end of file diff --git a/www/simply/plugin.simply-htmlsource.html b/www/simply/plugin.simply-htmlsource.html deleted file mode 100644 index f5069fe..0000000 --- a/www/simply/plugin.simply-htmlsource.html +++ /dev/null @@ -1,190 +0,0 @@ -
-
-
    -
  • - -
  • -
  • -
-
-
- -
-
-
    - -
  • -
-
-
- - diff --git a/www/simply/plugin.simply-keyboard.html b/www/simply/plugin.simply-keyboard.html deleted file mode 100644 index 1c349bc..0000000 --- a/www/simply/plugin.simply-keyboard.html +++ /dev/null @@ -1,170 +0,0 @@ - \ No newline at end of file diff --git a/www/simply/plugin.simply-login.html b/www/simply/plugin.simply-login.html deleted file mode 100644 index b3957c7..0000000 --- a/www/simply/plugin.simply-login.html +++ /dev/null @@ -1,67 +0,0 @@ -
-
-

-
-
- - -
-
- - -
- -
-
- diff --git a/www/simply/plugin.simply-meta.html b/www/simply/plugin.simply-meta.html deleted file mode 100644 index bc0f961..0000000 --- a/www/simply/plugin.simply-meta.html +++ /dev/null @@ -1,143 +0,0 @@ -
-
-
    -
  • -
  • -
  • -
- -
-
-
    -
  • -
-
-
- - \ No newline at end of file diff --git a/www/simply/plugin.simply-paste.html b/www/simply/plugin.simply-paste.html deleted file mode 100644 index 4be5315..0000000 --- a/www/simply/plugin.simply-paste.html +++ /dev/null @@ -1,362 +0,0 @@ - \ No newline at end of file diff --git a/www/simply/plugin.simply-plain.html b/www/simply/plugin.simply-plain.html deleted file mode 100644 index 72d4c66..0000000 --- a/www/simply/plugin.simply-plain.html +++ /dev/null @@ -1,62 +0,0 @@ - \ No newline at end of file diff --git a/www/simply/plugin.simply-save.html b/www/simply/plugin.simply-save.html deleted file mode 100644 index 1f95452..0000000 --- a/www/simply/plugin.simply-save.html +++ /dev/null @@ -1,86 +0,0 @@ -
-
- -
Saving...
-
Please wait...
-
-
- - diff --git a/www/simply/plugin.simply-scaler.html b/www/simply/plugin.simply-scaler.html deleted file mode 100644 index 61882b9..0000000 --- a/www/simply/plugin.simply-scaler.html +++ /dev/null @@ -1,221 +0,0 @@ - diff --git a/www/simply/plugin.simply-symbol.html b/www/simply/plugin.simply-symbol.html deleted file mode 100644 index 91ac743..0000000 --- a/www/simply/plugin.simply-symbol.html +++ /dev/null @@ -1,133 +0,0 @@ -
-
-
    -
  • -
  • -
-
-
-
-
- - \ No newline at end of file diff --git a/www/simply/plugin.simply-template.html b/www/simply/plugin.simply-template.html deleted file mode 100644 index 6beabc2..0000000 --- a/www/simply/plugin.simply-template.html +++ /dev/null @@ -1,134 +0,0 @@ -
-
-
    -
  • -
  • -
  • -
-
-
- - -
-
- -
-
-
-
-
    -
  • -
-
-
- - \ No newline at end of file diff --git a/www/simply/plugin.simply-undo-redo.html b/www/simply/plugin.simply-undo-redo.html deleted file mode 100644 index 88bb5f1..0000000 --- a/www/simply/plugin.simply-undo-redo.html +++ /dev/null @@ -1,233 +0,0 @@ - \ No newline at end of file diff --git a/www/simply/plugin.toolbar-scroll.html b/www/simply/plugin.toolbar-scroll.html deleted file mode 100644 index 82e9eec..0000000 --- a/www/simply/plugin.toolbar-scroll.html +++ /dev/null @@ -1,103 +0,0 @@ - \ No newline at end of file diff --git a/www/simply/scripts.js b/www/simply/scripts.js deleted file mode 100644 index 384e55b..0000000 --- a/www/simply/scripts.js +++ /dev/null @@ -1,2325 +0,0 @@ -/* - core javascript library for muze modules - ---------------------------------------- - - object namespace(string module, function implementaion) - This method checks if the namespace 'module' is available, and if not - creates it and registers it. It returns the object the namespace points - to, so you can create a shorthand for it. - If you specify an implementation method, this method will be called with - 'this' pointing to the namespace object. - examples: - muze.namespace('muze.test'); - - var myMod = muze.namespace('muze.temp.my.module.with.a.long.name'); - - muze.namespace('muze.test', function() { this.test = function() { alert 'test'; } } ); - - object require(mixed modules, function continuation) - This method checks if the given module is available (registered). - If not, it will try to load the module, if it can or throw an error with the - missing module, and return false. - If it is available, it will return the module object, for a single module. - If a continuation function is supplied, that function will be called if and when the - required namespaces are available. - If you require multiple modules, pass an array with all required modules or a string - with all modules seperated with a ','. Extra spaces will be trimmed of. - You can specify a url for any given module instead of a module name or in addition of - a module name by seperating them with a '|' character: - muze.require('jquery|//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js', ...) - muze.require('//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js', ...) - - muze.require('module.not.available'); - - will throw an error, so you can do this: - - try { - muze.require('muze.event'); - // do stuff - } catch(e) { - // module is not available - } - - or: - - muze.require('muze.event, muze.env', function() { - // do stuff, this function is called in the global scope - }); - - object include(string url, string namespace) - This method checks whether the given namespace is already registered. If - so it doesn't do anything. - If the namespace is not registered (or not entered), it dynamically loads - the url as a javascript object (script tag). - In both cases the method returns the onload handler object. This object - has one method 'onload', which allows you to specify a function that should - be run when the javascript is loaded. This function is also run if the - javascript was already loaded and include didn't actually do anything. - examples: - // this will only load muze.test.js if namespace muze.test isn't already - // loaded and muze.test.js isn't already loaded - muze.include('muze.test.js', 'muze.test').onload(function() { - muze.test.run(); - }); - - // this will load muze.test.js, even if muze.test is already available - // if muze.test.js uses the muze.namespace() method correctly, it - // can then extend muze.test - muze.include('muze.test.js').onload(...); - - // this will load the script if the url isn't already loaded - muze.include('random.script.js').onload(function() { - // script is available but is not registered with a namespace - }) - - mixed load(string url, bool waitforme, bool cached) - This method allows you to easily do ajax calls. If 'waitforme' is true, - the ajax call is done synchronously, and load will return the responseText. - Otherwise the call is done asynchronously, and load will return an onload - handler object, just like include, only in this case the function you - specify in onload will be called with one argument, namely the responseText. - If you set 'cached' to true, the url won't be extended with a timestamp, - allowing the browser to cache the response. - examples: - var response = muze.load('ajax.call.html', true); - - muze.load('ajax.call.html') - .onload(function(response) { - myDiv.innerHTML = response; - }) - .ontimeout( 1000, function() { - myDiv.innerHTML = 'timed out'; - this.clear(); - } ); - - object loader(object) - This method allows you to easily implement your own loader handler, with onload and - ontimeout methods. If you pass an object to loader, the onload handler will be called - with that object defined as this. The ontimeout handler won't, it will allways use the loader as this. - You must keep an internal reference to the loader object and call loader.loaded() manually - to trigger the onload. Any arguments passed to loaded() will be passed on to an onload handler - set throught loader.onload. - If a timeout handler is set through loader.ontimeout(timer, method) than it will be called if - the loader.loaded() method isn't called before the timeout. - example: - function myAjaxyThing() { - var loader = muze.loader(); - // do some stuff - mything.onload = function() { - loader.loaded(response); - } - return loader; - } - methods: - onload(callback) - ontimeout(timer, callback) - loaded() - clear() -*/ - -var muze = this.muze = {}; -muze.global = this; -muze.url = (function() { - var scripts = document.getElementsByTagName('script'); - var index = scripts.length - 1; - var urlHelper = document.createElement('a'); - urlHelper.href = scripts[index].src; - return urlHelper; -})(); - -(function() { - - /* private methods */ - - function _getHTTPObject(cors) { //FIXME: check if rearranged thing work - var xmlhttp = null; - if (typeof XMLHttpRequest == 'undefined') { - if (typeof ActiveXObject != 'undefined') { - try { - xmlhttp = new ActiveXObject("Msxml2.XMLHTTP"); - } catch (e) { - try { - xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); - } catch (E) { - xmlhttp = null; - } - } - } - } else { - try { - if ( cors && typeof XDomainRequest != 'undefined' ) { - xmlhttp = new XDomainRequest(); - } else { - xmlhttp = new XMLHttpRequest(); - } - } catch (e) { - xmlhttp = null; - } - } - return xmlhttp; - } - - function _namespaceWalk( module, handler ) { - var rest = module.replace(/^\s+|\s+$/g, ''); //trim - var name = ''; - var temp = muze.global; - var i = rest.indexOf( '.' ); - while ( i != -1 ) { - name = rest.substring( 0, i ); - if ( !temp[name]) { - temp = handler(temp, name); - if (!temp) { - return temp; - } - } - temp = temp[name]; - rest = rest.substring( i + 1 ); - i = rest.indexOf( '.' ); - } - if ( rest ) { - if ( !temp[rest] ) { - temp = handler(temp, rest); - if (!temp) { - return temp; - } - } - temp = temp[rest]; - } - return temp; - } - - function _namespaceSet( module, object ) { - var rest = module.replace(/^\s+|\s+$/g, ''); //trim - var name = ''; - var temp = muze.global; - var i = rest.indexOf( '.' ); - while ( i != -1 ) { - name = rest.substring( 0, i ); - if ( !temp[name]) { - temp = handler(temp, name); - if (!temp) { - return temp; - } - } - temp = temp[name]; - rest = rest.substring( i + 1 ); - i = rest.indexOf( '.' ); - } - if ( rest ) { - temp[rest] = object; - } - } - - /* private variables */ - - var included = {}; - var registered = {}; - var dependencies= []; - - muze.namespace = function( module, implementation ) { - var moduleInstance = _namespaceWalk( module, function(ob, name) { - ob[name] = {}; - return ob; - }); - registered[module]=true; - if (typeof implementation == 'function') { - var result = implementation.call(moduleInstance); - if ( result ) { - _namespaceSet( module, result ); - moduleInstance = result; - } - } - // call other continuations that depend on this module - // only after remaining code in this module has had a chance to run - // not all modules use an implementation callback method - for ( var p in moduleInstance ) { - if ( moduleInstance.hasOwnProperty(p) ) { - // module is initialized - checkDependencies(); - return moduleInstance; - } - } - // module not yet initialized, so give it time. - muze.global.setTimeout(function() { - checkDependencies(); - }, 1); - return moduleInstance; - }; - - function _parseModuleInfo( moduleInfo ) { - var pipePos = moduleInfo.indexOf('|'); - var slashPos = moduleInfo.indexOf('/'); - var module, url; - - if ( pipePos != -1 ) { - module = moduleInfo.substring(0, pipePos); - url = moduleInfo.substring(pipePos+1); - } else if ( slashPos != -1 ) { - module = false; - url = moduleInfo; - } else { - module = moduleInfo; - url = document.createElement('a'); - url.href = muze.url.href; - if ( url.search.match('muze') ) { - url.search = '?'+module; - } else if ( url.pathname.match('muze.js') ) { - url.pathname = url.pathname.replace('muze.js', module.replace('.','/')+'.js' ); - } else { - url.href = ''; - } - url = url.href; - } - return { - module: module, - url: url - }; - } - - function _parseModulesList( modules ) { - // the continuation is a function which is only run if all requirements are met - var modulesList; - if (typeof modules == 'string') { - modulesList = (/,/.test(modules)) ? modules.split(',') : [ modules ]; - } else if (typeof modules.length != 'undefined') { - modulesList = modules; - } else { - throw('Incorrect argument 1 (required modules): '+modules); - } - var scriptsToCheck = []; - for ( var i=0; i=0; i-- ) { - if ( dependencies[i].continuation ) { - for ( var ii=dependencies[i].scriptsToLoad.length-1; ii>=0; ii-- ) { - var module = dependencies[i].scriptsToLoad[ii].module; - if ( registered[module] ) { - dependencies[i].scriptsToLoad.splice(ii, 1); - // delete dependencies[i].scriptsToLoad[ii]; - } - } - if ( dependencies[i].scriptsToLoad.length === 0 ) { - var continuation = dependencies[i].continuation; - dependencies[i].continuation = false; - continuation.call(muze.global); - } - } - } - } - - muze.require = function( modules, continuation ) { - modules = _parseModulesList( modules ); - var scriptsToLoad = []; - var moduleInstance; - - var moduleWalker = function(module) { - if (module.module) { - moduleInstance = _namespaceWalk( module.module, function(ob, name) { - if (typeof continuation == 'undefined' || !module.url ) { - throw 'namespace ' + name + ' not found '; - } else { - scriptsToLoad[ scriptsToLoad.length ] = module; - } - }); - } else if ( !included[ module.url ] ) { - if (typeof continuation == 'undefined' || !module.url ) { - throw 'namespace ' + name + ' not found '; - } else { - scriptsToLoad[ scriptsToLoad.length ] = module; - } - } - return moduleInstance; - }; - - var result; - for (var i=0; i 1){ - for(var i=1, len=parts.length; i < len; i++){ - camel += parts[i].charAt(0).toUpperCase() + parts[i].substring(1); - } - } - //Cache it and return it - cache[str] = camel; - } - } - return cache[str]; - }; - })(); - - //First argument is the style to be tested (opacity, minHeight, etc.) - //The second argument is an optional argument to test support for a style value (position: fixed) - return function(style, value){ - //get the key that will be used for caching - var key = getKey(style, value); - if(key in cache){ - //If the key exists within the cache, return the held value - return cache[key]; - }else{ - //Default to false, support must be proven - var supported = false; - //Camel-case the style for use against raw objects - var camel = toCamelCase(style); - //If the native runtime style exists than proceed (IE) - if(el.runtimeStyle){ - //We use a try-catch block because IE will throw an error on unsupported style values - try{ - //We set the style against the elements style object and if the value is not supplied we - //default to an empty string (works against all styles) - el.style[camel] = value || ""; - //Unsupported styles and style values will always return undefined - supported = !Env.isUndefined(el.runtimeStyle[camel]); - }catch(e){} - }else{ - //Must be a standards compliant browser (FF, Opera, Safari, Chrome, etc.) - //Set the elements style, if value is not supplied we default to inherit which is supported - //by all standards compliant browsers - el.style[style] = value || "inherit"; - //Get the view for a little short form - var view = document.defaultView; - //If the browser supportes document.defaultView and its getComputedStyle method than proceed - //Currently there is not fallback for this - if(view && view.getComputedStyle){ - //Get the computed style - var cs = view.getComputedStyle(el, "")[camel]; - //Unsupported styles always return undefined - supported = !Env.isUndefined(cs); - //If a value was supplied than we have to test it separately because the getComputedStyle method will often parse the value into - //something much harder to detect i.e. (color: 1px returns rgb(0,0,0)) - if(value){ - //We create a new div as the innerHTML within our main element - //Any hyphenated styles must be supplied in that fashion for these tests(vertical-align not verticalAlign) - //a little syntastic sugar too - el.innerHTML = '
'; - //Unsupported style values will always return an empty string - supported = supported && el.firstChild.style[camel] !== ""; - } - } - } - //Cache the value and return it - cache[key] = supported; - return cache[key]; - } - }; - })(); - - //Does the browser support cookies - //Env.support.cookies = !!navigator.cookieEnabled && navigator.cookieEnabled; - //The above check generates a security violation in IE when used inside a Modal Dialog, hence the adjusted check below - Env.support.cookies = false; - try { - document.cookie="muzeEnvTestCookie=1; path=/"; - Env.support.cookies = (document.cookie.indexOf("muzeEnvTestCookie") != -1) ? true : false; - } catch(e) { - // ipad security error weirdness - } - - //Is the browser in standards mode or quirks mode - Env.support.strict = !!document.compatMode && document.compatMode == "CSS1Compat"; - //Is the current page hosted on a secure server - Env.support.secure = !!window.location.href && window.location.href.toLowerCase().indexOf("https") === 0; - //Does the browser support canvas - Env.support.canvas = !!document.createElement("canvas").getContext; - //Does the browser support SVG - Env.support.svg = !!(document.createElementNS && document.createElementNS('http://www.w3.org/2000/svg', 'svg').width); - //Does the browser XPath queries on the HTML/XHTML document - Env.support.xpath = !!document.evaluate; - - //Does the browser support VML (vector graphics) - //Inspired by Google Maps (http://maps.google.com/intl/en_ALL/mapfiles/73/maps2.api/main.js) - Env.support.vml = (function(){ - //Create an element to act as a container - var el = document.createElement('div'); - //Try adding a VML object via element's innerHTML - el.innerHTML = ''; - //Get the VML object - var vml = el.firstChild; - //Declare VML bevaviour - vml.style.behavior = "url(#default#VML)"; - //If the VML object exists and the attribute is an object than VML is supported - return vml && Env.isObject(vml.adj); - })(); - - //Does the browser support flash - Env.support.flash = (function(){ - //Check for ActiveX first because some versions of IE support navigator.plugins, just not the same as other browsers - if(window.ActiveXObject){ - try{ - //try to create a flash instance - new ActiveXObject("ShockwaveFlash.ShockwaveFlash"); - return true; - }catch(e){} - //If the try-catch fails, return false - return false; - }else if(navigator.plugins){ - //Loop through all the plugins - for(var i=0, length = navigator.plugins.length; i < length; i++){ - //test to see if any plugin names contain the word flash, if so it must support it - return true - if((/flash/gi).test(navigator.plugins[i].name)){ - return true; - } - } - //return false if no plugins match - return false; - } - //Return false if ActiveX and nagivator.plugins are not supported - return false; - })(); - - //Can the browser convert array-like objects (nodelist, arguments) to an array using native methods - Env.support.nativeArrayConversion = (function(){ - try{ - //get the child nodes of the html element - var children = document.documentElement.childNodes; - //hijack the slice and use it for the conversion - make sure the result is an array - return Env.isArray(Array.prototype.slice.call(children)); - }catch(e){} - //return false if the try-catch block fails - return false; - })(); - - //Does the string replace method support functions as a second argument (Safari 2.0.2) - Env.support.stringReplaceFunction = (function(){ - var str = ""; - if(str.replace){ - //If the string equals success as returned by the function, then the replace method of strings must - //accept functions as second parameters, otherwise it is false - return str.replace(str, function(){return 'success';}) === 'success'; - }else{ - //Return false if the strings to not support a replace method - return false; - } - })(); - - //Does the browser allow textnode appending, and eval the text - Env.support.scriptEval = (function(){ - //Create a script element - var script = document.createElement("script"); - try{ - //Try to append a textnode that will hopefully be evaluated and create a new property on the Env namespace - script.appendChild(document.createTextNode("muze.env.test = true;")); - }catch(e){ - //If an exception is caught, it must be IE and not supported - return false; - } - //Append the script to the root element () to allow an eval - document.documentElement.appendChild(script); - //Quickly remove the script - document.documentElement.removeChild(script); - //We are done with the script so we null it out to save memory - script = null; - //Was the eval successful? Does the property exist - var supported = !!Env.test; - //Delete the property - delete Env.test; - //Return the supported value - return supported; - })(); - - //Does the browser allow DOM manipulation of tables via innerHTML - Env.bugs.tableInnerHTML = (function(){ - //Create the table - var el = document.createElement("table"); - try{ - //Use a try catch block because IE throws errors - //Append a row to the innerHTML of the table - el.innerHTML = "test"; - //Query the table for a td element to check if the insert worked - return el.getElementsByTagName('td').length === 0; - }catch(e){} - //The try-catch block fails, there must be a bug - return true; - })(); - - //Does the browser allow DOM manipulation of selects via innerHTML - Env.bugs.selectInnerHTML = (function(){ - //Create the select - var el = document.createElement("select"); - //Try appending to the innerHTML - el.innerHTML = ''; - if(el.options && el.options[0]){ - //Does the option exist within the select, if not there is a bug - return el.options[0].nodeName.toUpperCase() !== "OPTION"; - }else{ - //If no options are found, the insert must have failed - return true; - } - })(); - - Env.bugs.getElementById = (function(){ - //Create a container for everything - var el = document.createElement('div'); - //Create a unique ID for the input we are about to create - var id = "input" + new Date().getTime(); - //Add an input to test a bug with getElementById - el.innerHTML = ''; - //Get the head element - var head = document.getElementsByTagName('head')[0]; - //append the container element to the head - head.appendChild(el); - //Does getElementById return elements with the same defined name - var supported = !Env.isNull(document.getElementById(id)); - //remove the el from the head - head.removeChild(el); - //we are done with the test, null out the element and save memory - el = null; - //return the supported value - return supported; - })(); - - //Create an element to perform various DOM and CSS related capabilities tests against - var el = document.createElement("div"); - //Add an attribute which will later be changed to trigger a mutation event - el.id = new Date().getTime() + Math.random(); - //Quickly create a child node that will be used to test various CSS styles - el.innerHTML = '
'; - //Add a comment node to the element - el.appendChild(document.createComment('test')); - - //Does the browser support cssFloat as the proxy for CSS float - Env.support.cssFloat = "cssFloat" in el.style; - //Does the browser support CSS transforms - Env.support.cssTransform = "WebkitTransform" in el.style || "MozTransform" in el.style; - - - //Change the id to trigger the DOMAttrModified and DOMSubtreeModified (except in Safari) event if it is supported - el.id = new Date().getTime() + Math.random(); - //Create a form element to test a bug in IE - //Alternatively, appending a new element will trigger the DOMSubtreeModified event is it is supported (Safari); - var form = el.appendChild(document.createElement('form')); - //Add an input to test a bug with setting the name attribute - form.innerHTML = ''; - //Get the input element for testing - var input = el.getElementsByTagName('input')[0]; - //try to set the name of the input via setAttribute - input.setAttribute('name', 'test'); - - - //Does getElementsByTagName return comment nodes (IE) - Env.bugs.getElementsByTagName = (function(){ - //Get all descending elements of the root element via "*" - var elements = el.getElementsByTagName('*'); - //Loop the elements and look for comment nodes - for(var i=0, length = elements.length; i < length; i++){ - if(elements[i].nodeType == document.COMMENT_NODE){ - //If a comment node is found, its a bug - return true; - } - } - //If the loop completes without finding any comment nodes then no bug - return false; - })(); - - Env.bugs.querySelectorAll = (function(){ - //Does this browser support querySelectorAll - if(el.querySelectorAll){ - //Safari sometimes doesn't respond to case sensitivity - return el.querySelectorAll(".TEST").length === 0; - }else{ - //If querySelectorAll isn't supported return false for no bug - return false; - } - })(); - - Env.bugs.getElementsByClassName = (function(){ - //Does this browser support getElementsByClassName - if(el.getElementsByClassName){ - //Opera 9.6 doesn't find elements by their second class name - return el.getElementsByClassName("unique").length === 0; - }else{ - //if getElementsByClassName isn't supported return false for no bug - return false; - } - })(); - - Env.bugs.cachedClassNames = (function(){ - //Does this browser support getElementsByClassName - if(el.getElementsByClassName){ - //change the class name of the last element to test - el.firstChild.className = "random"; - //Safari 3.2 caches class names - return el.getElementsByClassName("random").length === 1; - }else{ - //If getElementsByClassName isn't supported return false for no bug - return false; - } - })(); - - - //These tests can only be determined once they are included in the DOM and rendered - //For now we just set them to false, they must be proven - - Env.support.boxModel = false; - Env.bugs.setNameAttribute = false; - - //Env is not ready until a few tests involving insertion into the DOM are performed - Env.ready = false; - //Certain properties need to be added to the DOM and rendered to be tested accurately - //This method can be called manually in your scripts once the DOM has finished loading or it can be left up to the automatic polling for DOM completion - //The option is available because in some cases where the DOM is small (low bytes and less to load time), the poll will not trigger the method and complete - //the tests until, in some cases, after window.onload is fired, so we provide this method to manually invoke the method as a last resort in such a case - Env.onReady = function(){ - if(!Env.ready){ - //Query the DOM for the body - var body = document.getElementsByTagName('body')[0]; - //If the body and appendChild and removeChild methods are recognized, than proceed - if(body && body.appendChild && body.removeChild){ - //append the element to the DOM - body.appendChild(el); - //Is the box model support - Env.support.boxModel = el.firstChild.offsetWidth === 4; - //Query for the input based on the name to see if setAttribute on the name worked - Env.bugs.setNameAttribute = form.elements ? Env.isUndefined(form.elements.test) : false; - //Remove the element from the dom - body.removeChild(el); - //clear the interval - clearTimeout(poll); - //make the elements and the interval null to save memory - el = poll = null; - //All tests are done and Env is ready to be used - Env.ready = true; - } - } - }; - - //poll Env.ready - var poll = setTimeout(Env.onReady, 1); - - //Helper functions purely for testing support of the mutation events - function handler(e){ - Env.support[e.type] = true; - removeEvent(e.target, e.type, arguments.callee); - } - - function addEvent(el, type, fn){ - if(el.addEventListener){ - el.addEventListener(type, fn, false); - }else if(el.attachEvent){ - el.attachEvent("on" + type, fn); - }else{ - el["on"+type] = fn; - } - } - - function removeEvent(el, type, fn){ - if(el.removeEventListener){ - el.removeEventListener(type, fn, false); - }else if(el.detachEvent){ - el.detachEvent('on' + type, fn); - }else{ - el["on"+type] = null; - delete el["on"+type]; - } - } - return Env; -})(); -/* - FIXME: event add/remove via array index laten werken, geen directe functie pointers, alleen indexes in handles array - op die manier krijg je geen circulaire referenties via closures - - javascript events library for muze modules - ---------------------------------------- - - object get(object evt) - This method returns the event object cross browser. You only need this if you don't - use muze.event.attach() to attach your event handler, since it already does this for - you. - - examples: - function myEventHandler(evt) { - evt = muze.event.get(evt); - .... - } - - bool cancel(object evt) - This method cancels the event, stops propagation, prevents default, in short it kills - the event dead. Cross browser. It also returns false, so you may assign it directly - to events you want killed. - - examples: - function myEventHandler(evt) { - ... - if (killEvent == true) { - return muze.event.cancel(evt); - } - ... - } - - document.body.onMouseDown = muze.event.cancel; - - - bool pass(object evt) - This method returns true. So you may use it to make explicit that you don't cancel an event. - - mixed attach(object obj, string event, object handler, bool useCapture) - This method attaches an event handler to an event on an object. It makes sure the event - gets cleaned on unload, so you won't get memory leaks. It makes sure that 'this' points - to the object the event is defined on. Important: Returns the handler required for detaching - the event. This is not the same handler as passed to the attach function! - arguments: - obj DOM object on which to catch the event - event name of the event to catch, e.g. 'load', 'click', etc. - handler function that handles the event. - useCapture Mozilla's useCapture option to addEventListener - examples: - - ... - var detachHandler = muze.event.attach(document.body, 'load', function() { alert(this.innerHTML); }); - ... - - bool detach(object obj, string event, object, handler, bool useCapture) - This method detaches an event handler from an event on an object. - arguments: - obj DOM objeect on which the event handler was attached - event name of the event to remove, e.g. 'load', 'click', etc. - handler handler to detach. - useCapture Mozilla's useCapture option to addEventListener - examples: - - ... - var detachHandler = muze.event.attach(document.body, 'click', function() { alert('we have a click'); }); - ... - muze.event.detach(document.body, 'click', detachHandler); - ... - - - void clean() - This method cleans/removes all attached event handlers. It is automatically run on unload of document, if needed. - - TODO: - custom events met trigger en bind achtige functie, misschien in eigen namespace - -*/ - -muze.require('muze.env', function() { - -muze.namespace('muze.event', function() { - - /* private methods */ - - /* private variables */ - var event = this; - - - var evt; - if (muze.env.isHostMethod(document, 'createEvent')) { - event.create = function( name, maskEvt, win ) { - if (!win) { - win = muze.global; - } - var type = 'HTMLEvents'; - var init = function(evt, mask) { - evt.initEvent(name, mask ? mask.bubbles : true, mask ? mask.cancelable : true); - }; - switch (name) { - case 'click' : - case 'dblclick': - case 'mousedown': - case 'mousemove': - case 'mouseout': - case 'mouseover': - case 'mouseup': - case 'mousewheel': - case 'contextmenu': - case 'DOMMouseScroll': - case 'drag': - case 'dragdrop': - case 'dragend': - case 'dragenter': - case 'dragover': - case 'dragexit': - case 'dragleave': - case 'dragstart': - case 'drop': - type = 'MouseEvents'; - init = function(evt, mask) { - if (mask) { - evt.initMouseEvent(name, mask.bubbles, mask.cancelable, mask.view, mask.detail, mask.screenX, mask.screenY, mask.clientX, mask.clientY, mask.ctrlKey, mask.altKey, mask.shiftKey, mask.metaKey, mask.button, mask.relatedTarget); - } else { - evt.initMouseEvent(name, true, true, win, 0, 0, 0, 0, 0, false, false, false, false, 0, null); - } - }; - break; - case 'DOMFocusIn': - case 'DOMFocusOut': - case 'DOMActivate': - type = 'UIEvents'; - init = function(evt, mask) { - if (mask) { - evt.initUIEvent(name, mask.bubbles, mask.cancelable, mask.view, mask.detail); - } else { - evt.initUIEvent(name, true, true, win, 1); - } - }; - break; - case 'keypress': - case 'keydown': - case 'keyup': - type = 'KeyboardEvents'; - evt = win.document.createEvent( type ); - if (muze.env.isHostMethod(evt, 'initKeyboardEvent')) { - init = function(evt, mask) { - if (mask) { - var modifiers = ''; - if (mask.altKey) { - modifiers += 'Alt '; - } - if (mask.ctrlKey) { - modifiers += 'Control '; - } - if (mask.shiftKey) { - modifiers += 'Shift '; - } - if (mask.metaKey) { - modifiers += 'Meta '; - } - evt.initKeyboardEvent(name, !!mask.bubbles, !!mask.cancelable, mask.view, mask.keyIdentifier, mask.keyLocation, modifiers); - } else { - evt.initKeyboardEvent(name, true, true, win, '', 0, ''); - } - }; - } else if (muze.env.isHostMethod(evt, 'initKeyEvent')) { - init = function(evt, mask) { - if (mask) { - evt.initKeyEvent(name, !!mask.bubbles, !!mask.cancelable, mask.view, mask.ctrlKey, mask.altKey, mask.shiftKey, mask.metaKey, mask.keyCode, mask.charCode); - } else { - evt.initKeyEvent(name, true, true, win, false, false, false, false, 0, 0); - } - }; - } - break; - case 'message': - type = 'MessageEvent'; - init = function(evt, mask) { - if (mask) { - evt.initMessageEvent(name, mask.bubbles, mask.cancelable, mask.data, mask.origin, mask.lastEventId, mask.source, mask.ports); - } else { - evt.initMessageEvent(name, true, true, '', '', '', '', null); - } - }; - break; - } - evt = win.document.createEvent(type); - init(evt, maskEvt); - return evt; - }; - } else if (muze.env.isHostMethod(document, 'createEventObject') ) { - event.create = function( name, evt, win ) { - if (!win) { - win = muze.global; - } - evt = win.document.createEventObject(name, evt); - return evt; - }; - } else { - event.create = false; - } - - if (muze.env.isHostMethod(document, 'dispatchEvent')) { - event.fire = function(el, name, evt) { - var win = muze.global; - if (el.ownerDocument && el.ownerDocument.defaultView) { - win = el.ownerDocument.defaultView; - } else if (el.ownerDocument && el.ownerDocument.parentWindow) { - win = el.ownerDocument.parentWindow; - } - evt = muze.event.create(name, evt, win); - el.dispatchEvent(evt); - }; - } else if (muze.env.isHostMethod(document, 'fireEvent')) { - event.fire = function(el, name, evt) { - if (name.substr(0,3)!=='DOM') { - name = 'on'+name; - } - el.fireEvent(name, evt); - }; - } else { - event.fire = false; - } - - event.get = function(evt, win) { - if ( !win ) { - win = muze.global; - } - if ( !evt ) { - evt = win.event; - } - return evt; - }; - - event.cancel = function(evt) { - event.preventDefault(evt); - event.stopPropagation(evt); - return false; - }; - - event.stopPropagation = function(evt) { - evt = event.get(evt); - if (muze.env.isHostMethod(evt, 'stopPropagation')) { - evt.stopPropagation(); - } else { - evt.cancelBubble = true; - } - }; - - event.preventDefault = function(evt) { - evt = event.get(evt); - if (muze.env.isHostMethod(evt, 'preventDefault')) { - evt.preventDefault(); - } else { - evt.returnValue=false; - } - }; - - event.pass = function(evt) { - return true; - }; - - event.target = function(evt) { - evt = event.get(evt); - if (muze.env.isHostObject(evt, 'target') ) { - return evt.target; - } else if (muze.env.isHostObject(evt, 'srcElement') ) { - return evt.srcElement; - } else { - return null; - } - }; - - event.getCharCode = function(evt) { - evt = event.get(evt); - if (evt.type=='keypress' || evt.type=='onkeypress') { - return (evt.charCode ? evt.charCode : ((evt.keyCode) ? evt.keyCode : evt.which)); - } else { - return false; - } - }; - - var docEl = document.documentElement; - var listeners = []; - - var getWrapper = function( id ) { - return function(evt) { - var win; - var o = listeners[id].el; - if (o.ownerDocument) { - win = o.ownerDocument.defaultView ? o.ownerDocument.defaultView : o.ownerDocument.parentWindow; - } else if (o.defaultView) { - win = o.defaultView; - } else if (o.parentWindow) { - win = o.parentWindow; - } else if (o.document) { - win = o; - } else { - win = muze.global; - } - evt = event.get(evt, win); - var f = listeners[id].listener; - f.call(o, evt); - }; - }; - - if (muze.env.isHostMethod(docEl, 'addEventListener')) { - event.attach = function(o, sEvent, fListener, useCapture) { - if ( !muze.env.isFunction(fListener) ) { - throw { - el : o, - message : 'listener is not a method', - event : sEvent - }; - } - var listenerID = listeners.push( { - el : o, - listener : fListener - } ) - 1; - var wrapped = getWrapper(listenerID); - o.addEventListener(sEvent, wrapped, !!useCapture); - return wrapped; - }; - } else if (muze.env.isHostMethod(docEl, 'attachEvent')) { - event.attach = function(o, sEvent, fListener, useCapture) { - if (!muze.env.isFunction(fListener)) { - throw { - el : o, - message : 'listener is not a method', - event : sEvent - }; - } - var listenerID = listeners.push( { - el : o, - listener : fListener - } ) - 1; - if (sEvent.substr(0,3)!='DOM') { - sEvent = 'on' + sEvent; - } - var wrapped = getWrapper(listenerID); - o.attachEvent(sEvent, wrapped); - return wrapped; - }; - } else { - event.attach = false; - } - - - if (muze.env.isHostMethod(docEl, 'removeEventListener') ) { - event.detach = function(o, sEvent, handle, useCapture) { - if (o && sEvent) { - var result = o.removeEventListener(sEvent, handle, !!useCapture); - return result; - } else { - return false; - } - }; - } else if (muze.env.isHostMethod(docEl, 'detachEvent') ) { - event.detach = function(o, sEvent, handle, useCapture) { - if (o && sEvent) { - var result = o.detachEvent('on'+sEvent, handle); - return result; - } else { - return false; - } - }; - } else { - event.detach = false; - } - - event.clean = function() { }; - -}); - -}); - -muze.namespace('muze.html', function() { - var getType = function(obj) { - return ({}).toString.call(obj).match(/\s([a-z|A-Z]+)/)[1].toLowerCase(); - }; - - var setAttr = function(el, name, value) { - if ( name == 'style' ) { - for (var ii in value ) { - el.style[ii] = value[ii]; - } - } else { - switch(name) { - case 'class': - name = 'className'; - break; - case 'for': - name = 'htmlFor'; - break; - } - el[ name ] = value; - } - }; - - this.el = function(tagName) { //, attributes, children) { - var i; - var el = muze.global.document.createElement(tagName); - var next = 1; - var attributes = arguments[1]; - if (attributes && getType(attributes)=='object') { - next = 2; - try { - for (i in attributes ) { - setAttr(el, i, attributes[i]); - } - } catch(e) { - if ( /input/i.test(tagName) ) { - var elString = '<'+tagName; - for ( i in attributes ) { - if ( getType(attributes[i])=='string' ) { - elString += ' '+i+'="'+escape(attributes[i])+'"'; - } - } - elString += '>'; - el = muze.global.document.createElement(elString); - for ( i in attributes ) { - if ( getType(attributes[i])!='string' ) { - setAttr(el, i, attributes[i]); - } - } - } - } - } - for (i=next, l=arguments.length; i 0 ) { - return useWin.getSelection().getRangeAt(0); - } else { - return useWin.document.createRange(); - } - } else { - return useWin.document.selection.createRange(); - } - }, - backwards : function( useWin ) { - if ( !useWin ) { - useWin = win; - } - if (w3c) { - var sel = useWin.getSelection(); - if (!sel.anchorNode) { - return false; - } - var position = sel.anchorNode.compareDocumentPosition(sel.focusNode); - if (position === 0) { - return (sel.anchorOffset > sel.focusOffset); - } else if (position == 4) { // Node.DOCUMENT_POSITION_PRECEDING) { - return false; - } else { - return true; - } - } else { - // FIXME: Old IE compat goes here; - return false; - } - }, - collapse : function(range, left) { - if (left!==false) { - left=true; - } - range.collapse(left); - return range; - }, - - clone : function(range) { - if (w3c) { - return range.cloneRange(); - } else { - return range.duplicate(); - } - }, - - select : function(range) { - if( w3c ) { - var node = self.getNode(range); - if (node && node.ownerDocument) { - var sel = node.ownerDocument.defaultView.getSelection(); - sel.removeAllRanges(); - sel.addRange(range); - } - } else { - try { - range.select(); // IE is sometimes buggy and likes to barf on you - } catch( e ) { } - } - return range; - }, - - selectNode : function(range, el, select) { - if( w3c ) { - range.selectNodeContents(el); - } else { - range.moveToElementText(el); - } - if( select ) { - self.select(range); - } - return range; - }, - - selectRange : function(range, left, right, select) { - if( w3c ) { - range.setStart(left.startContainer, left.startOffset); - if(!right) { - range.setEnd(left.endContainer, left.endOffset); - } else { - range.setEnd(right.startContainer, right.startOffset); - } - } else { - range.setEndPoint('StartToStart', left); - if (!right) { - range.setEndPoint('EndToEnd', left); - } else { - range.setEndPoint('EndToStart', right); - } - } - if( select ) { - self.select(range); - } - return range; - }, - - parentNode : function(range) { - if( w3c ) { - var parent = false; - if( range.collapsed || range.startContainer == range.endContainer ) { - parent = range.startContainer; - } else { - parent = range.commonAncestorContainer; - } - while( parent.nodeType == document.TEXT_NODE ) { // text node - parent = parent.parentNode; - } - return parent; - } else { - return range.item ? range.item(0) : range.parentElement(); - } - }, - - getNode : function(range) { - var node; - if( w3c ) { - node = range.commonAncestorContainer; - if( !range.collapsed ) { - /* - | | - | Beide textnodes zijn optioneel, die hoeven er niet te staan. - */ - - if( range.startContainer == range.endContainer && range.startOffset - range.endOffset < 2 && range.startContainer.hasChildNodes() ) { - // Case 1: geen tekstnodes. - // start en eind punt van selectie zitten in dezelfde node en de node heeft kinderen - dus geen text node - en de offset verschillen - // precies 1 - dus er is exact 1 node geselecteerd. - node = range.startContainer.childNodes[range.startOffset]; // image achtige control selections. - } else if ( range.startContainer.nodeType == document.TEXT_NODE && range.startOffset == range.startContainer.data.length && - range.endContainer.nodeType != document.TEXT_NODE && range.endContainer == range.startContainer.parentNode ) - { - // Case 2: tekstnode er voor, niet er achter. - // start punt zit in een tekst node maar wel helemaal aan het eind. eindpunt zit in dezelfde container waar de textnode ook in zit. - node = range.endContainer.childNodes[ range.endOffset - 1 ]; - } else if ( range.endContainer.nodeType == document.TEXT_NODE && range.endOffset === 0 && - range.startContainer.nodeType != document.TEXT_NODE && range.startContainer == range.endContainer.parentNode ) - { - // Case 3: tekstnode er achter, niet er voor; - // Eindpunt zit in een textnode helemaal aan het begin. Startpunt zit in dezelfde container waar de eindpunt-textnode ook in zit - node = range.startContainer.childNodes[ range.startOffset ]; - } else if ( range.startContainer.nodeType == document.TEXT_NODE && range.endContainer.nodeType == document.TEXT_NODE && - range.startOffset == range.startContainer.data.length && range.endOffset === 0 && - range.startContainer.nextSibling == range.endContainer.previousSibling ) - { - // Case 4: tekstnode voor en achter - // start zit in een tekstnode helemaal aan het eind. eind zit in een tekstnode helemaal aan het begin. - node = range.startContainer.nextSibling; - } else if( range.startContainer == range.endContainer ) { - // Case 5: bijv. 1 tekstnode met geselecteerde tekst - hierna wordt dan de parentNode als node gezet - node = range.startContainer; - } - } else { - if( range.startContainer == range.endContainer && range.startOffset - range.endOffset < 2 && range.startContainer.hasChildNodes() ) { - // Case 1: geen tekstnodes. - // start en eind punt van selectie zitten in dezelfde node en de node heeft kinderen - dus geen text node - en de offset verschillen - // precies 1 - dus er is exact 1 node geselecteerd. - if (range.startContainer.childNodes[range.startOffset-1]) { - node = range.startContainer.childNodes[range.startOffset-1]; // image achtige control selections. cursor is na de image dus pak de node voor de cursor - } else { - node = range.startContainer.childNodes[range.startOffset]; // er is geen node voor de cursor, dus pak dan maar die er na staat. - } - } - } - - while( node && (node.nodeType == document.TEXT_NODE || node.nodeType == document.DOCUMENT_TYPE_NODE)) { - node = node.parentNode; - } - return node; - } else { - node = range.item ? range.item(0) : range.parentElement(); - while (node && (node.nodeType == document.TEXT_NODE || node.nodeType == document.DOCUMENT_TYPE_NODE)) { - node = node.parentNode; - } - return node; - } - }, - - isEmpty : function(range) { - return self.getHTMLText(range) === ''; - }, - - getHTMLText : function(range) { - if( w3c ) { - var frag = range.cloneContents(); - var div = range.startContainer.ownerDocument.createElement('div'); - div.appendChild(frag); - var result = div.innerHTML; - div = null; - return result; - } else { - if( range.item ) { - var control = range.item(0); - var textrange = control.ownerDocument.body.createTextRange(); - textrange.moveToElementText(control); - return textrange.htmlText; - } else { - return range.htmlText; - } - } - }, - - setHTMLText : function(range, htmltext) { - if( w3c ) { - var div = range.startContainer.ownerDocument.createElement('div'); - div.innerHTML = htmltext; - var frag = range.startContainer.ownerDocument.createDocumentFragment(); - for (var i=0; i < div.childNodes.length; i++) { - var node = div.childNodes[i].cloneNode(true); - frag.appendChild(node); - } - div = null; - range = self.replace(range, frag); - } else { - if( range.item ) { // control range - var control = range.item(0); - var textrange = control.ownerDocument.body.createTextRange(); - textrange.moveToElementText(control); - range.execCommand('delete', false); - range = textrange; - } - range.pasteHTML(htmltext); - } - return range; - }, - - replace : function(range, el) { - if( w3c ) { - range.deleteContents(); - range.insertNode(el); - // FIXME: definately betere check gebruiken waar de cursor moet komen, gaat mis als je over meer dan 1 textnode een selectie hebt - if( range.startContainer && range.startContainer.nextSibling ) { // ie behaviour simulatie - range.selectNode(range.startContainer.nextSibling); - } - range.collapse(false); - } else { - self.setHTMLText(range, el.outerHTML); - } - return range; - } - - }; - return self; - - })(); - - return dom; -})(simply.dom || {}); - - -simply.util = ( function(util) { - util.base64 = ( function() { - - /** - * - * Base64 encode / decode - * http://www.webtoolkit.info/ - * - **/ - - var base64 = { - - // private property - _keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=", - - // public method for encoding - encode : function (input) { - var output = ""; - var chr1, chr2, chr3, enc1, enc2, enc3, enc4; - var i = 0; - - input = base64._utf8_encode(input); - - while (i < input.length) { - - chr1 = input.charCodeAt(i++); - chr2 = input.charCodeAt(i++); - chr3 = input.charCodeAt(i++); - - enc1 = chr1 >> 2; - enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); - enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); - enc4 = chr3 & 63; - - if (isNaN(chr2)) { - enc3 = enc4 = 64; - } else if (isNaN(chr3)) { - enc4 = 64; - } - - output = output + - this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) + - this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4); - - } - - return output; - }, - - // public method for decoding - decode : function (input) { - var output = ""; - var chr1, chr2, chr3; - var enc1, enc2, enc3, enc4; - var i = 0; - - input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ""); - - while (i < input.length) { - - enc1 = this._keyStr.indexOf(input.charAt(i++)); - enc2 = this._keyStr.indexOf(input.charAt(i++)); - enc3 = this._keyStr.indexOf(input.charAt(i++)); - enc4 = this._keyStr.indexOf(input.charAt(i++)); - - chr1 = (enc1 << 2) | (enc2 >> 4); - chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); - chr3 = ((enc3 & 3) << 6) | enc4; - - output = output + String.fromCharCode(chr1); - - if (enc3 != 64) { - output = output + String.fromCharCode(chr2); - } - if (enc4 != 64) { - output = output + String.fromCharCode(chr3); - } - - } - - output = base64._utf8_decode(output); - - return output; - - }, - - // private method for UTF-8 encoding - _utf8_encode : function (string) { - string = string.replace(/\r\n/g,"\n"); - var utftext = ""; - - for (var n = 0; n < string.length; n++) { - - var c = string.charCodeAt(n); - - if (c < 128) { - utftext += String.fromCharCode(c); - } - else if((c > 127) && (c < 2048)) { - utftext += String.fromCharCode((c >> 6) | 192); - utftext += String.fromCharCode((c & 63) | 128); - } - else { - utftext += String.fromCharCode((c >> 12) | 224); - utftext += String.fromCharCode(((c >> 6) & 63) | 128); - utftext += String.fromCharCode((c & 63) | 128); - } - - } - - return utftext; - }, - - // private method for UTF-8 decoding - _utf8_decode : function (utftext) { - var string = ""; - var i = 0; - var c = 0; - var c1 = 0; - var c2 = 0; - - while ( i < utftext.length ) { - - c = utftext.charCodeAt(i); - - if (c < 128) { - string += String.fromCharCode(c); - i++; - } - else if((c > 191) && (c < 224)) { - c2 = utftext.charCodeAt(i+1); - string += String.fromCharCode(((c & 31) << 6) | (c2 & 63)); - i += 2; - } - else { - c2 = utftext.charCodeAt(i+1); - c3 = utftext.charCodeAt(i+2); - string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)); - i += 3; - } - - } - - return string; - } - }; - - return base64; - })(); - return util; -})(simply.util || {}); - - -simply.editor = ( function(editor) { - editor.selectionchange = (function (undefined) { - - var MAC = /^Mac/.test(navigator.platform); - var MAC_MOVE_KEYS = [65, 66, 69, 70, 78, 80]; // A, B, E, F, P, N from support.apple.com/en-ie/HT201236 - var SELECT_ALL_MODIFIER = MAC ? 'metaKey' : 'ctrlKey'; - var RANGE_PROPS = ['startContainer', 'startOffset', 'endContainer', 'endOffset']; - var HAS_OWN_SELECTION = {INPUT: 1, TEXTAREA: 1}; - - var ranges; - - return { - start: function (doc) { - var d = doc || document; - if (ranges || !hasNativeSupport(d) && (ranges = newWeakMap())) { - if (!ranges.has(d)) { - ranges.set(d, getSelectionRange(d)); - on(d, 'input', onInput); - on(d, 'keydown', onKeyDown); - on(d, 'mousedown', onMouseDown); - on(d, 'mousemove', onMouseMove); - on(d, 'mouseup', onMouseUp); - on(d.defaultView, 'focus', onFocus); - } - } - }, - stop: function (doc) { - var d = doc || document; - if (ranges && ranges.has(d)) { - ranges['delete'](d); - off(d, 'input', onInput); - off(d, 'keydown', onKeyDown); - off(d, 'mousedown', onMouseDown); - off(d, 'mousemove', onMouseMove); - off(d, 'mouseup', onMouseUp); - off(d.defaultView, 'focus', onFocus); - } - } - }; - - function hasNativeSupport(doc) { - var osc = doc.onselectionchange; - if (osc !== undefined) { - try { - doc.onselectionchange = 0; - return doc.onselectionchange === null; - } catch (e) { - } finally { - doc.onselectionchange = osc; - } - } - return false; - } - - function newWeakMap() { - if (typeof WeakMap !== 'undefined') { - return new WeakMap(); - } else { - console.error('selectionchange: WeakMap not supported'); - return null; - } - } - - function getSelectionRange(doc) { - var s = doc.getSelection(); - return s.rangeCount ? s.getRangeAt(0) : null; - } - - function on(el, eventType, handler) { - el.addEventListener(eventType, handler, true); - } - - function off(el, eventType, handler) { - el.removeEventListener(eventType, handler, true); - } - - function onInput(e) { - if (!HAS_OWN_SELECTION[e.target.tagName]) { - dispatchIfChanged(this, true); - } - } - - function onKeyDown(e) { - var code = e.keyCode; - if (code === 65 && e[SELECT_ALL_MODIFIER] && !e.shiftKey && !e.altKey || // Ctrl-A or Cmd-A - code >= 37 && code <= 40 || // arrow key - e.ctrlKey && MAC && MAC_MOVE_KEYS.indexOf(code) >= 0) { - if (!HAS_OWN_SELECTION[e.target.tagName]) { - setTimeout(dispatchIfChanged.bind(null, this), 0); - } - } - } - - function onMouseDown(e) { - if (e.button === 0) { - on(this, 'mousemove', onMouseMove); - setTimeout(dispatchIfChanged.bind(null, this), 0); - } - } - - function onMouseMove(e) { // only needed while primary button is down - if (e.buttons & 1) { - dispatchIfChanged(this); - } else { - off(this, 'mousemove', onMouseMove); - } - } - - function onMouseUp(e) { - if (e.button === 0) { - setTimeout(dispatchIfChanged.bind(null, this), 0); - } else { - off(this, 'mousemove', onMouseMove); - } - } - - function onFocus() { - setTimeout(dispatchIfChanged.bind(null, this.document), 0); - } - - function dispatchIfChanged(doc, force) { - var r = getSelectionRange(doc); - if (force || !sameRange(r, ranges.get(doc))) { - ranges.set(doc, r); - setTimeout(doc.dispatchEvent.bind(doc, new Event('selectionchange')), 0); - } - } - - function sameRange(r1, r2) { - return r1 === r2 || r1 && r2 && RANGE_PROPS.every(function (prop) { - return r1[prop] === r2[prop]; - }); - } - })(); - - editor.selection = ( function() { - - var win = window; - var savedRange = null; - var domSelection = simply.dom.selection; - - var controlTags = { - IMG : true, - OBJECT : true, - EMBED : true - }; - - function isUneditable( node ) { - return node.getAttribute('contentEditable') == 'false'; - } - - function isControlTag( node ) { - var tag = node.tagName.toUpperCase(); - return ( controlTags[tag] ? true : false ); - } - - var self = { - init : function( useWin ) { - win = useWin; - }, - save : function( range ) { - if( !range ) { - range = domSelection.get(win); - } - savedRange = range; - }, - restore : function( range ) { - if( !range ) { - range = savedRange; - } - if( range ) { - domSelection.select(range); - } - }, - get : function() { - return savedRange ? savedRange : domSelection.get(win); - }, - getControlNode : function( range ) { - if( !range ) { - range = self.get(); - } - if( range ) { - var node = domSelection.getNode(range); - if( isControlTag(node) || isUneditable(node) ) { // this could use a lot more probably - return node; - } - } - return false; - }, - remove : function() { - savedRange = null; - } - }; - - return self; - - })(); - - return editor; -})(simply.editor || {}); - - -// polyfill to add :scope selector for IE -(function() { - if (!HTMLElement.prototype.querySelectorAll) { - throw new Error('rootedQuerySelectorAll: This polyfill can only be used with browsers that support querySelectorAll'); - } - - // A temporary element to query against for elements not currently in the DOM - // We'll also use this element to test for :scope support - var container = document.createElement('div'); - - // Check if the browser supports :scope - try { - // Browser supports :scope, do nothing - container.querySelectorAll(':scope *'); - } - catch (e) { - // Match usage of scope - var scopeRE = /^\s*:scope/gi; - - // Overrides - function overrideNodeMethod(prototype, methodName) { - // Store the old method for use later - var oldMethod = prototype[methodName]; - - // Override the method - prototype[methodName] = function(query) { - var nodeList, - gaveId = false, - gaveContainer = false; - - if (query.match(scopeRE)) { - // Remove :scope - query = query.replace(scopeRE, ''); - - if (!this.parentNode) { - // Add to temporary container - container.appendChild(this); - gaveContainer = true; - } - - parentNode = this.parentNode; - - if (!this.id) { - // Give temporary ID - this.id = 'rootedQuerySelector_id_'+(new Date()).getTime(); - gaveId = true; - } - - // Find elements against parent node - nodeList = oldMethod.call(parentNode, '#'+this.id+' '+query); - - // Reset the ID - if (gaveId) { - this.id = ''; - } - - // Remove from temporary container - if (gaveContainer) { - container.removeChild(this); - } - - return nodeList; - } - else { - // No immediate child selector used - return oldMethod.call(this, query); - } - }; - } - - // Browser doesn't support :scope, add polyfill - overrideNodeMethod(HTMLElement.prototype, 'querySelector'); - overrideNodeMethod(HTMLElement.prototype, 'querySelectorAll'); - } -}()); - diff --git a/www/simply/simply.elementBinding.js b/www/simply/simply.elementBinding.js deleted file mode 100644 index c6c57f3..0000000 --- a/www/simply/simply.elementBinding.js +++ /dev/null @@ -1,697 +0,0 @@ -(function(global) { - var dataBinding = function(dataParent, path) { - if (dataParent.hasOwnProperty("_bindings_") && dataParent._bindings_[path]) { - return dataParent._bindings_[path]; - } - - var self = this; - - var setup = function(dataParent, path) { - path = "" + path; - /* - resolve binding to field.subfield.key, adding databindings along the data path; - */ - var keys = path.split("."); - var key = keys.pop(); - var parentBinding; - var currentParent = dataParent; - keys.forEach(function(parentKey) { - if (!currentParent[parentKey]) { - currentParent[parentKey] = {}; - } - parentBinding = simply.databind.create(currentParent, parentKey); - currentParent = currentParent[parentKey]; - }); - if (!currentParent[key]) { - currentParent[key] = undefined; - // if twoWay -> set value to current element value (getter?) -> initialize later (on bind) if undefined - } -// return { parentBinding: parentBinding, dataParent: dataParent, key: key}; -/* oude code hieronder */ - - self.parentBinding = parentBinding; //setup(dataParent, key); - self.dataParent = currentParent; - self.key = key; - self.elements = []; - self.changeStack = []; - - registerBinding(self.dataParent, self.key); - }; - - var addShadowValue = function() { - if (!self.hasOwnProperty("shadowValue")) { - var shadowValue; - Object.defineProperty(self, "shadowValue", { - get : function() { - return shadowValue; - }, - set : function(value) { - if (isEqual(shadowValue, value)) { - return; - } - - var previousValue = shadowValue; - shadowValue = value; - - if (shadowValue instanceof Array) { - overrideArrayFunctions(shadowValue); - } - if (typeof shadowValue === "object") { - monitorChildData(shadowValue); - } - - if (previousValue && shadowValue) { - transferBindings(previousValue, shadowValue); - } - } - }); - } - }; - - var transferBindings = function(oldValue, newValue) { - if (!oldValue._bindings_) { - return; - } - var oldBindings = oldValue._bindings_; - var newBindings = newValue._bindings_; - for (var key in oldBindings) { - if (newBindings && newBindings[key]) { - transferBoundElements(oldBindings[key], newBindings[key]); - } else { - setReconnectTrigger(newValue, key, oldBindings[key]); - } - } - }; - - var transferBoundElements = function(oldBinding, newBinding) { - oldBinding.elements.forEach(function(element) { - if (element.listItemDataBinding && (element.listItemDataBinding.binding === oldBinding)) { - var getter = element.listItemDataBinding.getter; - var setter = element.listItemDataBinding.setter; - oldBinding.unbind(element); - newBinding.bind(element, getter, setter); - } else if (element.dataBinding && (element.dataBinding.binding === oldBinding)) { - if (oldBinding.parentBinding && oldBinding.parentBinding.key == -1) { - // when the key is -1, the element was removed so no need to worry about it; - return; - } - var getter = element.dataBinding.getter; - var setter = element.dataBinding.setter; - oldBinding.unbind(element); - newBinding.bind(element, getter, setter); - } - }); - }; - - var setReconnectTrigger = function(dataParent, key, previousBinding) { - var reconnectChildren = function(value, previousData) { - var previousDescriptors = Object.getOwnPropertyDescriptors(previousData); - for (var i in previousDescriptors) { - if (typeof previousDescriptors[i].get !== "function" && typeof previousDescriptors[i].set === "function") { - var newBinding = previousDescriptors[i].set({}); // set it just to fetch the previous binding, so we can add a reconnect trigger for it; - setReconnectTrigger(value, i, newBinding); - } - } - if (typeof value === "undefined") { - return; - } - if (previousData && previousData._bindings_) { - for (var i in previousData._bindings_) { - if (typeof value[i] === "undefined") { - setReconnectTrigger(value, i, previousData._bindings_[i]); - } else { - // there is no databinding on the new value yet - add it and transfer the bindings/elements; - var newBinding = new dataBinding(value, i); - reconnectChildren(value[i], previousData[i]); - transferBindings(previousData[i], value[i]); - if (newBinding) { - transferBoundElements(previousData._bindings_[i], newBinding); - } - } - } - } - }; - - var reconnectBinding = function(value) { - if (typeof value !== 'undefined') { - newBinding = new dataBinding(dataParent, key); - reconnectChildren(value, previousBinding.shadowValue); - dataParent[key] = value; - transferBindings(previousBinding.shadowValue, value); - transferBoundElements(previousBinding, newBinding); - return newBinding; - } - }; - Object.defineProperty(dataParent, key, { - set : reconnectBinding, - configurable: true - }); - }; - - var addParentKey = function() { - if (!self.hasOwnProperty("parentKey")) { - Object.defineProperty(self, "parentKey", { - get : function() { - var parentKeys = []; - - var binding = self.parentBinding; - while(binding) { - parentKeys.unshift(binding.key); - binding = binding.parentBinding; - } - - parentKeys.unshift(""); // root node - parentKeys.push(""); // end node - - return parentKeys.join("/"); //TODO: SWITCH TO '.' - } - }); - } - }; - - var addPath = function() { - if (!self.hasOwnProperty("path")) { - Object.defineProperty(self, "path", { - get : function() { - var parentKeys = []; - - var binding = self.parentBinding; - while(binding) { - parentKeys.unshift(binding.key); - binding = binding.parentBinding; - } - - parentKeys.unshift(""); // root node - parentKeys.push(self.key); // end node - - return parentKeys.join("/"); //TODO: switch to '.' - } - }); - } - }; - - var addBindings = function(dataParent) { - if (!dataParent.hasOwnProperty("_bindings_")) { - var bindings = {}; - Object.defineProperty(dataParent, "_bindings_", { - get : function() { - return bindings; - } - }); - } - }; - - var registerBinding = function(dataParent, key) { - - addShadowValue(); - self.shadowValue = dataParent[key]; - - addParentKey(); - - addPath(); - - addBindings(dataParent); - dataParent._bindings_[key] = self; - - Object.defineProperty(dataParent, key, { - set : function(value) { - self.set(value, self); - // FIXME: run upwards on parentBindings; - }, - get : function() { - return self.shadowValue; - }, - enumerable: true - }); - }; - - var overrideArrayFunction = function(shadowValue, name) { - if (shadowValue.hasOwnProperty(name)) { - return; // we already did this; - } - Object.defineProperty(shadowValue, name, { - value : function() { - self.resolve(); // make sure the shadowValue is in sync with the latest state; - var result = Array.prototype[name].apply(shadowValue, arguments); - - - // for (var i in shadowValue) { - // shadowValue[i] = shadowValue[i]; // this will force a renumber/reindex for the parentKeys; - // } - - self.set(shadowValue, self); - - monitorChildData(shadowValue); // we might have new children that we need to watch as well; - return result; - } - }); - }; - - var overrideArrayFunctions = function(shadowValue) { - ['pop','push','shift','unshift','splice'].forEach(function(fn) { - overrideArrayFunction(shadowValue, fn); - }); - }; - - var monitorChildData = function(shadowValue) { - var monitor = function(shadowValue, key) { - var childBinding = new dataBinding(shadowValue, key); - if (!childBinding.parentBinding) { - childBinding.parentBinding = self; - } - }; - - for (var key in shadowValue) { - monitor(shadowValue, key); - } - }; - -/* - var info = setup(dataParent, path); -console.log(info); - this.parentBinding = info.parentbinding; //setup(dataParent, key); - this.dataParent = info.dataParent; - this.key = info.key; - this.elements = []; - this.elementIndex = new WeakMap(); - this.changeStack = []; - - registerBinding(this.dataParent, this.key); -*/ - setup(dataParent, path); - }; - - dataBinding.prototype.bind = function(element, getter, setter) { - var index = this.elements.push(element); - - // change this to non enumerable property - var elementBinding = { - setter : setter, - getter : getter, - binding : this, - observer: null, - observerPaused: 0 - }; - if (this.dataParent instanceof Array) { - if (element.listItemDataBinding) { - element.listItemDataBinding.binding.unbind(element); - } - element.listItemDataBinding = elementBinding; - } else { - if (element.dataBinding) { - element.dataBinding.binding.unbind(element); - } - element.dataBinding = elementBinding; - } - if (typeof this.shadowValue === 'undefined') { - this.set(getter(element), element); - } else { - setter(element, this.shadowValue); - } - this.addListeners(element); - }; - - dataBinding.prototype.bindOneWay = function(element, setter) { - if (element.dataBinding) { - element.dataBinding.binding.unbind(element); - } - var index = this.elements.push(element); - element.dataBinding = { - setter : setter, - binding : this - }; - if (typeof this.shadowValue !== 'undefined') { - setter(element, this.shadowValue); // or try to set an empty value? - } - }; - - dataBinding.prototype.set = function(value, source) { - // using a changeStack here for debugging - if different pieces of code - // change a value within one resolve cycle, this allows you to see - // what caused this and if your change was actually registered - this.changeStack.push({value: value, source: source}); - this.resolve(); // must run immediately or this.get will return old values - - // update the parentBindings to reconnect to it, in case we got lost - this.updateParent(value, source); - }; - - dataBinding.prototype.updateParent = function(value, source) { - if (this.parentBinding) { - if (this.parentBinding.dataParent[this.parentBinding.key] !== this.dataParent) { - this.parentBinding.dataParent[this.parentBinding.key][this.key] = value; - } - this.parentBinding.updateParent(this.dataParent, source); - } - }; - - dataBinding.prototype.get = function() { - return this.shadowValue; - }; - - dataBinding.prototype.resolve = function() { - var self = this; - if (this.resolveTimer) { - clearTimeout(this.resolveTimer); - } - if (!this.changeStack.length) { - return; - } - // we only need the last change - // stack is useful for debugging purposes only - var change = this.changeStack.pop(); - this.changeStack = []; - - var oldValue = this.shadowValue; - this.shadowValue = change.value; - var newValue = this.shadowValue; - - // event / callback voor wijziging in data zelf hier toevoegen - // of in updateElements als je throttle wil hebben. - self.updateElements(change); - this.fireEvent("databind:resolved", document, {dataBinding: this, arguments:{oldValue: oldValue, newValue: newValue}}); - }; - dataBinding.prototype.getElementBinding = function(element) { - if (element.dataBinding && (element.dataBinding.binding === this)) { - return element.dataBinding; - } else if (element.listItemDataBinding && (element.listItemDataBinding.binding === this)) { - return element.listItemDataBinding; - } - }; - dataBinding.prototype.updateElement = function(element) { - var elementBinding = this.getElementBinding(element); - if (!elementBinding) { - return; - } - elementBinding.idleCallback = false; - this.pauseListeners(element); - elementBinding.setter(element, this.get()); - this.resumeListeners(element); - this.fireEvent("databind:elementresolved", element); - }; - - dataBinding.prototype.updateElements = function(change) { - var isElementXPercentInViewport = function(el, percentVisible) { - var rect = el.getBoundingClientRect(); - var windowHeight = (window.innerHeight || document.documentElement.clientHeight); - - return !( - Math.floor(100 - (((rect.top >= 0 ? 0 : rect.top) / +-(rect.height / 1)) * 100)) < percentVisible || - Math.floor(100 - ((rect.bottom - windowHeight) / rect.height) * 100) < percentVisible - ) - }; - - var visibilityPercentage = function(el) { - var rect = el.getBoundingClientRect(); - var windowHeight = (window.innerHeight || document.documentElement.clientHeight); - - return windowHeight / Math.min( - Math.abs(Math.floor(100 - (((rect.top >= 0 ? 0 : rect.top) / +-(rect.height / 1)) * 100))), - Math.abs(Math.floor(100 - ((rect.bottom - windowHeight) / rect.height) * 100)) - ); - }; - - var self = this; - this.elements.forEach(function(element, index) { - if (change.source != element) { - var elementBinding = self.getElementBinding(element); - if (!elementBinding) { - return; - } - - if (elementBinding.idleCallback) { - return; // - } - - if (isElementXPercentInViewport(element, 50)) { - self.updateElement(element); - } else { - if (elementBinding.idleCallback) { - cancelIdleCallback(elementBinding.idleCallback); - }; - elementBinding.idleCallback = requestIdleCallback(function() { - self.updateElement(element); - }, {timeout: 10 * parseInt(visibilityPercentage(element) * 50)}); - // spread out the timeout for the elements so they don't clog the browser because they update all at once. - // elements that are closer to be on screen are done before the elements that are far away. - } - } - }); - - if (!self.handleScreenUpdate) { - self.handleScreenUpdate = function() { - self.elements.forEach(function(element, index) { - var elementBinding = self.getElementBinding(element); - if (!elementBinding) { - return; - } - if (elementBinding.idleCallback && isElementXPercentInViewport(element, 50)) { - console.log("updating element that has idle callback and is now in view"); - cancelIdleCallback(elementBinding.idleCallback); - self.updateElement(element); - } - }); - }; - } - - window.removeEventListener("scroll", self.handleScreenUpdate); - window.addEventListener("scroll", self.handleScreenUpdate); - }; - - dataBinding.prototype.unbind = function(element) { - // change elements to Set() - if (this.elements.indexOf(element) > -1) { - this.removeListeners(element); - this.elements.splice(this.elements.indexOf(element), 1); - if (element.dataBinding && (element.dataBinding.binding === this)) { - delete element.dataBinding; - } else if (element.listItemDataBinding && (element.listItemDataBinding.binding === this)) { - delete element.listItemDataBinding; - } - return true; - } - return false; - }; - - var isEqual = function(data1, data2) { - return JSON.stringify(data1) == JSON.stringify(data2); - }; - dataBinding.prototype.updateFrom = function(element) { - if (element.dataBinding) { - elementValue = element.dataBinding.getter(element); - if (!isEqual(elementValue, this.shadowValue)) { - this.set(elementValue, element); - } - } - }; - - dataBinding.prototype.addListeners = function(element) { - var dataBinding = element.dataBinding; - if (!dataBinding) { - dataBinding = element.listItemDataBinding; - } - if (dataBinding) { - if (dataBinding.observer) { - this.removeListeners(element); - } - var self = this; - dataBinding.observer = new MutationObserver( - getChangeHandler(element) - ); - // FIXME: doesn't trigger when element itself is removed from the dom - dataBinding.observer.observe(element, { - characterData: true, - subtree: true, - childList: true, - attributes: true - }); - } - // FIXME: the mutationObserver is slow to pick up on node insert/node remove changes - }; - - dataBinding.prototype.pauseListeners = function(element) { - if (element.dataBinding && element.dataBinding.observer) { - element.dataBinding.observer.disconnect(); - element.dataBinding.observerPaused++; - } - }; - - dataBinding.prototype.resumeListeners = function(element) { - if (element.dataBinding && element.dataBinding.observerPaused) { - element.dataBinding.observerPaused--; - if (!element.dataBinding.observerPaused) { - element.dataBinding.observer.observe(element, { - characterData: true, - subtree: true, - childList: true, - attributes: true - }); - } - } - if (element.listItemDataBinding && element.listItemDataBinding.observerPaused) { - element.listItemDataBinding.observerPaused--; - if (!element.listItemDataBinding.observerPaused) { - element.listItemDataBinding.observer.observe(element, { - characterData: true, - subtree: true, - childList: true, - attributes: true - }); - } - } - }; - - dataBinding.prototype.fireEvent = function(evtname, target, eventData) { - var event; // The custom event that will be created - if (document.createEvent) { - event = document.createEvent("HTMLEvents"); - event.initEvent(evtname, true, true); - } else { - event = document.createEventObject(); - event.eventType = evtname; - } - - event.data = eventData; - event.eventName = evtname; - - if (document.createEvent) { - target.dispatchEvent(event); - } else { - // target.fireEvent("on" + event.eventType, event); - } - return event; - }; - - dataBinding.prototype.removeListeners = function(element) { - if (element.dataBinding && element.dataBinding.observer) { - element.dataBinding.observer.disconnect(); - } - if (element.listItemDataBinding && element.listItemDataBinding.observer) { - element.listItemDataBinding.observer.disconnect(); - } - }; - - /** - * returns a function that updates the data from a - * target element. This function is passed on to the - * mutation observer so we don't need to search for the - * bound element there. - * @param target DomElement the bound element - * @return void - */ - function getChangeHandler(target) { - return function(mutations) { - if (target.dataBinding && target.dataBinding.binding) { - if (target.dataBinding.binding.shadowValue instanceof Array) { - mutations.forEach(function(mutation) { - if (mutation.type == "childList" && mutation.target == target) { - mutation.removedNodes.forEach(function(node) { - if (node.nodeType != document.ELEMENT_NODE) { - return; - } - if (!node.listItemDataBinding) { - return; - } - var index = parseInt(node.listItemDataBinding.binding.key); - if (index < 0) { - return; - } - var listItemParent = node.listItemDataBinding.binding.dataParent; - console.log("remove childNode, value before splice " + JSON.stringify(listItemParent)); - listItemParent._bindings_[index].key = -1; - - node.listItemDataBinding.simplyData = Array.prototype['splice'].call( - listItemParent, index, 1 - )[0]; - - delete listItemParent._bindings_[index]; - - var counter = 0; - for (i in listItemParent._bindings_) { - listItemParent._bindings_[counter] = listItemParent._bindings_[i]; - console.log("renumbering " + listItemParent._bindings_[counter].key + " to " + counter); - listItemParent._bindings_[counter].key = counter; - delete listItemParent._bindings_[i]; - counter++; - } - console.log("remove childNode, value after splice " + JSON.stringify(listItemParent)); - }); - - mutation.addedNodes.forEach(function(node) { - if (node.nodeType != document.ELEMENT_NODE) { - return; - } - var index = 0; - if (mutation.previousSibling) { - if (!mutation.previousSibling.listItemDataBinding) { - return; - } - index = parseInt(mutation.previousSibling.listItemDataBinding.binding.key) + 1; - } - if (!node.parentNode) { - // node was already removed, carry on; - return; - } - var listItemParent = node.parentNode.dataBinding.binding.get(); - console.log("add childNode, value before splice " + JSON.stringify(listItemParent)); - - Array.prototype['splice'].call( - listItemParent, - // listDataBinding can be empty if we clone a list item and append it to the list; - // the data change will be picked up by the list getter instead; - index, 0, (node.listItemDataBinding ? node.listItemDataBinding.simplyData :null) - ); - - var counter = 0; - node.parentNode.childNodes.forEach(function(listItem) { - if (listItem.listItemDataBinding) { - console.log("renumbering " + listItem.listItemDataBinding.binding.key + " to " + counter); - listItemParent._bindings_[counter] = listItem.listItemDataBinding.binding; - listItem.listItemDataBinding.binding.key = counter; - counter++; - } - }); - console.log("add childNode, value after splice " + JSON.stringify(listItemParent)); - }); - } - }); - } - - target.dataBinding.binding.updateFrom(target); - } - }; - } - - var databind = { - create: function(dataParent, path) { - if (typeof dataParent != "object") { - console.log("Attempted to bind on a non-object data for " + path); - return; - } - // If we already have a databinding on this data[key], re-use that one instead of creating a new one; - if (dataParent.hasOwnProperty("_bindings_") && dataParent._bindings_[path]) { - return dataParent._bindings_[path]; - } - return new dataBinding(dataParent, path); - }, - debug: function(on) { - debugMode = Boolean(on); - // log change/resolve changes value and source - }, - sync: function(data) { - // stel ik delete een entry uit een array met 'delete arr[2]' - // dan wil ik 'simply.databind.sync(arr)' kunnen doen om alsnog - // de change te triggeren... hoe doe ik dat? - } - }; - - if (typeof module !== 'undefined' && typeof module.exports != 'undefined') { - module.exports = databind; - } else { - if (!global.simply) { - global.simply = {}; - } - global.simply.databind = databind; - } - -})(this); diff --git a/www/simply/simply.tripleBinding.js b/www/simply/simply.tripleBinding.js deleted file mode 100644 index 7060e49..0000000 --- a/www/simply/simply.tripleBinding.js +++ /dev/null @@ -1,575 +0,0 @@ -var resolveNameSpace = function(property) { - var namespace = "xmlns:" + property.split(":")[0]; - var namespaceElement = document.body.closest("[" + CSS.escape(namespace) + "]"); - if (namespaceElement) { - return namespaceElement.getAttribute(namespace) + property.split(":")[1]; - } - return property; -}; - -tripleBinding = function(triple, dataBinding) { - /* - Triple is an object: - { - store : rdfStore, - subject : rdfSubject, - predicate : rdfPredicate - } - */ - - - var self = this; - this.triple = triple; - this.dataBinding = dataBinding; - this.triple.dataBinding = dataBinding; - this.triple.tripleBinding = this; - this.simplyDataBindingElement = true; - - this.triple.predicate = resolveNameSpace(this.triple.predicate); - - if (typeof this.triple.store.simplyDataBindings === "undefined") { - this.triple.store.simplyDataBindings = {}; - } - if (typeof this.triple.store.simplyDataBindings[this.triple.subject] === "undefined") { - this.triple.store.simplyDataBindings[this.triple.subject] = {}; - } - if (typeof this.triple.store.simplyDataBindings[this.triple.subject][this.triple.predicate] === "undefined") { - this.triple.store.simplyDataBindings[this.triple.subject][this.triple.predicate] = this; - } else { - console.log("Warning: binding to the same subject/predicate twice"); - var previousBinding = this.triple.store.simplyDataBindings[this.triple.subject][this.triple.predicate]; - previousBinding.isInDocument = function() { - return false; - }; - this.dataBinding.unbind(previousBinding); - this.triple.store.simplyDataBindings[this.triple.subject][this.triple.predicate] = this; - } - this.unbind = function() { - if (this.dataBinding) { - this.dataBinding.unbind(this); - } - }; - this.dataBindingPaused = 0; - - this.getBlankNode = function(self, subject) { - var result = {}; - if (!self.triple.store.subjectIndex[subject]) { - subject = "_:" + subject; - } - if (!self.triple.store.subjectIndex[subject]) { - return; - } - self.triple.store.subjectIndex[subject].forEach(function(triple) { - if (typeof result[triple.predicate.value] === "undefined") { - result[triple.predicate.value] = []; - } - result[triple.predicate.value].push(triple.object); - }); - return result; - }; - this.getNamedNode = function(self, subject) { - var result = {}; - if (!self.triple.store.subjectIndex[subject]) { - subject = "<" + subject + ">"; - } - if (!self.triple.store.subjectIndex[subject]) { - return; - } - self.triple.store.subjectIndex[subject].forEach(function(triple) { - if (typeof result[triple.predicate.value] === "undefined") { - result[triple.predicate.value] = []; - } - result[triple.predicate.value].push(triple.object); - }); - return result; - }; - - this.getObjects = function() { - var triples = this.getTriples(); - var objects = []; - triples.forEach(function(triple) { - if (triple.object.termType == "Collection") { - triple.object.elements.forEach(function(item) { - objects.push(item); - }); - } else { - objects.push(triple.object); - } - }); - return objects; - }; - - this.getTriples = function() { - var triples = []; - var subject = this.triple.subject; - var predicate = this.triple.predicate; - var store = this.triple.store; - var self = this; - - if (!this.triple.store.subjectIndex[subject]) { - if (this.triple.store.subjectIndex["<" + subject + ">"]) { - subject = "<" + subject + ">"; - } else if (this.triple.store.subjectIndex[subject.replace(/^\[(.*)\]$/, "$1")]) { - subject = subject.replace(/^\[(.*)\]$/, "$1"); - } - } - if (!this.triple.store.subjectIndex[subject]) { - return []; - } - this.triple.store.subjectIndex[subject].forEach(function(triple) { - if (triple.predicate.value != predicate) { - return; - } - if ((triple.object.termType == "Collection") && (triple.object.elements.length == 0)) { - return; // empty collection, no need to add - } - triples.push(triple); - }); - return triples; - }; - - this.getter = function() { - var self = this; - var objects = this.getObjects(); - if (!objects) { - return; - } - if (this.dataBinding.mode == "field") { - if (objects.length) { - return objects[0].isBlank ? "[_:" + objects[0].value + "]" : objects[0].value; - // follows the format as described in https://www.w3.org/TR/2008/REC-rdfa-syntax-20081014/#sec_5.4.5. - } - return; - } else { - var result = objects.map(function(object) { - switch (object.termType) { - case "Collection": - return object.elements.map(function(item) { - if (item.isBlank) { - item.contents = self.getBlankNode(self, item.value); - } - return { - value : (item.isBlank ? "[_:" + item.value + "]" : item.value), - contents: item.contents - }; - }); - // break; - case "Literal": - return object; - // break; - case "BlankNode": - return { - value: "[_:" + object.value + "]", - contents: self.getBlankNode(self, object.value) - }; - // break; - case "NamedNode": - return { - value: object.value, - contents: self.getNamedNode(self, object.value) - }; - // break; - } - }); - return result; - } - }; - - this.getFirstElementBinding = function(dataBinding) { - for (var i=0; i 0) { // move value to the front so we handle that first, setting the about value for the other fields - var index = keys.indexOf("value"); - keys.splice(index, 1); - keys.unshift("value"); - } - var blankNode = new $rdf.BlankNode(); - item.value = "[_:" + blankNode.value + "]"; - // console.log("created blank node " + blankNode.value + " as parent"); - var predicate = self.getFirstElementBinding(item._bindings_.value).element.getAttribute("property"); - if (!predicate) { - predicate = self.getFirstElementBinding(item._bindings_.value).element.parentNode.getAttribute("property"); - } - if (!predicate) { - return; - } - predicate = resolveNameSpace(predicate); - - self.triple.store.add(blankNode, $rdf.sym("http://www.w3.org/1999/02/22-rdf-syntax-ns#type"), $rdf.sym(resolveNameSpace(self.getFirstElementBinding(item._bindings_.value).element.getAttribute("typeof")))); - self.triple.store.subjectIndex[subject].every(function(triple) { - if (triple.predicate.value != predicate) { - return true; // continue - } - if (triple.object.termType === "Collection") { - triple.object.append(blankNode); - } else { - self.triple.store.add(self.triple.store.subjectIndex[subject][0].subject, $rdf.sym(predicate), blankNode); - } - return false; // stop loop after first time we added it; - }); - - bindChildren(item, blankNode); - setTimeout(function() { - keys.forEach(function(key) { - if (!item._bindings_ || !item._bindings_[key]) { - return; - } - if (!item._bindings_[key].elements.length) { - return; - } - var subject = self.getFirstElementBinding(item._bindings_[key]).element.closest("[about]").getAttribute("about"); - if (!self.triple.store.subjectIndex[subject]) { - if (self.triple.store.subjectIndex["<" + subject + ">"]) { - subject = "<" + subject + ">"; - } else if (self.triple.store.subjectIndex[subject.replace(/^\[(.*)\]$/, "$1")]) { - subject = subject.replace(/^\[(.*)\]$/, "$1"); - } - } - if (!self.triple.store.subjectIndex[subject]) { - return; - } - subject = self.triple.store.subjectIndex[subject][0].subject; - var predicate = self.getFirstElementBinding(item._bindings_[key]).element.getAttribute("property"); - if (!predicate) { - predicate = self.getFirstElementBinding(item._bindings_[key]).element.parentNode.getAttribute("property"); - } - if (!predicate) { - return; - } - predicate = resolveNameSpace(predicate); - var value = item[key]; - if ((subject.isBlank ? "[_:" + subject.value + "]" : subject.value) === value) { - return; - } - - if (value && value.length && typeof value !== "object") { - // console.log("adding " + predicate + " to " + subject); - self.triple.store.add(subject, $rdf.sym(predicate), value); - } else { - if (!value || typeof value.forEach !== "function") { - return; - } - bindParents(value, subject); - } - - var triple = new tripleBinding( - { - store : self.triple.store, - subject : (subject.isBlank ? "[_:" + subject.value + "]" : subject.value), - predicate: predicate, - initFromStore : self.triple.initFromStore - }, - item._bindings_[key] - ); - item._bindings_[key].bind(triple); - }); - }, 10); // needs a bit to let the 'about' property get set; - } - }); - } - - this.deleteBlankNode = function(store, node) { - while (store.subjectIndex["_:" + node].length) { - subEntry = store.subjectIndex["_:" + node][0]; - store.removeStatement(subEntry); - if (subEntry.object.termType === "BlankNode") { - this.deleteBlankNode(store, subEntry.object.value); - } - } - }; - - this.setter = function(data) { - try { - if (this.getFirstElementBinding(this.triple.dataBinding).element.closest("[about]").getAttribute("about") !== this.triple.subject) { - // 'about' changed, update to reflect; - console.log("Updating subject from: " + this.triple.subject); - delete this.triple.store.simplyDataBindings[this.triple.subject][this.triple.predicate]; - this.triple.subject = this.getFirstElementBinding(this.triple.dataBinding).element.closest("[about]").getAttribute("about"); - console.log("Updating subject to: " + this.triple.subject); - this.triple.store.simplyDataBindings[this.triple.subject][this.triple.predicate] = this; - } - } catch (e) { - } - - if ((typeof data === "object") && (typeof data.about !== "undefined") && (data.about === null)) { - return; - } - var subject = this.triple.subject; - var objects = this.getObjects(); - if (this.dataBinding.mode == "field") { - /* - if (data.indexOf("http") === 0) { // make it a symbol if it is a url - data = $rdf.sym(data); - } - */ - if (objects.length) { - if ((data !== null) && (typeof data !== "undefined") && data !== "") { - switch (data.termType) { - case "Literal": - objects[0] = data; - break; - default: - if (objects[0].termType === "BlankNode") { - data = data.replace(/^\[_:(.*)\]$/, "$1"); - } - objects[0].value = data; - break; - } - } else { - this.triple.store.removeStatement(this.getTriples()[0]); - } - } else { - if (this.triple.subject == data) { - return; // skip descriptions for ourself - } - if (data == "") { - return; // skip creation of empty data - } - if ((typeof data.about === "object") && (data.about === null)) { - return; // no known about, skip it - } - - console.log("create a new triple for value"); - console.log(data); - console.log(this.triple); - if (!this.triple.store.subjectIndex[subject]) { - if (this.triple.store.subjectIndex["<" + subject + ">"]) { - subject = "<" + subject + ">"; - } else if (this.triple.store.subjectIndex[subject.replace(/^\[(.*)\]$/, "$1")]) { - subject = subject.replace(/^\[(.*)\]$/, "$1"); - } - } - if (!this.triple.store.subjectIndex[subject]) { - try { - subject = $rdf.sym(subject); - } catch (e) { - return; - } - } else { - subject = this.triple.store.subjectIndex[subject][0].subject; - } - if ((data !== null) && (typeof data !== "undefined") && data !== "") { - if ((typeof data.about !== "undefined") && (subject.isBlank) && ("[_:" + subject.value + "]" == data.about)) { - console.log("skip adding about self"); - } else { - this.triple.store.add(subject, $rdf.sym(this.triple.predicate), data); - } - } - } - } else { - var self = this; - if (!this.triple.store.subjectIndex[subject]) { - if (this.triple.store.subjectIndex["<" + subject + ">"]) { - subject = "<" + subject + ">"; - } else if (this.triple.store.subjectIndex[subject.replace(/^\[(.*)\]$/, "$1")]) { - subject = subject.replace(/^\[(.*)\]$/, "$1"); - } - } - if (!this.triple.store.subjectIndex[subject]) { - return; - } - var dataNodes = data.map(function(entry) { - return entry.value; - }); - - var triples = this.getTriples(); - if (triples.length === 0 && dataNodes.length > 0) { - self.triple.store.add($rdf.sym(self.triple.subject), $rdf.sym(self.triple.predicate), new $rdf.Collection()); - } - - triples.forEach(function(entry) { - switch (entry.object.termType) { - case "Collection": - entry.object.elements.forEach(function(item, index, elements) { - if (dataNodes.indexOf(item.isBlank ? "[_:" + item.value + "]" : item.value) === -1) { - // node was removed; - // console.log("remove node"); - // console.log(self.triple.subject); - // console.log(self.triple.predicate); - // console.log(item.value); - // self.triple.store.removeStatement(item); - elements.splice(index, 1); // remove it from the collection; - if (item.termType === "BlankNode") { - self.deleteBlankNode(self.triple.store, item.value); - } - } - }); - entry.object.elements.sort(function(a, b) { - aIndex = dataNodes.indexOf(a.isBlank ? "[_:" + a.value + "]" : a.value); - bIndex = dataNodes.indexOf(b.isBlank ? "[_:" + b.value + "]" : b.value); - if (aIndex > bIndex) { - return 1; - } else if (aIndex < bIndex) { - return -1; - } else { - return 0; - } - }); - break; - case "BlankNode": - if (dataNodes.indexOf("[_:" + entry.object.value + "]" ) === -1) { - self.triple.store.removeStatement(entry); - self.deleteBlankNode(self.triple.store, entry.object.value); - } - break; - default: - if (dataNodes.indexOf(entry.object.value) === -1) { - self.triple.store.removeStatement(entry); - } - break; - } - }); - setTimeout(function() { - bindParents(data, subject); - }); - } - return data; - }; - - this.addListeners = function() { - }; - - this.removeListeners = function() { - }; - - this.resumeListeners = function() { - this.triple.dataBindingPaused--; - if (this.triple.dataBindingPaused < 0) { - console.log("Warning: resume called of non-paused databinding"); - this.triple.dataBindingPaused = 0; - } - }; - this.pauseListeners = function() { - this.triple.dataBindingPaused++; - }; - - this.fireEvent = function(event) { - }; - this.isInDocument = function() { - return true; - }; - - - // Init triples from the rdfStore to start with; - if (this.triple.initFromStore) { - var storeValue = this.getter(); - if (Array.isArray(storeValue) && !storeValue.length) { - return; - } - if (!storeValue) { - return; - } - this.dataBinding.set(this.getter()); - this.dataBinding.resolve(true); - } -}; - -editor.field.storedInit = editor.field.init; -editor.list.storedInit = editor.list.init; - -window.simplyBlankNodeCount = 1; - -var initRdflibTriple = function(element) { - var fieldName = element.getAttribute("data-simply-field"); - if (!fieldName) { - fieldName = element.getAttribute("data-simply-list"); - } - - var about = element.closest("[about]"); - if (!about) { - window.setTimeout(function() { - initRdflibTriple(element); - }, 10); - return; - } - - var subject = about.getAttribute("about"); - if (element.hasAttribute("typeof")) { - if (subject.indexOf("[") !== 0) { // skip blank nodes; FIXME: do we need a better way to exclude them? - // Only add the type if it is not already set; - var currentType = simplyApp.rdfStore.match($rdf.sym(subject), $rdf.sym("http://www.w3.org/1999/02/22-rdf-syntax-ns#type")); - if (currentType.length) { - element.setAttribute("typeof", currentType[0].object.value); - } else { - simplyApp.rdfStore.add($rdf.sym(subject), $rdf.sym("http://www.w3.org/1999/02/22-rdf-syntax-ns#type"), $rdf.sym(resolveNameSpace(element.getAttribute("typeof")))); - } - } - } - - if (!element.hasAttribute("property")) { - return; - } - - var property = element.getAttribute("property"); - var initFromStore = true; - if (element.getAttribute("data-set-to-store")) { - initFromStore = false; - } - if (element.dataBinding) { - if ( - !simplyApp.rdfStore.simplyDataBindings || - !simplyApp.rdfStore.simplyDataBindings[subject] || - !simplyApp.rdfStore.simplyDataBindings[subject][property] - ) { - element.dataBinding.bind( - new tripleBinding( - { - store: simplyApp.rdfStore, - subject : subject, - predicate : property, - initFromStore: initFromStore - }, - element.dataBinding - ) - ); - } - } -}; - -editor.field.init = function(field, dataParent, useDataBinding) { - editor.field.storedInit(field, dataParent, useDataBinding); - initRdflibTriple(field); -}; -editor.list.init = function(list, dataParent, useDataBinding) { - editor.list.storedInit(list, dataParent, useDataBinding); - initRdflibTriple(list); -}; diff --git a/www/simply/slip.js b/www/simply/slip.js deleted file mode 100644 index 4790df5..0000000 --- a/www/simply/slip.js +++ /dev/null @@ -1,1095 +0,0 @@ -/* Slip - swiping and reordering in lists of elements on touch screens, no fuss. - - Fires these events on list elements: - - • slip:swipe - When swipe has been done and user has lifted finger off the screen. - If you execute event.preventDefault() the element will be animated back to original position. - Otherwise it will be animated off the list and set to display:none. - - • slip:beforeswipe - Fired before first swipe movement starts. - If you execute event.preventDefault() then element will not move at all. - - • slip:reorder - Element has been dropped in new location. event.detail contains the location: - • insertBefore: DOM node before which element has been dropped (null is the end of the list). Use with node.insertBefore(). - • spliceIndex: Index of element before which current element has been dropped, not counting the element iself. - For use with Array.splice() if the list is reflecting objects in some array. - - • slip:beforereorder - When reordering movement starts. - Element being reordered gets class `slip-reordering`. - If you execute event.preventDefault() then element will not move at all. - - • slip:beforewait - If you execute event.preventDefault() then reordering will begin immediately, blocking ability to scroll the page. - - • slip:tap - When element was tapped without being swiped/reordered. - - • slip:cancelswipe - Fired when the user stops dragging and the element returns to its original position. - - - Usage: - - CSS: - You should set `user-select:none` (and WebKit prefixes, sigh) on list elements, - otherwise unstoppable and glitchy text selection in iOS will get in the way. - - You should set `overflow-x: hidden` on the container or body to prevent horizontal scrollbar - appearing when elements are swiped off the list. - - - var list = document.querySelector('ul#slippylist'); - new Slip(list); - - list.addEventListener('slip:beforeswipe', function(e) { - if (shouldNotSwipe(e.target)) e.preventDefault(); - }); - - list.addEventListener('slip:swipe', function(e) { - // e.target swiped - if (thatWasSwipeToRemove) { - e.target.parentNode.removeChild(e.target); - } else { - e.preventDefault(); // will animate back to original position - } - }); - - list.addEventListener('slip:beforereorder', function(e) { - if (shouldNotReorder(e.target)) e.preventDefault(); - }); - - list.addEventListener('slip:reorder', function(e) { - // e.target reordered. - if (reorderedOK) { - e.target.parentNode.insertBefore(e.target, e.detail.insertBefore); - } else { - e.preventDefault(); - } - }); - - Requires: - • Touch events - • CSS transforms - • Function.bind() - - Caveats: - • Elements must not change size while reordering or swiping takes place (otherwise it will be visually out of sync) -*/ -/*! @license - Slip.js 1.2.0 - - © 2014 Kornel Lesiński . All rights reserved. - - Redistribution and use in source and binary forms, with or without modification, - are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and - the following disclaimer in the documentation and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -window['Slip'] = (function(){ - 'use strict'; - - var damnYouChrome = /Chrome\/[34]/.test(navigator.userAgent); // For bugs that can't be programmatically detected :( Intended to catch all versions of Chrome 30-40 - var needsBodyHandlerHack = damnYouChrome; // Otherwise I _sometimes_ don't get any touchstart events and only clicks instead. - - /* When dragging elements down in Chrome (tested 34-37) dragged element may appear below stationary elements. - Looks like WebKit bug #61824, but iOS Safari doesn't have that problem. */ - var compositorDoesNotOrderLayers = damnYouChrome; - - // -webkit-mess - var testElement = document.createElement('div'); - - var transitionPrefix = "webkitTransition" in testElement.style ? "webkitTransition" : "transition"; - var transformPrefix = "webkitTransform" in testElement.style ? "webkitTransform" : "transform"; - var transformProperty = transformPrefix === "webkitTransform" ? "-webkit-transform" : "transform"; - var userSelectPrefix = "webkitUserSelect" in testElement.style ? "webkitUserSelect" : "userSelect"; - - testElement.style[transformPrefix] = 'translateZ(0)'; - var hwLayerMagic = testElement.style[transformPrefix] ? 'translateZ(0) ' : ''; - var hwTopLayerMagic = testElement.style[transformPrefix] ? 'translateZ(1px) ' : ''; - testElement = null; - - var globalInstances = 0; - var attachedBodyHandlerHack = false; - var nullHandler = function(){}; - - function Slip(container, options) { - if ('string' === typeof container) container = document.querySelector(container); - if (!container || !container.addEventListener) throw new Error("Please specify DOM node to attach to"); - - if (!this || this === window) return new Slip(container, options); - - this.options = options; - - // Functions used for as event handlers need usable `this` and must not change to be removable - this.cancel = this.setState.bind(this, this.states.idle); - this.onTouchStart = this.onTouchStart.bind(this); - this.onTouchMove = this.onTouchMove.bind(this); - this.onTouchEnd = this.onTouchEnd.bind(this); - this.onMouseDown = this.onMouseDown.bind(this); - this.onMouseMove = this.onMouseMove.bind(this); - this.onMouseUp = this.onMouseUp.bind(this); - this.onMouseLeave = this.onMouseLeave.bind(this); - this.onSelection = this.onSelection.bind(this); - this.onScroll = this.onScroll.bind(this); - - this.setState(this.states.idle); - this.attach(container); - } - - function getTransform(node) { - var transform = node.style[transformPrefix]; - if (transform) { - return { - value:transform, - original:transform, - }; - } - - if (window.getComputedStyle) { - var style = window.getComputedStyle(node).getPropertyValue(transformProperty); - if (style && style !== 'none') return {value:style, original:''}; - } - return {value:'', original:''}; - } - - function findIndex(target, nodes) { - var originalIndex = 0; - var listCount = 0; - - for (var i=0; i < nodes.length; i++) { - if (nodes[i].nodeType === 1) { - listCount++; - if (nodes[i] === target.node) { - originalIndex = listCount-1; - } - } - } - - return originalIndex; - } - - /* Helper functions to improve on getBoundingClientRect - also works - * for elements that are collapsed because all the child elements - * have float: styles. */ - - function getNodeBounds(el) { - var minTop; - var maxBottom; - var minLeft; - var maxRight; - - if (el.offsetHeight > 0) { - return el.getBoundingClientRect(); - } - - // Its a collapsed element, probably because of floating child elements. - for (var i=0; i rects.top) { - minTop = rects.top; - } - - if (typeof maxBottom === "undefined") { - maxBottom = rects.bottom; - } else if (maxBottom < rects.bottom) { - maxBottom = rects.bottom; - } - - if (typeof minLeft === "undefined") { - minLeft = rects.left; - } else if (minLeft > rects.left) { - minLeft = rects.left; - } - - if (typeof maxRight === "undefined") { - maxRight = rects.right; - } else if (maxRight < rects.right) { - maxRight = rects.right; - } - } - } - return { - top : minTop, - bottom : maxBottom, - left : minLeft, - right: maxRight - } - } - - function getNodeHeight(el) { - if (el.offsetHeight > 0) { - return el.offsetHeight; - } - if (el.childNodes.length) { - var nodeBounds = getNodeBounds(el); - return nodeBounds.bottom - nodeBounds.top; - } - return 0; - } - function getNodeWidth(el) { - if (el.offsetHeight > 0) { - return el.offsetWidth; - } - if (el.childNodes.length) { - var nodeBounds = getNodeBounds(el); - return nodeBounds.right - nodeBounds.left; - } - return 0; - } - function getNodeLeft(el) { - if (el.offsetHeight > 0) { - return el.offsetLeft; - } - if (el.childNodes.length) { - var nodeBounds = getNodeBounds(el); - return nodeBounds.left; - } - return 0; - } - function getNodeTop(el) { - if (el.offsetHeight > 0) { - return el.offsetTop; - } - if (el.childNodes.length) { - var nodeBounds = getNodeBounds(el); - return nodeBounds.top; - } - return 0; - } - - - // All functions in states are going to be executed in context of Slip object - Slip.prototype = { - - container: null, - options: {}, - state: null, - - target: null, // the tapped/swiped/reordered node with height and backed up styles - - usingTouch: false, // there's no good way to detect touchscreen preference other than receiving a touch event (really, trust me). - mouseHandlersAttached: false, - - startPosition: null, // x,y,time where first touch began - latestPosition: null, // x,y,time where the finger is currently - previousPosition: null, // x,y,time where the finger was ~100ms ago (for velocity calculation) - - canPreventScrolling: false, - - states: { - idle: function idleStateInit() { - this.target = null; - this.usingTouch = false; - this.removeMouseHandlers(); - - return { - allowTextSelection: true, - }; - }, - - undecided: function undecidedStateInit() { - this.target.height = this.target.node.offsetHeight; - this.target.node.style[transitionPrefix] = ''; - - if (!this.dispatch(this.target.originalTarget, 'beforewait')) { - if (this.dispatch(this.target.originalTarget, 'beforereorder')) { - this.setState(this.states.reorder); - } - } else { - var holdTimer = setTimeout(function(){ - var move = this.getAbsoluteMovement(); - if (this.canPreventScrolling && move.x < 15 && move.y < 25 && !this.selectionChanged) { - if (this.dispatch(this.target.originalTarget, 'beforereorder')) { - this.setState(this.states.reorder); - } - } - }.bind(this), 300); - } - - return { - leaveState: function() { - clearTimeout(holdTimer); - }, - - onMove: function() { - var move = this.getAbsoluteMovement(); - - if (move.x > 20 && move.y < Math.max(100, this.target.height)) { - if (this.dispatch(this.target.originalTarget, 'beforeswipe')) { - this.setState(this.states.swipe); - return false; - } else { - this.setState(this.states.idle); - } - } - if (move.x > 20) { - this.setState(this.states.idle); - } - if (move.y > 20) { - this.setState(this.states.idle); - } - - // Chrome likes sideways scrolling :( - if (move.x > move.y*1.2) return false; - }, - - onLeave: function() { - this.setState(this.states.idle); - }, - - onEnd: function() { - var allowDefault = this.dispatch(this.target.originalTarget, 'tap'); - this.setState(this.states.idle); - return allowDefault; - }, - }; - }, - - swipe: function swipeStateInit() { - var swipeSuccess = false; - var container = this.container; - - var originalIndex = findIndex(this.target, this.container.childNodes); - - container.className += ' slip-swiping-container'; - function removeClass() { - container.className = container.className.replace(/(?:^| )slip-swiping-container/,''); - } - - this.target.height = this.target.node.offsetHeight; - - return { - leaveState: function() { - if (swipeSuccess) { - this.animateSwipe(function(target){ - target.node.style[transformPrefix] = target.baseTransform.original; - target.node.style[transitionPrefix] = ''; - if (this.dispatch(target.node, 'afterswipe')) { - removeClass(); - return true; - } else { - this.animateToZero(undefined, target); - } - }.bind(this)); - } else { - this.animateToZero(removeClass); - this.dispatch(this.target.node, 'cancelswipe'); - } - }, - - onMove: function() { - var move = this.getTotalMovement(); - - if (Math.abs(move.y) < this.target.height+20) { - this.target.node.style[transformPrefix] = 'translate(' + move.x + 'px,0) ' + hwLayerMagic + this.target.baseTransform.value; - return false; - } else { - this.setState(this.states.idle); - } - }, - - onLeave: function() { - this.state.onEnd.call(this); - }, - - onEnd: function() { - var dx = this.latestPosition.x - this.previousPosition.x; - var dy = this.latestPosition.y - this.previousPosition.y; - var velocity = Math.sqrt(dx*dx + dy*dy) / (this.latestPosition.time - this.previousPosition.time + 1); - - var move = this.getAbsoluteMovement(); - var swiped = velocity > 0.6 && move.time > 110; - - var direction; - if (dx > 0) { - direction = "right"; - } else { - direction = "left"; - } - - if (swiped) { - if (this.dispatch(this.target.node, 'swipe', {direction: direction, originalIndex: originalIndex})) { - swipeSuccess = true; // can't animate here, leaveState overrides anim - } - } - this.setState(this.states.idle); - return !swiped; - }, - }; - }, - - reorder: function reorderStateInit() { - - this.target.height = getNodeHeight(this.target.node); - this.target.width = getNodeWidth(this.target.node); - - var nodes = this.container.childNodes; - var originalIndex = findIndex(this.target, nodes); - var mouseOutsideTimer; - var zeroY = getNodeTop(this.target.node) + this.target.height/2; - var zeroX = getNodeLeft(this.target.node) + this.target.width/2; - - this.target.rects = getNodeBounds(this.target.node); - this.target.node.rects = this.target.rects; - - this.target.parentList = Array.prototype.slice.call(this.target.node.parentNode.children); - - var otherNodes = []; - var variationInX = false; - var variationInY = false; - - for(var i=0; i < nodes.length; i++) { - if (nodes[i].nodeType != 1 || nodes[i] === this.target.node) continue; - var t = getNodeTop(nodes[i]); - var l = getNodeLeft(nodes[i]); - - nodes[i].style[transitionPrefix] = transformProperty + ' 0.2s ease-in-out'; - if (nodes[i].offsetParent) { - otherNodes.push({ - node: nodes[i], - baseTransform: getTransform(nodes[i]), - rects : getNodeBounds(nodes[i]), - posY: t + (t < zeroY ? getNodeHeight(nodes[i]) : 0) - zeroY, - posX: l + (l < zeroX ? getNodeWidth(nodes[i]) : 0) - zeroX, - }); - nodes[i].rects = getNodeBounds(nodes[i]); - - if (otherNodes[0].posX != otherNodes[otherNodes.length-1].posX) { - variationInX = true; - } - if (otherNodes[0].posY != otherNodes[otherNodes.length-1].posY) { - variationInY = true; - } - if (t != getNodeTop(this.target.node)) { - variationInY = true; - } - if (l != getNodeLeft(this.target.node)) { - variationInX = true; - } - } - } - - this.target.node.className += ' slip-reordering'; - this.target.node.style.zIndex = '99999'; - this.target.node.style[userSelectPrefix] = 'none'; - if (compositorDoesNotOrderLayers) { - // Chrome's compositor doesn't sort 2D layers - this.container.style.webkitTransformStyle = 'preserve-3d'; - } - this.container.origTransform = this.container.style[transformPrefix]; - this.container.origTransformOrigin = this.container.style[transformPrefix + "Origin"]; - this.container.origTransition = this.container.style[transitionPrefix]; - - var containerRects = this.container.getBoundingClientRect(); - if ( - (window.innerHeight < containerRects.height) || - (window.innerWidth < containerRects.width) - ) { - this.container.scale = Math.min( - (window.innerHeight-100)/containerRects.height, - (window.innerWidth)/containerRects.width - ); - - if (this.container.scale < 0.4) { - this.container.scale = 0.4; - }; - - this.container.style[transitionPrefix] = transformProperty + " .3s ease-in-out"; - this.container.style[transformPrefix + "Origin"] = (this.startPosition.x - containerRects.left) + "px " + (this.startPosition.y - containerRects.top) + "px"; - this.container.style[transformPrefix] = "scale(" + this.container.scale + ")"; - document.addEventListener("focus", this.preventFocus, true); - } - - function setPosition() { - /*jshint validthis:true */ - - if (mouseOutsideTimer) { - // don't care where the mouse is as long as it moves - clearTimeout(mouseOutsideTimer); mouseOutsideTimer = null; - } - - var move = this.getTotalMovement(); - if (!variationInX) { - move.x = 0; - } - if (!variationInY) { - move.y = 0; - } - - var targetRects = getNodeBounds(this.target.node); - this.target.node.focus(); - - var yAngleCorrection = Math.sin(2 * Math.PI / 180) * (move.x); - move.y -= yAngleCorrection; - -// this.target.node.style[transformPrefix] = 'translate(0,' + move.y + 'px) ' + hwTopLayerMagic + this.target.baseTransform.value; - this.target.node.style[transformPrefix] = 'rotate(2deg) translate(' + move.x + 'px,' + move.y + 'px) ' + hwTopLayerMagic + this.target.baseTransform.value; - this.target.node.style["animationName"] = 'none'; // FIXME; - // rotate around the position of the mouse to prevent the rotation from selecting text; - // this.target.node.style[transformPrefix + "Origin"] = (this.startPosition.x - targetRects.left) + "px " + (this.startPosition.y - targetRects.top) + "px"; - this.target.node.style[transformPrefix + "Origin"] = this.startOrigin; - - var height = this.target.height; - var width = this.target.width; - var currentTarget = this.target; - - // Set to the middle of the dragged element; - var currentRect = { - top : (currentTarget.rects.top + currentTarget.rects.bottom) / 2, - bottom: (currentTarget.rects.top + currentTarget.rects.bottom) / 2, - left : (currentTarget.rects.left + currentTarget.rects.right) / 2, - right: (currentTarget.rects.left + currentTarget.rects.right) / 2 - }; - - // Offset the mouse position; - currentRect.top += move.y; - currentRect.bottom += move.y; - currentRect.left += move.x; - currentRect.right += move.x; - - var hoverTarget; - - otherNodes.forEach(function(o){ - if ( - (currentRect.right > o.rects.left) && - (currentRect.left < o.rects.right) && - (currentRect.top < o.rects.bottom) && - (currentRect.bottom > o.rects.top) - ) { - hoverTarget = o; - } - return; - }); - - if (!hoverTarget) { - if ( - (currentRect.right > currentTarget.rects.left) && - (currentRect.left < currentTarget.rects.right) && - (currentRect.top < currentTarget.rects.bottom) && - (currentRect.bottom > currentTarget.rects.top) - ) { - // We are hovering over our old spot; - hoverTarget = currentTarget; - } else { - // No target is an exact match, find the closest one; - var bestDeltaMatch = currentTarget; - var delta1, delta2; - - otherNodes.forEach(function(o){ - delta1 = Math.pow((o.rects.top - currentRect.top), 2) + Math.pow((o.rects.right - currentRect.right), 2); - delta2 = Math.pow((bestDeltaMatch.rects.top - currentRect.top), 2) + Math.pow((bestDeltaMatch.rects.right - currentRect.right), 2); - if (delta1 < delta2) { - bestDeltaMatch = o; - } - - return; - }); - hoverTarget = bestDeltaMatch; - } - } - - if (hoverTarget) { - var hoverTargetIndex = currentTarget.parentList.indexOf(hoverTarget.node); - var currentTargetIndex = currentTarget.parentList.indexOf(currentTarget.node); - var beginIndex = Math.min(hoverTargetIndex, currentTargetIndex); - var endIndex = Math.max(hoverTargetIndex, currentTargetIndex); - - for (var i=0; i= beginIndex && index <= endIndex) { - var node1, node2; - if (hoverTargetIndex > currentTargetIndex) { - node1 = currentTarget.parentList[i+1]; - node2 = currentTarget.parentList[i]; - // console.log("swap " + (i+1) + " to " + (i)); - } else { - node1 = currentTarget.parentList[i]; - node2 = currentTarget.parentList[i+1]; - // console.log("swap " + (i) + " to " + (i+1)); - } - - var offY = node2.rects.top - node1.rects.top; - var offX = node2.rects.left - node1.rects.left; - - if (offX === 0) { - offY = (offY > 0) ? currentTarget.height : -currentTarget.height; - } - if (offY === 0) { - offX = (offX > 0) ? currentTarget.width: -currentTarget.width; - } - - // FIXME: should change accelerated/non-accelerated state lazily - // node1.node.style[transformPrefix] = off ? 'translate(0,'+off+'px) ' + hwLayerMagic + o.baseTransform.value : o.baseTransform.original; - otherNodes[i].node.style[transformPrefix] = (offX || offY) ? 'translate('+offX+'px,'+offY+'px) ' + hwLayerMagic + otherNodes[i].baseTransform.value : otherNodes[i].baseTransform.original; - otherNodes[i].node.style["animationName"] = "none"; - } - } - currentTarget.hoverTarget = hoverTarget; - } else { - for (var i=0; i index2) { - this.dispatch(this.target.node, 'reorder', {spliceIndex:index2, insertBefore:currentTarget.parentList[index2], originalIndex: originalIndex}); - } else { - this.dispatch(this.target.node, 'reorder', {spliceIndex:index2+1, insertBefore:currentTarget.parentList[index2+1], originalIndex: originalIndex}); - } - - this.setState(this.states.idle); - return false; - }, - }; - }, - }, - - attach: function(container) { - globalInstances++; - if (this.container) this.detach(); - - // In some cases taps on list elements send *only* click events and no touch events. Spotted only in Chrome 32+ - // Having event listener on body seems to solve the issue (although AFAIK may disable smooth scrolling as a side-effect) - if (!attachedBodyHandlerHack && needsBodyHandlerHack) { - attachedBodyHandlerHack = true; - document.body.addEventListener('touchstart', nullHandler, false); - } - - this.container = container; - this.otherNodes = []; - - document.addEventListener("selectionchange", this.onSelection, false); - - // cancel is called e.g. when iOS detects multitasking gesture - this.container.addEventListener('touchcancel', this.cancel, false); - this.container.addEventListener('touchstart', this.onTouchStart, false); - this.container.addEventListener('touchmove', this.onTouchMove, false); - this.container.addEventListener('touchend', this.onTouchEnd, false); - this.container.addEventListener('mousedown', this.onMouseDown, false); - // mousemove and mouseup are attached dynamically - }, - - detach: function() { - this.cancel(); - - this.container.removeEventListener('mousedown', this.onMouseDown, false); - this.container.removeEventListener('touchend', this.onTouchEnd, false); - this.container.removeEventListener('touchmove', this.onTouchMove, false); - this.container.removeEventListener('touchstart', this.onTouchStart, false); - this.container.removeEventListener('touchcancel', this.cancel, false); - - document.removeEventListener("selectionchange", this.onSelection, false); - - globalInstances--; - if (!globalInstances && attachedBodyHandlerHack) { - attachedBodyHandlerHack = false; - document.body.removeEventListener('touchstart', nullHandler, false); - } - }, - - setState: function(newStateCtor){ - if (this.state) { - if (this.state.ctor === newStateCtor) return; - if (this.state.leaveState) this.state.leaveState.call(this); - } - - // Must be re-entrant in case ctor changes state - var prevState = this.state; - var nextState = newStateCtor.call(this); - if (this.state === prevState) { - nextState.ctor = newStateCtor; - this.state = nextState; - } - }, - - findTargetNode: function(targetNode) { - while(targetNode && targetNode.parentNode !== this.container) { - targetNode = targetNode.parentNode; - } - return targetNode; - }, - - onSelection: function(e) { - var isRelated = e.target === document || this.findTargetNode(e); - if (!isRelated) return; - - this.selectionChanged = true; - }, - - addMouseHandlers: function() { - // unlike touch events, mousemove/up is not conveniently fired on the same element, - // but I don't need to listen to unrelated events all the time - if (!this.mouseHandlersAttached) { - this.mouseHandlersAttached = true; - document.documentElement.addEventListener('mouseleave', this.onMouseLeave, false); - window.addEventListener('mousemove', this.onMouseMove, true); - window.addEventListener('mouseup', this.onMouseUp, true); - window.addEventListener('blur', this.cancel, false); - window.addEventListener("scroll", this.onScroll); - - } - }, - - removeMouseHandlers: function() { - if (this.mouseHandlersAttached) { - this.mouseHandlersAttached = false; - document.documentElement.removeEventListener('mouseleave', this.onMouseLeave, false); - window.removeEventListener('mousemove', this.onMouseMove, true); - window.removeEventListener('mouseup', this.onMouseUp, true); - window.removeEventListener('blur', this.cancel, false); - window.removeEventListener("scroll", this.onScroll); - } - }, - - onMouseLeave: function(e) { - if (this.usingTouch) return; - - if (e.target === document.documentElement || e.relatedTarget === document.documentElement) { - if (this.state.onLeave) { - this.state.onLeave.call(this); - } - } - }, - preventDragStart : function(e) { - e.preventDefault(); - return false; - }, - preventFocus : function(e) { - e.stopPropagation(); - e.target.blur(); - }, - onMouseDown: function(e) { - if (this.usingTouch || e.button != 0 || !this.setTarget(e)) return; - - document.addEventListener("dragstart", this.preventDragStart); - - this.addMouseHandlers(); // mouseup, etc. - - this.canPreventScrolling = true; // or rather it doesn't apply to mouse - - this.startAtPosition({ - x: e.clientX, - y: e.clientY, - time: e.timeStamp, - }); - }, - - onTouchStart: function(e) { - this.usingTouch = true; - this.canPreventScrolling = true; - - // This implementation cares only about single touch - if (e.touches.length > 1) { - this.setState(this.states.idle); - return; - } - - if (!this.setTarget(e)) return; - - this.startAtPosition({ - x: e.touches[0].clientX, - y: e.touches[0].clientY, - time: e.timeStamp, - }); - }, - - setTarget: function(e) { - var targetNode = this.findTargetNode(e.target); - if (!targetNode) { - this.setState(this.states.idle); - return false; - } - - //check for a scrollable parent - var scrollContainer = targetNode.parentNode; - while (scrollContainer){ - if (scrollContainer.scrollHeight > scrollContainer.clientHeight && window.getComputedStyle(scrollContainer)['overflow-y'] != 'visible') break; - else scrollContainer = scrollContainer.parentNode; - } - - this.target = { - originalTarget: e.target, - node: targetNode, - scrollContainer: scrollContainer, - baseTransform: getTransform(targetNode), - }; - return true; - }, - - startAtPosition: function(pos) { - this.startPosition = this.previousPosition = this.latestPosition = pos; - - var targetRects = this.target.node.getBoundingClientRect(); - this.startOrigin = (this.startPosition.x - targetRects.left) + "px " + (this.startPosition.y - targetRects.top) + "px"; - var self = this; - window.setTimeout(function() { - self.selectionChanged = false; - }, 5); - this.setState(this.states.undecided); - var scrollable = this.target.scrollContainer || document.body; - this.scrollTopStart = scrollable.scrollTop; - this.scrollLeftStart = scrollable.scrollLeft; - this.scrollTopDelta = 0; - this.scrollLeftDelta = 0; - }, - - updatePosition: function(e, pos) { - if(this.target == null) - return; - this.latestPosition = pos; - - var triggerOffset = 40, - offset = 0; - - var scrollable = this.target.scrollContainer || document.body, - containerRect = scrollable.getBoundingClientRect(), - targetRect = this.target.node.getBoundingClientRect(), - bottomOffset = Math.min(containerRect.bottom, window.innerHeight) - targetRect.bottom, - topOffset = targetRect.top - Math.max(containerRect.top, 0); - - if (bottomOffset < triggerOffset){ - offset = triggerOffset - bottomOffset; - } - else if (topOffset < triggerOffset){ - offset = topOffset - triggerOffset; - } - - var prevScrollTop = scrollable.scrollTop; -// scrollable.scrollTop += offset; // commented out, this causes issues it seems. When the editor is scrolled down, dragging a form element would cause the page to scroll to top; removing this line prevents that. - if (prevScrollTop != scrollable.scrollTop) this.startPosition.y += prevScrollTop-scrollable.scrollTop; - - if (this.state.onMove) { - if (this.state.onMove.call(this) === false) { - e.preventDefault(); - } - } - - // sample latestPosition 100ms for velocity - if (this.latestPosition.time - this.previousPosition.time > 100) { - this.previousPosition = this.latestPosition; - } - }, - - onScroll : function(e) { - var scrollable = this.target.scrollContainer || document.body; - - this.scrollTopDelta = this.scrollTopStart - scrollable.scrollTop; - this.scrollLeftDelta = this.scrollLeftStart - scrollable.scrollLeft; - - this.updatePosition(e, this.latestPosition); - }, - - onMouseMove: function(e) { - this.updatePosition(e, { - x: e.clientX, - y: e.clientY, - time: e.timeStamp, - }); - }, - - onTouchMove: function(e) { - this.updatePosition(e, { - x: e.touches[0].clientX, - y: e.touches[0].clientY, - time: e.timeStamp, - }); - - // In Apple's touch model only the first move event after touchstart can prevent scrolling (and event.cancelable is broken) - this.canPreventScrolling = false; - }, - - onMouseUp: function(e) { - if (this.usingTouch || e.button !== 0) return; - - if (this.state.onEnd && false === this.state.onEnd.call(this)) { - e.preventDefault(); - } - - document.removeEventListener("dragstart", this.preventDragStart); - document.removeEventListener("focus", this.preventFocus, true); - }, - - onTouchEnd: function(e) { - if (e.touches.length > 1) { - this.cancel(); - } else if (this.state.onEnd && false === this.state.onEnd.call(this)) { - e.preventDefault(); - } - document.removeEventListener("focus", this.preventFocus, true); - }, - - getTotalMovement: function() { - var scale = this.container.scale; - if (typeof scale === "undefined") { - scale = 1; - } - - return { - x:(this.latestPosition.x - this.startPosition.x - this.scrollLeftDelta)/scale, - y:(this.latestPosition.y - this.startPosition.y - this.scrollTopDelta)/scale, - }; - }, - - getAbsoluteMovement: function() { - var scale = this.container.scale; - if (typeof scale === "undefined") { - scale = 1; - } - return { - x: Math.abs(this.latestPosition.x - this.startPosition.x)/scale, - y: Math.abs(this.latestPosition.y - this.startPosition.y)/scale, - time:this.latestPosition.time - this.startPosition.time, - }; - }, - - dispatch: function(targetNode, eventName, detail) { - var event = document.createEvent('CustomEvent'); - if (event && event.initCustomEvent) { - event.initCustomEvent('slip:' + eventName, true, true, detail); - } else { - event = document.createEvent('Event'); - event.initEvent('slip:' + eventName, true, true); - event.detail = detail; - } - return targetNode.dispatchEvent(event); - }, - - getSiblings: function(target) { - var siblings = []; - var tmp = target.node.nextSibling; - while(tmp) { - if (tmp.nodeType == 1) siblings.push({ - node: tmp, - baseTransform: getTransform(tmp), - }); - tmp = tmp.nextSibling; - } - return siblings; - }, - - animateToZero: function(callback, target) { - // save, because this.target/container could change during animation - target = target || this.target; - - target.node.style[transitionPrefix] = transformProperty + ' 0.1s ease-out'; - target.node.style[transformPrefix] = 'translate(0,0) ' + hwLayerMagic + target.baseTransform.value; - setTimeout(function(){ - target.node.style[transitionPrefix] = ''; - target.node.style[transformPrefix] = target.baseTransform.original; - if (callback) callback.call(this, target); - }.bind(this), 101); - }, - - animateSwipe: function(callback) { - var target = this.target; - var siblings = this.getSiblings(target); - var emptySpaceTransform = 'translate(0,' + this.target.height + 'px) ' + hwLayerMagic + ' '; - - // FIXME: animate with real velocity - target.node.style[transitionPrefix] = 'all 0.1s linear'; - target.node.style[transformPrefix] = ' translate(' + (this.getTotalMovement().x > 0 ? '' : '-') + '100%,0) ' + hwLayerMagic + target.baseTransform.value; - - setTimeout(function(){ - if (callback.call(this, target)) { - siblings.forEach(function(o){ - o.node.style[transitionPrefix] = ''; - o.node.style[transformPrefix] = emptySpaceTransform + o.baseTransform.value; - }); - setTimeout(function(){ - siblings.forEach(function(o){ - o.node.style[transitionPrefix] = transformProperty + ' 0.1s ease-in-out'; - o.node.style[transformPrefix] = 'translate(0,0) ' + hwLayerMagic + o.baseTransform.value; - }); - setTimeout(function(){ - siblings.forEach(function(o){ - o.node.style[transitionPrefix] = ''; - o.node.style[transformPrefix] = o.baseTransform.original; - }); - },101); - }, 1); - } - }.bind(this), 101); - }, - }; - - // AMD - if ('function' === typeof define && define.amd) { - define(function(){ - return Slip; - }); - } - return Slip; -})(); \ No newline at end of file diff --git a/www/simply/toolbar.simply-basepack.html b/www/simply/toolbar.simply-basepack.html deleted file mode 100644 index 49bc688..0000000 --- a/www/simply/toolbar.simply-basepack.html +++ /dev/null @@ -1,5372 +0,0 @@ -
-
-
    -
  • - -
  • -
  • - -
  • -
  • - -
  • -
  • - -
  • -
-
-
-
-

*HTML Toolbar for Text Cursor*

-
-
    -
  • -
  • -
  • -
  • -
  • -
-
-
    -
  • -
-
    -
  • -
  • -
  • -
  • -
-
-
-
-
-
    -
  • -
  • -
  • -
  • -
  • -
-
-
-
    -
  • -
  • -
-
-
-
-
-

*HTML Toolbar for Text Selection*

-
-
    -
  • -
  • -
  • -
  • -
  • -
  • -
-
-
    -
  • -
-
    -
  • -
  • -
  • -
  • -
-
-
-
- -
-
    -
  • -
  • -
  • -
  • -
  • -
-
-
-
    -
  • -
  • -
-
-
-
- -
-

HTML Image Toolbar

-
-
    -
  • -
  • -
  • -
  • -
  • -
  • -
-
-
-
-
    -
  • -
  • -
  • -
-
    -
  • -
  • -
  • -
  • -
-
-
-
-
-
-
- -
-
-
-

HTML Image Toolbar

-
-
    -
  • -
  • -
-
-
-
-
-
-
-
-
-
- - -
-
-
    - -
  • -
  • -
  • -
  • - - -
  • - - -
  • -
  • -
-
-
-
-
- - -
-

HTML Iframe Toolbar

-
-
    -
  • -
-
-
-
-
-
-
-

*Objectlist Toolbar*

-
-
    -
  • -
  • -
  • -
-
-
    -
  • -
-
-
-
    -
  • -
-
-
-
-
-

*Objectlist Toolbar*

-
-
    -
  • -
-
-
    -
  • -
-
-
-
-
-

*Objectlist Toolbar*

-
-
    -
  • -
  • -
  • -
  • -
-
-
    -
  • -
-
-
-
    -
  • -
-
-
-
    -
  • -
-
-
-
-
-

Insert icon toolbar

-
-
    -
  • -
-
-
-
-
-
    -
  • -
  • -
  • -
-
-
- - -
-
- -
-
-
-
-
    -
  • -
-
-
- -
-
- -
Saving...
-
Please wait...
-
-
- - -
-
-
    -
  • -
  • -
  • -
- -
-
-
    -
  • -
-
-
- -
-
-
    -
  • - -
  • -
  • -
-
-
- -
-
-
    - -
  • -
-
-
- - -
-
-
    -
  • -
  • -
-
-
-
-
- - -
-
-
    -
  • -
  • -
  • -
  • - -
  • - -
-
-
-
-
Theirs
-
Mine
-
-
-
-
    -
  • Review the differences and choose which of them to use.
  • -
  • -
-
-
- -
-
-
    -
  • -
  • -
  • -
  • -
  • -
-
-
- -
-
-
Your key
-
Valid for
-
- -
-
-
- -
-
-
- - - -
- -
-
-
- - diff --git a/www/simply/toolbar.simply-icon.html b/www/simply/toolbar.simply-icon.html deleted file mode 100644 index ae99d37..0000000 --- a/www/simply/toolbar.simply-icon.html +++ /dev/null @@ -1,16 +0,0 @@ -
-

Insert icon toolbar

-
-
    -
  • -
-
-
- \ No newline at end of file diff --git a/www/simply/toolbar.simply-iframe.html b/www/simply/toolbar.simply-iframe.html deleted file mode 100644 index c90bb69..0000000 --- a/www/simply/toolbar.simply-iframe.html +++ /dev/null @@ -1,82 +0,0 @@ -
-

HTML Iframe Toolbar

-
-
    -
  • -
-
-
-
-
-
- \ No newline at end of file diff --git a/www/simply/toolbar.simply-image.html b/www/simply/toolbar.simply-image.html deleted file mode 100644 index ced290e..0000000 --- a/www/simply/toolbar.simply-image.html +++ /dev/null @@ -1,674 +0,0 @@ -
-

HTML Image Toolbar

-
-
    -
  • -
  • -
  • -
  • -
  • -
  • -
-
-
-
-
    -
  • -
  • -
  • -
-
    -
  • -
  • -
  • -
  • -
-
-
-
-
-
-
- -
-
-
-

HTML Image Toolbar

-
-
    -
  • -
  • -
-
-
-
-
-
-
-
-
-
- - \ No newline at end of file diff --git a/www/simply/toolbar.simply-list.html b/www/simply/toolbar.simply-list.html deleted file mode 100755 index b731669..0000000 --- a/www/simply/toolbar.simply-list.html +++ /dev/null @@ -1,448 +0,0 @@ -
-

*Objectlist Toolbar*

-
-
    -
  • -
  • -
  • -
-
-
    -
  • -
-
-
-
    -
  • -
-
-
-
-
-

*Objectlist Toolbar*

-
-
    -
  • -
-
-
    -
  • -
-
-
-
-
-

*Objectlist Toolbar*

-
-
    -
  • -
  • -
  • -
  • -
-
-
    -
  • -
-
-
-
    -
  • -
-
-
-
    -
  • -
-
-
-
- \ No newline at end of file diff --git a/www/simply/toolbar.simply-main-toolbar.html b/www/simply/toolbar.simply-main-toolbar.html deleted file mode 100755 index 710bba1..0000000 --- a/www/simply/toolbar.simply-main-toolbar.html +++ /dev/null @@ -1,38 +0,0 @@ -
-
-
    -
  • - -
  • -
  • - -
  • -
  • - -
  • -
  • - -
  • -
-
-
- \ No newline at end of file diff --git a/www/simply/toolbar.simply-selectable.html b/www/simply/toolbar.simply-selectable.html deleted file mode 100644 index c6e19df..0000000 --- a/www/simply/toolbar.simply-selectable.html +++ /dev/null @@ -1,167 +0,0 @@ - \ No newline at end of file diff --git a/www/simply/toolbar.simply-text.html b/www/simply/toolbar.simply-text.html deleted file mode 100644 index 76693c5..0000000 --- a/www/simply/toolbar.simply-text.html +++ /dev/null @@ -1,998 +0,0 @@ -
-

*HTML Toolbar for Text Cursor*

-
-
    -
  • -
  • -
  • -
  • -
  • -
-
-
    -
  • -
-
    -
  • -
  • -
  • -
  • -
-
-
-
-
-
    -
  • -
  • -
  • -
  • -
  • -
-
-
-
    -
  • -
  • -
-
-
-
-
-

*HTML Toolbar for Text Selection*

-
-
    -
  • -
  • -
  • -
  • -
  • -
  • -
-
-
    -
  • -
-
    -
  • -
  • -
  • -
  • -
-
-
-
- -
-
    -
  • -
  • -
  • -
  • -
  • -
-
-
-
    -
  • -
  • -
-
-
-
- - \ No newline at end of file diff --git a/www/simply/toolbars.js b/www/simply/toolbars.js deleted file mode 100755 index d01c6e9..0000000 --- a/www/simply/toolbars.js +++ /dev/null @@ -1,1303 +0,0 @@ - editor.toolbar = { - getToolbarEl : function(el) { - while ( el && el.tagName!='div' && !/\bsimply-toolbar\b/.test(el.className) ) { - el = el.parentNode; - } - return el; - }, - getSectionEl : function(el) { - while ( el && el.tagName!='div' && !/\bsimply-toolbar-section\b/.test(el.className) ) { - el = el.parentNode; - } - return el; - }, - getDialogEl : function(el) { - while ( el && el.tagName!='div' && !/\bsimply-dialog\b/.test(el.className) ) { - el = el.parentNode; - } - return el; - }, - handleButton : function(el) { - var toolbar = editor.toolbar.getToolbarEl(el); - var section = editor.toolbar.getSectionEl(el); - var i; - var l; - var selectedSectionButtons; - - if (el.getAttribute("disabled")) { - return true; - } - if ( toolbar ) { - if ( !section ) { - var sections = toolbar.querySelectorAll('.simply-toolbar-section.simply-selected, .simply-toolbar-status'); - for ( i=0, l=sections.length; i/g, ">") - .replace(/"/g, """) - .replace(/'/g, "'"); - }, - findClassNode : function(node, selector) { - // Helper function to find the node for a class - // selector; It searches starting on the given node - // and goes upwards to find the specific node; Only - // parents of the starting node are valid results; - - if (!selector) { - selector = hope.render.html.rules.nestingSets.block.join(","); // default to blocks only - } - var parents = editor.node.parents(node); - var query = ":scope > " + selector.replace(/,/, ', :scope >'); - for (var i=0; i -1) { - return targets[j]; - } - } - } - } - return false; - } - }; - - editor.context = { - touching : false, - skipUpdate : false, - explain : {}, - weigh : function(filter, targets) { - var sel = vdSelectionState.get(); - - var target = targets.shift(); - - var listBonus = false; - if (target && target.clickStart) { - listBonus = true; - } - - if (!filter.context) { - filter.context = "parent"; - } - - if (typeof editor.context.explain[filter.context] === "undefined") { - editor.context.explain[filter.context] = []; - } - editor.context.explain[filter.context].push({ - "filter" : filter, - "targets" : targets - }); - - while (target) { - var tempNode = document.createElement("DIV"); - tempNode.appendChild(target.cloneNode(false)); - - if (typeof editor.context.explain[filter.context] === "undefined") { - editor.context.explain[filter.context] = []; - } - - var result = 0; - if ( - ( (typeof filter.selector !== 'undefined') ? tempNode.querySelectorAll(":scope > " + filter.selector).length : true) && - ( (typeof filter["sel-collapsed"] !== 'undefined') ? (sel.collapsed == filter["sel-collapsed"]) : true) - ) { - editor.context.explain[filter.context].push("click depth score, +" + (50 * (targets.length+1)) + " points"); - result += 50 * (targets.length+1); // tagName weight - if (typeof filter.selector !== 'undefined') { - editor.context.explain[filter.context].push("class selector bonus, +" + (2*(filter.selector.split(".").length-1)) + " points"); - result += 2*(filter.selector.split(".").length-1); // Add the number of class selectors; - editor.context.explain[filter.context].push("attribute selectors bonus, +" + (2*(filter.selector.split("[").length-1)) + " points"); - result += 2*(filter.selector.split("[").length-1); // Add the number of attribute selectors - } - - if (listBonus) { - var rect = target.getBoundingClientRect(); - if ( - target.clickStart.x > rect.left && - target.clickStart.x < rect.right && - target.clickStart.y < rect.bottom && - target.clickStart.y > rect.top - ) { - // click was in the element; less value for lists and list items; - if (target.getAttribute("contenteditable") && filter.context && (typeof filter["list-bonus"] !== 'undefined')) { - editor.context.explain[filter.context].push("filter has list-bonus, but click was in the element, -5 points"); - result -= 5; - } - } else { - // click was outside the element; more value for lists and list items; - if (typeof filter["list-bonus"] !== 'undefined') { - editor.context.explain[filter.context].push("filter has list-bonus, click was outside the element; +" + 50 * (targets.length) + " points"); - result += 50 * (targets.length); - } - } - } - - if (typeof filter["sel-collapsed"] !== 'undefined') { - editor.context.explain[filter.context].push("filters on selection collapsed, +1 point"); - result += 1; - } - if (typeof filter.parent == 'undefined') { - editor.context.explain[filter.context].push("result = " + result); - return result; - } else { - var parentResult = editor.context.weigh(filter.parent, targets); - if (parentResult) { - editor.context.explain[filter.context].push("has parent filter value, +" + parentResult + " points"); - editor.context.explain[filter.context].push(editor.context.explain.parent); - editor.context.explain[filter.context].push("result = " + parseInt(result + parentResult)); - return result + parentResult; - } else { - editor.context.explain[filter.context].push("parent filter did not match, result = 0"); - return 0; - } - } - } - if (!(target.tagName.toLowerCase() == "td" && target.parentNode && target.parentNode.getAttribute("data-simply-list-item"))) { - // Special case for td, because the :before for the list item is set on the TD instead of the TR; We need to keep the list bonus one cycle longer; - listBonus = false; - } - target = targets.shift(); - } - editor.context.explain[filter.context].push("result = 0"); - return 0; - }, - get : function() { - editor.context.explain = {}; - - var sel = vdSelectionState ? vdSelectionState.get() : false; - - if (sel) { - var parent = vdSelection.getNode(sel); - - if ((parent && parent.getAttribute && (parent.getAttribute("contenteditable") || parent.getAttribute("data-simply-selectable"))) || editor.node.hasEditableParent(parent)) { - if (parent || parent.getAttribute || parent.getAttribute("contenteditable")) { - var validFilters = {}; - var bestFilter = false; - var bestFilterWeight = 0; - for (var i in editor.contextFilters) { - var filter = editor.contextFilters[i]; - var filterWeight = editor.context.weigh(filter, editor.node.parents(parent)); - - if (filterWeight) { - validFilters[i] = filterWeight; - if (filterWeight > bestFilterWeight) { - bestFilter = filter.context; - bestFilterWeight = filterWeight; - } - } - } - editor.context.explain.validFilters = validFilters; - - return bestFilter; - } else { - if (sel.collapsed) { - editor.context.explain['simply-text-cursor'] = ["cursor is in a contentEditable field and selection is collapsed."]; - return "simply-text-cursor"; - } else { - editor.context.explain['simply-text-selection'] = ["cursor is in a contentEditable field and selection is not collapsed."]; - return "simply-text-selection"; - } - } - } else { - editor.context.explain['simply-no-context'] = ["selection parent is not editable, not selectable and does not have an editable parent"]; - return "simply-no-context"; - } - } - }, - toolbar : { - getPosition : function(sel, useCursor) { - var ltop, lleft, rleft, rtop, top, left; - - var range = sel; //.getRangeAt(0); - if ( !range ) { - return null; - } - var rects = range.getClientRects(); - var parent = vdSelection.getNode(sel); - - if ( !rects.length ) { - muze.event.fire(range.startContainer, "databinding:pause"); - var focusedElement = document.querySelector(":focus"); - var selStart = focusedElement ? focusedElement.selectionStart : 0; - var selEnd = focusedElement ? focusedElement.selectionEnd : selStart; - - // insert element at range and get its position, other options aren't exact enough - var span = document.createElement('span'); - if ( span.getClientRects ) { - // Ensure span has dimensions and position by - // adding a zero-width space character - try { - span.appendChild( document.createTextNode("\u200b") ); - range.insertNode(span); - rects = span.getClientRects(); - var spanParent = span.parentNode; - spanParent.removeChild(span); - // Glue any broken text nodes back together - spanParent.normalize(); - } catch(e) { - console.log(e); - } - if (focusedElement) { - focusedElement.focus(); // Restore focus after chrome lost it when inserting the span. - focusedElement.selectionStart = selStart; - focusedElement.selectionEnd = selEnd; - } - } - - - muze.event.fire(range.startContainer, "databinding:resume"); - } - if ( rects.length ) { - ltop = rects[0].top; - lleft = rects[0].left; - rleft = rects[rects.length-1].right; - rtop = rects[rects.length-1].bottom; - } - if ( parent && ( !rects.length || (parent.getAttribute("data-simply-selectable") ) ) ) { - pos = parent && parent.getBoundingClientRect ? parent.getBoundingClientRect() : { left: 0, top: 0, right: 0, bottom: 0}; - lleft = pos.left; - ltop = pos.top; - rleft = pos.right; - rtop = pos.bottom; - } - // fallback... if nothing else works - if ( lleft === 0 && rleft === 0 && ltop === 0 && rtop === 0 ) { - parent = vdSelection.parentNode(sel); - if ( !parent || !parent.getBoundingClientRect ) { - return false; - } - pos = parent.getBoundingClientRect(); - lleft = pos.left; - ltop = pos.top; - rleft = pos.right; - rtop = pos.bottom; - } - - if (window.getComputedStyle(document.body).position == "static") { - ltop += Math.max(document.body.scrollTop, document.documentElement.scrollTop); - lleft += Math.max(document.body.scrollLeft, document.documentElement.scrollLeft); - rtop += Math.max(document.body.scrollTop, document.documentElement.scrollTop); - rleft += Math.max(document.body.scrollLeft, document.documentElement.scrollLeft); - } else { - ltop -= document.body.getClientRects()[0].top; - rtop -= document.body.getClientRects()[0].top; - } - - top = Math.max(ltop, rtop); - left = lleft + ((rleft - lleft) / 2); - - return { top: top, left: left, ltop: ltop, lleft: lleft, rtop: rtop, rleft: rleft }; - }, - reposition : function() { - var markerLeft, scrollHeight, scrollTop; - - var sel = vdSelectionState.get(); - var currentContext = editor.context.get(); - var activeSection = editor.toolbarsContainer.getElementById(currentContext); - var pos = editor.context.toolbar.getPosition(sel); - if ( !pos || !activeSection ) { - // editor.context.toolbar.hide = true; - return; - } - - // skip repositioning if the element is - // returning all 0 values, this happens when - // the selection element is no longer in - // view (for instance, pulldown menu element - // which is no longer active). It is better - // to leave the toolbar where it is in this - // case; - if (pos.top === 0 && pos.left === 0 && pos.ltop === 0 && pos.lleft === 0 && pos.rtop === 0 && pos.rleft === 0) { - return; - } - - var top = pos.top; - var left = pos.left; - var activeToolbar = activeSection.querySelector("div.simply-toolbar"); - top += document.body.offsetTop; - var newleft = left - (activeToolbar.offsetWidth/2); - - // Recalculate toolbar position if it is off-screen left/right - if (newleft < document.body.scrollLeft) { - markerLeft = Math.max(activeToolbar.offsetWidth/2 + newleft - document.body.scrollLeft, 20) + "px"; - } else if (newleft + activeToolbar.offsetWidth > document.body.offsetWidth + document.body.scrollLeft) { - var delta = newleft + activeToolbar.offsetWidth - document.body.offsetWidth - document.body.scrollLeft; - markerLeft = Math.min(activeToolbar.offsetWidth/2 + delta, activeToolbar.offsetWidth - 20) + "px"; - } else { - markerLeft = "50%"; - } - activeToolbar.getElementsByClassName("marker")[0].style.left = markerLeft; - - // Recalculate toolbar position if it is off-screen left/right - if (newleft < document.body.scrollLeft) { - newleft = document.body.scrollLeft; - } else if (newleft + activeToolbar.offsetWidth > document.body.offsetWidth + document.body.scrollLeft) { - newleft = document.body.offsetWidth - activeToolbar.offsetWidth + document.body.scrollLeft; - } else { - } - - // Recalculate the toolbar width, the browser messes this up because the buttons are floating; - var buttons = activeToolbar.querySelectorAll("ul.simply-buttons > li"); - var width = activeToolbar.offsetWidth; - var newWidth = 0; - for (var i=0; i editPaneRect.height ) { - // toolbar extends beyond bottom edge if not repositioned - var mintop = Math.min(pos.ltop, pos.rtop); - if ( mintop + toolbarRect.height <= editPaneRect.height ) { - // toolbar can be repositioned - // FIXME: min top should be position of the cursor, not selection - top = editPaneRect.height - toolbarRect.height - 32; // 32 to allow space for scrollbars; - } else { - top = mintop; - scrollHeight = Math.max(document.body.scrollHeight, document.body.clientHeight); - scrollTop = Math.max(document.body.scrollTop, document.documentElement.scrollTop); - if ( scrollTop >= (scrollHeight - document.body.clientHeight - toolbarRect.height ) ) { - // no more scroll space, so add it. - document.body.classList.add('simply-footer-space'); - } - - /* - if ( top + toolbarRect.height > editPaneRect.height ) { - // FIXME: even after adding footer space, we still don't fit. Now what? - } - */ - } - } - - if ( document.body.classList.contains('simply-footer-space') ) { - scrollHeight = Math.max(document.body.scrollHeight, document.body.clientHeight); - scrollTop = Math.max(document.body.scrollTop, document.documentElement.scrollTop); - if ( scrollTop < (scrollHeight - document.body.clientHeight - toolbarRect.height - 132 )) { - document.body.classList.remove('simply-footer-space'); - } - } - activeSection.style.top = top + 10 + "px"; // 10 is the height of the marker arrow - activeSection.style.left = newleft + "px"; - } - }, - show : function() { - var currentContext = editor.context.get(); - - var sections = editor.toolbarsContainer.querySelectorAll("section.simply-section"); - for (var i=0; i -1) { - sections[j].style.left = "-10000px"; - } - } - } - }; - //window.setTimeout(hideIt, 200); - - var activeSection = editor.toolbarsContainer.getElementById(currentContext); - // console.log(activeSection); - - if (activeSection && !editor.context.toolbar.hide) { - var htmlContext = activeSection.querySelectorAll("div.simply-toolbar-status")[0]; - if ( htmlContext ) { - if (!htmlContext.classList.contains("simply-selected")) { - htmlContext.classList.add("simply-selected"); - } - } - // activeSection.style.display = "block"; - activeSection.className += " active"; - hideIt(); // window.setTimeout(hideIt, 200); - - - var sel = vdSelectionState.get(); - var parent = vdSelection.getNode(sel); - if (parent == document) { - return; - } - - editor.context.toolbar.reposition(); - - if (editor.context.touching) { - // FIXME: Android fix here - // restore selection triggers contextupdate, which triggers restore selection - this hopefully prevents that loop. - editor.context.skipUpdate = true; - if (!sel.collapsed) { - // FIXME: This reverses the - // current selection, which - // causes problems selecting - // from right to left; It is - // needed to allow text - // selection on android. - vdSelectionState.restore(sel); - } - window.setTimeout(function() { editor.context.skipUpdate = false;}, 20); - } - } else { - hideIt(); - } - - if (editor.toolbarsContainer.getElementById("VD_DETAILS")) { - if (showBorders) { - editor.toolbarsContainer.getElementById('VD_DETAILS').classList.add('simply-selected'); - } else { - editor.toolbarsContainer.getElementById('VD_DETAILS').classList.remove('simply-selected'); - } - } - - if (editor.toolbarsContainer.getElementById('vdShowTagBoundaries')) { - if (showTagBoundaries) { - editor.toolbarsContainer.getElementById('vdShowTagBoundaries').classList.add('simply-selected'); - } else { - editor.toolbarsContainer.getElementById('vdShowTagBoundaries').classList.remove('simply-selected'); - } - } - - if (editor.toolbarsContainer.getElementById('vdShowTagStack')) { - if (showTagStack) { - editor.toolbarsContainer.getElementById('vdShowTagStack').classList.add('simply-selected'); - } else { - editor.toolbarsContainer.getElementById('vdShowTagStack').classList.remove('simply-selected'); - } - } - }, - initProperties : function(context) { - switch (context) { - case "simply-text-selection" : - case "simply-table-cell-selection": - case "simply-image" : - case "simply-hyperlink" : - editor.context.toolbar.hide = false; - break; - default: - break; - } - - if (editor.toolbars[context] && editor.toolbars[context].update) { - editor.toolbar.updating = true; - editor.toolbars[context].update(editor.toolbarsContainer.getElementById(context)); - editor.toolbar.updating = false; - } - }, - fixSelection : function() { - // check the current selection and update it if necessary - var sel = vdSelectionState.get(); - var parent = vdSelection.getNode(sel); - - // console.log(parent); - var selParent = editor.node.getUneditableParent(parent); - if (selParent) { - // console.log(selParent); - // Selection if part of something uneditable - sel.selectNode(selParent); - sel.startContainer.ownerDocument.defaultView.getSelection().removeAllRanges(); - sel.startContainer.ownerDocument.defaultView.getSelection().addRange(sel); - vdSelectionState.save(sel); - sel.startContainer.ownerDocument.defaultView.getSelection().removeAllRanges(); - } - - }, - getTagStack : function() { - var sel = vdSelectionState.get(); - var parent = vdSelection.getNode(sel); - var newContextStack = []; - - if (sel) { - while (parent && editor.node.hasEditableParent(parent) && parent.parentNode) { - newContextStack.push(parent); - parent=parent.parentNode; - } - } - - return newContextStack; - }, - update : function() { - // Check if the current selection is part of an uneditable thing, if so, move the selection to that parent; - var sel = vdSelectionState.get(); - var parent = vdSelection.getNode(sel); - - // Skip the update when the selection is within a toolbar; - if (editor.node.hasToolbarParent(parent)) { - return; - } - if (document.querySelector(":focus") && editor.node.hasToolbarParent(document.querySelector(":focus"))) { - return; - } - if (editor.context.skipUpdate) { - return; - } - if (editor.context.touching) { - return; - } - if (editor.toolbarsContainer.querySelector(".simply-dialog.active")) { - return; - } - - var field = editor.node.getEditableField(); - hopeEditor = field.hopeEditor; - editor.context.fixSelection(); - if ((typeof hopeEditor !== "undefined") && hopeEditor.needsUpdate) { - hopeEditor.selection.updateRange(); - hopeEditor.parseHTML(); // FIXME: This causes flickering in Firefox and random cursor movement; - hopeEditor.needsUpdate = false; - } - editor.context.show(); - vdHtmlContextStack = editor.context.getTagStack(); - } - }; - - editor.plugins.dialog = { - backdrop : null, - open : function(target, callback) { - vdSelectionState.save(vdSelectionState.get()); - editor.plugins.dialog.selectionIsCollapsed = window.getSelection().isCollapsed; - - if (!editor.plugins.dialog.backdrop) { - editor.plugins.dialog.createBackdrop(); - } - document.body.classList.add("simply-overflow-hidden"); - editor.plugins.dialog.backdrop.style.display = "block"; - target.classList.add("active"); - - editor.plugins.dialog.currentField = editor.node.getEditableField(); - if (editor.plugins.dialog.currentField.hopeEditor) { - editor.plugins.dialog.currentField.hopeEditor.selection.updateRange(); - var range = editor.plugins.dialog.currentField.hopeEditor.selection.getRange(); - editor.plugins.dialog.currentField.hopeEditor.currentRange = range; - } - - if (typeof callback == "function") { - callback(); - } - window.setTimeout(function() { - var sel = window.getSelection(); - sel.removeAllRanges(); - }, 10); - }, - close : function(callback) { - target = editor.toolbarsContainer.querySelector(".simply-dialog.active"); - editor.plugins.dialog.backdrop.style.display = "none"; - document.body.classList.remove("simply-overflow-hidden"); - target.classList.remove("active"); - - var hopeEditor = editor.plugins.dialog.currentField.hopeEditor; - if (hopeEditor) { - editor.fireEvent("databinding:pause", editor.plugins.dialog.currentField); - hopeEditor.parseHTML(); - hopeEditor.update(); - hopeEditor.selection.updateRange(hopeEditor.currentRange.start, hopeEditor.currentRange.end); - hopeEditor.showCursor(); - editor.fireEvent("databinding:resume", editor.plugins.dialog.currentField); - } else { - vdSelectionState.restore(vdSelectionState.get()); - if (editor.plugins.dialog.selectionIsCollapsed) { - window.setTimeout(function() { - var sel = window.getSelection(); - sel.removeAllRanges(); - }, 10); - } - } - vdSelectionState.remove(); - if (typeof callback == "function") { - callback(); - } - }, - createBackdrop : function() { - if (!editor.plugins.dialog.backdrop) { - backdrop = document.createElement("IFRAME"); - backdrop.className = "simply-dialog-backdrop"; - backdrop.style.display = "none"; - backdrop.style.width = "100%"; - backdrop.style.height = "100%"; - backdrop.style.top = 0; - backdrop.style.left = 0; - backdrop.style.position = "fixed"; - backdrop.style.zIndex = 100001; - backdrop.style.border = 0; - backdrop.style.backgroundColor = "rgba(255,255,255,0.7)"; - document.body.appendChild(backdrop); - editor.plugins.dialog.backdrop = backdrop; - } - }, - fullscreen : function(button) { - var dialog = editor.plugins.dialog.getDialogEl(button); - if (dialog.classList.contains("fullscreen")) { - button.classList.remove("simply-selected"); - dialog.classList.remove("fullscreen"); - } else { - button.classList.add("simply-selected"); - dialog.classList.add("fullscreen"); - } - editor.fireEvent("resize", document); - }, - getDialogEl : function(el) { - while ( el && el.tagName!='div' && !/\bsimply-dialog\b/.test(el.className) ) { - el = el.parentNode; - } - return el; - } - }; - editor.addAction("simply-dialog-fullscreen", editor.plugins.dialog.fullscreen); - editor.addAction("simply-dialog-close", editor.plugins.dialog.close); - editor.addAction("simply-main-collapse", function() { - editor.toolbarsContainer.querySelector("#simply-main-toolbar").classList.toggle("simply-collapse"); - }); - - editor.context.toolbar.hide = false; - - document.addEventListener("click", function(event) { - var target = muze.event.target(event); - if( target.tagName.toLowerCase() === 'img' ) { - var range = document.createRange(); - range.selectNode(target); - var sel = window.getSelection(); - sel.removeAllRanges(); - sel.addRange(range); - if (focus in target) { - target.focus(); - } - editor.context.update(); - } - }); - - function monitorIframe() { - // monitor for iframes that get focus; - if (editor.monitor) { - // already monitoring iframes; - return; - } - - editor.monitor = setInterval(function(){ - var elem = document.activeElement; - if(elem && elem.tagName == 'IFRAME'){ - if (editor.context.currentIframe != elem) { - editor.context.currentIframe = elem; - var sel = vdSelectionState.get(); - sel.selectNode(elem); - sel.startContainer.ownerDocument.defaultView.getSelection().removeAllRanges(); - sel.startContainer.ownerDocument.defaultView.getSelection().addRange(sel); - vdSelectionState.save(sel); - sel.startContainer.ownerDocument.defaultView.getSelection().removeAllRanges(); - editor.context.update(); - } - } else { - if (editor.context.currentIframe) { - vdSelectionState.remove(); - vdSelectionState.restore(); - editor.context.update(); - editor.context.currentIframe = null; - } - } - }, 100); - } - - var vdSelection, vdSelectionState; - var initSelections = function() { - if (typeof simply === "undefined" || typeof simply.editor === "undefined") { - window.setTimeout(initSelections, 100); - return; - } - vdSelectionState = simply.editor.selection; - vdSelection = simply.dom.selection; - vdSelectionState.init(window); - simply.editor.selectionchange.start(document); // onselectionchange event for Firefox - - editor.selectionChangeTimer = false; - - muze.event.attach( document, 'selectionchange', function() { - if (editor.selectionChangeTimer) { - return; - } - // throttle selection changed - only execute this once in one loop; - editor.selectionChangeTimer = window.setTimeout(function() { - editor.selectionChangeTimer = false; - var field = editor.node.getEditableField(); - var hopeEditor = field.hopeEditor; - if (hopeEditor) { - if (hopeEditor.field == editor.node.getSimplyParent(document.activeElement)) { - editor.context.hopeEditor = hopeEditor; - hopeEditor.selection.updateRange(); - var range = hopeEditor.selection.getRange(); - hopeEditor.currentRange = range; - } - } - - if (editor.context.touching) { - editor.context.touching = false; // force update when selection changed; - editor.context.update(); - editor.context.touching = true; - } else { - // editor.context.update(); // removed; the update will be triggered by the mouseup/keyup events; - } - }, 0); - }); - - muze.event.attach( document, 'keyup', function(evt) { - // skip context updates when the keyup event is coming from autofilled (username/password) inputs, to prevent looping in chrome when credentials are saved. - try { - if (evt.target && evt.target.matches && evt.target.matches(":-webkit-autofill")) { - return; - } - } catch(e) { - if (e.code !== e.SYNTAX_ERR) { - throw e; - } - if (!e.message.match(":-webkit-autofill")) { - throw e; - } - // catch the error for SyntaxError: ':-webkit-autofill' is not a valid selector, let the rest bubble up; - } - editor.context.update(); - }); - - muze.event.attach( document, 'mouseup', function(evt) { - if (!document.querySelector(":focus")) { - // firefox on mac doesn't set focus for the mouseup until after the event; - evt.target.focus(); - } - editor.context.toolbar.hide = false; - editor.context.update(); - }); - - muze.event.attach( document, 'scroll', editor.context.toolbar.reposition ); - muze.event.attach( document, 'touchstart', function(evt) { - editor.context.touching = true; - }); - muze.event.attach( document, 'touchend', function(evt) { - window.setTimeout(function() { - editor.context.touching = false; - }, 1); - }); - - monitorIframe(); - }; - - initSelections(); \ No newline at end of file
-
-
-
    -
  • - -
  • -
  • - -
  • -
  • - -
  • -
-
-
-
    -
  • - -
  • -
-
-
-
-
- - - -
- Select the users with access to this management screen. They will be able to add, edit and delete - users, as well as restore backups. -
-
-
- -
- SimplyEdit stores at most one backup per hour. When the maximum number of backups is reached, - SimplyEdit will remove the oldest entry whenever a new backup file is created. -
-
-
- -
- Prerender.io is a third-party service that renders a statically cached version of your pages for - a specific set of crawlers and browsers that cannot run javascript natively. -
-
-
-
-
-
-
-
-
    -
  • - -
  • -
  • - -
  • -
  • - -
  • -
  • - -
  • -
  • - -
  • -
  • - -
  • - -
-
-
-
    -
  • - -
  • -
  • - -
  • -
-
-
-
    - -
-
- -
-
-
-
-
-
    -
  • - -
  • -
  • - -
  • -
  • - -
  • -
-
-
-
    -
  • - -
  • -
-
-
-
    -
  • - -
  • -
-
-
- -
-
- -
-
- -
- -

-
-
-
-
- -
-
-
    -
  • - -
  • -
  • - -
  • -
  • - -
  • -
  • - -
  • -
  • - -
  • - -
-
-
-
    - -
-
-
-
-
-
    -
  • - -
  • -
  • - -
  • -
  • - -
  • -
-
-
-

About this dashboard

-

This is the management dashboard for your SimplyEdit website. Here you can manage who can - edit your site and who can manage users and restore backups.

-

This dashboard will also help you install SimplyEdit and show if there are any problems with - your installation.

-

If the Check screen shows 100% green, but you still can't - save your changes in the SimplyEdit editor, it may be that your webserver is configured to deny all - PUT requests. Please contact your system administrator to remedy that.

-

If you still have problems, you can always join us at - https://riot.im/app/#/room/#SimplyEdit:matrix.org and ask for help there.

-
-
-
-
-
    -
  • - -
  • -
  • - -
  • -
  • - -
  • -
  • - -
  • -
-
-
-
    -
  • - -
  • -
-
-
-

The quickstart templates require PHP (at least 5.6) to work

- // -?> -
- - - - -
-
\n", $errors); - } else { - echo 'Congratulations! You are ready to edit your site.'; - } - ?>
-
-
-
-