From 640af8f4d934fb6620cdcf3a1ad6c5569bca556e Mon Sep 17 00:00:00 2001 From: Konstantin Date: Sat, 30 May 2026 11:23:38 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A3=D0=B4=D0=B0=D0=BB=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D0=B5=20=D0=BF=D0=BE=D0=BC=D0=BE=D0=B9=D0=BA=D0=B8=20=D0=B8?= =?UTF-8?q?=D0=B7=20=D0=BF=D1=80=D0=BE=D1=88=D0=BB=D0=BE=D0=B3=D0=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../extension/total/lightshopsets.php | 86 - .../ru-ru/extension/theme/lightshop.php | 396 - .../extension/theme/theme_lightshop_ol.php | 17 - .../ru-ru/extension/total/lightshopsets.php | 15 - .../admin/model/extension/theme/lightshop.php | 805 -- .../model/extension/theme/lightshopblog.php | 413 - .../extension/theme/lightshopblogreview.php | 131 - .../extension/theme/lightshopcatblog.php | 365 - .../model/extension/theme/lightshopnews.php | 298 - .../model/extension/theme/lightshopsets.php | 277 - .../view/image/lightshop/catalog-type1.png | Bin 9882 -> 0 bytes .../view/image/lightshop/catalog-type2.png | Bin 12398 -> 0 bytes .../view/image/lightshop/footer-type-1.png | Bin 6463 -> 0 bytes .../view/image/lightshop/footer-type-2.png | Bin 17266 -> 0 bytes .../view/image/lightshop/header-type-1.png | Bin 3888 -> 0 bytes .../view/image/lightshop/header-type-2.png | Bin 7356 -> 0 bytes .../view/image/lightshop/header-type-3.png | Bin 8000 -> 0 bytes .../view/image/lightshop/lightshop-logo.png | Bin 757 -> 0 bytes .../lightshop/codemirror/lib/codemirror.js | 9690 ----------------- .../lightshop/codemirror/mode/css/css.js | 832 -- .../lightshop/codemirror/mode/css/gss.html | 103 - .../lightshop/codemirror/mode/css/gss_test.js | 17 - .../lightshop/codemirror/mode/css/index.html | 75 - .../lightshop/codemirror/mode/css/less.html | 152 - .../codemirror/mode/css/less_test.js | 54 - .../lightshop/codemirror/mode/css/scss.html | 157 - .../codemirror/mode/css/scss_test.js | 110 - .../lightshop/codemirror/mode/css/test.js | 209 - .../codemirror/mode/javascript/index.html | 114 - .../codemirror/mode/javascript/javascript.js | 896 -- .../codemirror/mode/javascript/json-ld.html | 72 - .../codemirror/mode/javascript/test.js | 482 - .../mode/javascript/typescript.html | 61 - .../css/bootstrap-colorpicker.min.css | 10 - .../colorpicker/js/bootstrap-colorpicker.js | 1327 --- .../lightshop/codemirror/lib/codemirror.css | 346 - .../codemirror/mode/theme/monokai.css | 41 - .../lightshop/lightshop-column-icon.css | 28 - .../view/stylesheet/lightshop/lightshop.css | 601 - .../template/extension/module/lightshop.twig | 47 - .../lightshopcatalog/callback_form.twig | 78 - .../lightshopcatalog/callback_list.twig | 98 - .../lightshopcatalog/lightshop_blog_form.twig | 344 - .../lightshopcatalog/lightshop_blog_list.twig | 85 - .../lightshopcatalog/lightshop_news_form.twig | 263 - .../lightshopcatalog/lightshop_news_list.twig | 84 - .../lightshopcatalog/lightshop_sets_form.twig | 249 - .../lightshopcatalog/lightshop_sets_list.twig | 85 - .../lightshopcatalog/lightshop_tab_form.twig | 247 - .../lightshopcatalog/lightshop_tab_list.twig | 143 - .../lightshopblog_review_form.twig | 114 - .../lightshopblog_review_list.twig | 170 - .../lightshopcatblog_form.twig | 299 - .../lightshopcatblog_list.twig | 87 - .../lightshopcatalog/subscribe_form.twig | 57 - .../lightshopcatalog/subscribe_list.twig | 97 - .../lightshopcatalog/subscribe_mail.twig | 61 - .../extension/theme/theme_lightshop.twig | 4157 ------- .../extension/theme/theme_lightshop_nl.twig | 111 - .../extension/total/lightshopsets.twig | 53 - .../ru-ru/extension/module/lightshop_blog.php | 73 - .../extension/module/lightshop_blog_mod.php | 56 - .../ru-ru/extension/module/lightshop_news.php | 52 - .../ru-ru/extension/module/lightshop_set.php | 8 - .../ru-ru/extension/theme/lightshop.php | 101 - .../ru-ru/extension/total/lightshopsets.php | 2 - .../uk-ua/extension/module/lightshop_blog.php | 70 - .../extension/module/lightshop_blog_mod.php | 57 - .../uk-ua/extension/module/lightshop_news.php | 52 - .../uk-ua/extension/module/lightshop_set.php | 7 - .../uk-ua/extension/theme/lightshop.php | 99 - .../uk-ua/extension/total/lightshopsets.php | 2 - .../model/extension/module/lightshop.php | 430 - .../model/extension/module/lightshopblog.php | 204 - .../extension/module/lightshopcatblog.php | 128 - .../model/extension/module/lightshopnews.php | 48 - .../extension/module/lightshopsubscribe.php | 38 - .../model/extension/total/lightshopsets.php | 52 - .../theme_lightshop/bootstrap.min.js | 13 - .../theme_lightshop/fontawesome/js/all.js | 4523 -------- .../theme_lightshop/fontawesome/js/all.min.js | 5 - .../theme_lightshop/fontawesome/js/brands.js | 586 - .../fontawesome/js/brands.min.js | 5 - .../fontawesome/js/conflict-detection.js | 998 -- .../fontawesome/js/conflict-detection.min.js | 5 - .../fontawesome/js/fontawesome.js | 2539 ----- .../fontawesome/js/fontawesome.min.js | 5 - .../theme_lightshop/fontawesome/js/regular.js | 280 - .../fontawesome/js/regular.min.js | 5 - .../theme_lightshop/fontawesome/js/solid.js | 1130 -- .../fontawesome/js/solid.min.js | 5 - .../fontawesome/js/v4-shims.js | 68 - .../fontawesome/js/v4-shims.min.js | 5 - .../javascript/theme_lightshop/functions.js | 3849 ------- .../theme_lightshop/functions.min.js | 1 - .../theme_lightshop/jquery-2.2.4.min.js | 4 - .../theme_lightshop/jquery-ui.min.js | 7 - .../theme_lightshop/jquery.lazyload.js | 143 - .../javascript/theme_lightshop/widgets.js | 40 - 99 files changed, 40804 deletions(-) delete mode 100644 public/admin/controller/extension/total/lightshopsets.php delete mode 100644 public/admin/language/ru-ru/extension/theme/lightshop.php delete mode 100644 public/admin/language/ru-ru/extension/theme/theme_lightshop_ol.php delete mode 100644 public/admin/language/ru-ru/extension/total/lightshopsets.php delete mode 100644 public/admin/model/extension/theme/lightshop.php delete mode 100644 public/admin/model/extension/theme/lightshopblog.php delete mode 100644 public/admin/model/extension/theme/lightshopblogreview.php delete mode 100644 public/admin/model/extension/theme/lightshopcatblog.php delete mode 100644 public/admin/model/extension/theme/lightshopnews.php delete mode 100644 public/admin/model/extension/theme/lightshopsets.php delete mode 100644 public/admin/view/image/lightshop/catalog-type1.png delete mode 100644 public/admin/view/image/lightshop/catalog-type2.png delete mode 100644 public/admin/view/image/lightshop/footer-type-1.png delete mode 100644 public/admin/view/image/lightshop/footer-type-2.png delete mode 100644 public/admin/view/image/lightshop/header-type-1.png delete mode 100644 public/admin/view/image/lightshop/header-type-2.png delete mode 100644 public/admin/view/image/lightshop/header-type-3.png delete mode 100644 public/admin/view/image/lightshop/lightshop-logo.png delete mode 100644 public/admin/view/javascript/lightshop/codemirror/lib/codemirror.js delete mode 100644 public/admin/view/javascript/lightshop/codemirror/mode/css/css.js delete mode 100644 public/admin/view/javascript/lightshop/codemirror/mode/css/gss.html delete mode 100644 public/admin/view/javascript/lightshop/codemirror/mode/css/gss_test.js delete mode 100644 public/admin/view/javascript/lightshop/codemirror/mode/css/index.html delete mode 100644 public/admin/view/javascript/lightshop/codemirror/mode/css/less.html delete mode 100644 public/admin/view/javascript/lightshop/codemirror/mode/css/less_test.js delete mode 100644 public/admin/view/javascript/lightshop/codemirror/mode/css/scss.html delete mode 100644 public/admin/view/javascript/lightshop/codemirror/mode/css/scss_test.js delete mode 100644 public/admin/view/javascript/lightshop/codemirror/mode/css/test.js delete mode 100644 public/admin/view/javascript/lightshop/codemirror/mode/javascript/index.html delete mode 100644 public/admin/view/javascript/lightshop/codemirror/mode/javascript/javascript.js delete mode 100644 public/admin/view/javascript/lightshop/codemirror/mode/javascript/json-ld.html delete mode 100644 public/admin/view/javascript/lightshop/codemirror/mode/javascript/test.js delete mode 100644 public/admin/view/javascript/lightshop/codemirror/mode/javascript/typescript.html delete mode 100644 public/admin/view/javascript/lightshop/colorpicker/css/bootstrap-colorpicker.min.css delete mode 100644 public/admin/view/javascript/lightshop/colorpicker/js/bootstrap-colorpicker.js delete mode 100644 public/admin/view/stylesheet/lightshop/codemirror/lib/codemirror.css delete mode 100644 public/admin/view/stylesheet/lightshop/codemirror/mode/theme/monokai.css delete mode 100644 public/admin/view/stylesheet/lightshop/lightshop-column-icon.css delete mode 100644 public/admin/view/stylesheet/lightshop/lightshop.css delete mode 100644 public/admin/view/template/extension/module/lightshop.twig delete mode 100644 public/admin/view/template/extension/module/lightshopcatalog/callback_form.twig delete mode 100644 public/admin/view/template/extension/module/lightshopcatalog/callback_list.twig delete mode 100644 public/admin/view/template/extension/module/lightshopcatalog/lightshop_blog_form.twig delete mode 100644 public/admin/view/template/extension/module/lightshopcatalog/lightshop_blog_list.twig delete mode 100644 public/admin/view/template/extension/module/lightshopcatalog/lightshop_news_form.twig delete mode 100644 public/admin/view/template/extension/module/lightshopcatalog/lightshop_news_list.twig delete mode 100644 public/admin/view/template/extension/module/lightshopcatalog/lightshop_sets_form.twig delete mode 100644 public/admin/view/template/extension/module/lightshopcatalog/lightshop_sets_list.twig delete mode 100644 public/admin/view/template/extension/module/lightshopcatalog/lightshop_tab_form.twig delete mode 100644 public/admin/view/template/extension/module/lightshopcatalog/lightshop_tab_list.twig delete mode 100644 public/admin/view/template/extension/module/lightshopcatalog/lightshopblog_review_form.twig delete mode 100644 public/admin/view/template/extension/module/lightshopcatalog/lightshopblog_review_list.twig delete mode 100644 public/admin/view/template/extension/module/lightshopcatalog/lightshopcatblog_form.twig delete mode 100644 public/admin/view/template/extension/module/lightshopcatalog/lightshopcatblog_list.twig delete mode 100644 public/admin/view/template/extension/module/lightshopcatalog/subscribe_form.twig delete mode 100644 public/admin/view/template/extension/module/lightshopcatalog/subscribe_list.twig delete mode 100644 public/admin/view/template/extension/module/lightshopcatalog/subscribe_mail.twig delete mode 100644 public/admin/view/template/extension/theme/theme_lightshop.twig delete mode 100644 public/admin/view/template/extension/theme/theme_lightshop_nl.twig delete mode 100644 public/admin/view/template/extension/total/lightshopsets.twig delete mode 100644 public/store/language/ru-ru/extension/module/lightshop_blog.php delete mode 100644 public/store/language/ru-ru/extension/module/lightshop_blog_mod.php delete mode 100644 public/store/language/ru-ru/extension/module/lightshop_news.php delete mode 100644 public/store/language/ru-ru/extension/module/lightshop_set.php delete mode 100644 public/store/language/ru-ru/extension/theme/lightshop.php delete mode 100644 public/store/language/ru-ru/extension/total/lightshopsets.php delete mode 100644 public/store/language/uk-ua/extension/module/lightshop_blog.php delete mode 100644 public/store/language/uk-ua/extension/module/lightshop_blog_mod.php delete mode 100644 public/store/language/uk-ua/extension/module/lightshop_news.php delete mode 100644 public/store/language/uk-ua/extension/module/lightshop_set.php delete mode 100644 public/store/language/uk-ua/extension/theme/lightshop.php delete mode 100644 public/store/language/uk-ua/extension/total/lightshopsets.php delete mode 100644 public/store/model/extension/module/lightshop.php delete mode 100644 public/store/model/extension/module/lightshopblog.php delete mode 100644 public/store/model/extension/module/lightshopcatblog.php delete mode 100644 public/store/model/extension/module/lightshopnews.php delete mode 100644 public/store/model/extension/module/lightshopsubscribe.php delete mode 100644 public/store/model/extension/total/lightshopsets.php delete mode 100644 public/store/view/javascript/theme_lightshop/bootstrap.min.js delete mode 100644 public/store/view/javascript/theme_lightshop/fontawesome/js/all.js delete mode 100644 public/store/view/javascript/theme_lightshop/fontawesome/js/all.min.js delete mode 100644 public/store/view/javascript/theme_lightshop/fontawesome/js/brands.js delete mode 100644 public/store/view/javascript/theme_lightshop/fontawesome/js/brands.min.js delete mode 100644 public/store/view/javascript/theme_lightshop/fontawesome/js/conflict-detection.js delete mode 100644 public/store/view/javascript/theme_lightshop/fontawesome/js/conflict-detection.min.js delete mode 100644 public/store/view/javascript/theme_lightshop/fontawesome/js/fontawesome.js delete mode 100644 public/store/view/javascript/theme_lightshop/fontawesome/js/fontawesome.min.js delete mode 100644 public/store/view/javascript/theme_lightshop/fontawesome/js/regular.js delete mode 100644 public/store/view/javascript/theme_lightshop/fontawesome/js/regular.min.js delete mode 100644 public/store/view/javascript/theme_lightshop/fontawesome/js/solid.js delete mode 100644 public/store/view/javascript/theme_lightshop/fontawesome/js/solid.min.js delete mode 100644 public/store/view/javascript/theme_lightshop/fontawesome/js/v4-shims.js delete mode 100644 public/store/view/javascript/theme_lightshop/fontawesome/js/v4-shims.min.js delete mode 100644 public/store/view/javascript/theme_lightshop/functions.js delete mode 100644 public/store/view/javascript/theme_lightshop/functions.min.js delete mode 100644 public/store/view/javascript/theme_lightshop/jquery-2.2.4.min.js delete mode 100644 public/store/view/javascript/theme_lightshop/jquery-ui.min.js delete mode 100644 public/store/view/javascript/theme_lightshop/jquery.lazyload.js delete mode 100644 public/store/view/javascript/theme_lightshop/widgets.js diff --git a/public/admin/controller/extension/total/lightshopsets.php b/public/admin/controller/extension/total/lightshopsets.php deleted file mode 100644 index 2a76906..0000000 --- a/public/admin/controller/extension/total/lightshopsets.php +++ /dev/null @@ -1,86 +0,0 @@ -load->language('extension/total/lightshopsets'); - - $this->document->setTitle($this->language->get('heading_title')); - - $this->load->model('setting/setting'); - - if (($this->request->server['REQUEST_METHOD'] == 'POST') && $this->validate()) { - $this->model_setting_setting->editSetting('total_lightshopsets', $this->request->post); - - $this->session->data['success'] = $this->language->get('text_success'); - - $this->response->redirect($this->url->link('marketplace/extension', 'user_token=' . $this->session->data['user_token'] . '&type=total', true)); - } - - $data['heading_title'] = $this->language->get('heading_title'); - - $data['text_edit'] = $this->language->get('text_edit'); - $data['text_enabled'] = $this->language->get('text_enabled'); - $data['text_disabled'] = $this->language->get('text_disabled'); - - $data['entry_status'] = $this->language->get('entry_status'); - $data['entry_sort_order'] = $this->language->get('entry_sort_order'); - - $data['button_save'] = $this->language->get('button_save'); - $data['button_cancel'] = $this->language->get('button_cancel'); - - if (isset($this->error['warning'])) { - $data['error_warning'] = $this->error['warning']; - } else { - $data['error_warning'] = ''; - } - - $data['breadcrumbs'] = array(); - - $data['breadcrumbs'][] = array( - 'text' => $this->language->get('text_home'), - 'href' => $this->url->link('common/dashboard', 'user_token=' . $this->session->data['user_token'], true) - ); - - $data['breadcrumbs'][] = array( - 'text' => $this->language->get('text_extension'), - 'href' => $this->url->link('marketplace/extension', 'user_token=' . $this->session->data['user_token'] . '&type=total', true) - ); - - $data['breadcrumbs'][] = array( - 'text' => $this->language->get('heading_title'), - 'href' => $this->url->link('extension/total/lightshopsets', 'user_token=' . $this->session->data['user_token'], true) - ); - - $data['action'] = $this->url->link('extension/total/lightshopsets', 'user_token=' . $this->session->data['user_token'], true); - - $data['cancel'] = $this->url->link('marketplace/extension', 'user_token=' . $this->session->data['user_token'] . '&type=total', true); - - if (isset($this->request->post['total_lightshopsets_status'])) { - $data['total_lightshopsets_status'] = $this->request->post['total_lightshopsets_status']; - } else { - $data['total_lightshopsets_status'] = $this->config->get('total_lightshopsets_status'); - } - - if (isset($this->request->post['total_lightshopsets_sort_order'])) { - $data['total_lightshopsets_sort_order'] = $this->request->post['total_lightshopsets_sort_order']; - } else { - $data['total_lightshopsets_sort_order'] = $this->config->get('total_lightshopsets_sort_order'); - } - - $data['header'] = $this->load->controller('common/header'); - $data['column_left'] = $this->load->controller('common/column_left'); - $data['footer'] = $this->load->controller('common/footer'); - - $this->response->setOutput($this->load->view('extension/total/lightshopsets', $data)); - } - - protected function validate() { - if (!$this->user->hasPermission('modify', 'extension/total/lightshopsets')) { var_dump($this->user->hasPermission('modify', 'extension/total/lightshopsets')); - $this->error['warning'] = $this->language->get('error_permission'); - } - - return !$this->error; - } - -} diff --git a/public/admin/language/ru-ru/extension/theme/lightshop.php b/public/admin/language/ru-ru/extension/theme/lightshop.php deleted file mode 100644 index cd14c3f..0000000 --- a/public/admin/language/ru-ru/extension/theme/lightshop.php +++ /dev/null @@ -1,396 +0,0 @@ -lazyLoad'; -$_['text_theme_lightshop_js_footorhead'] = 'Вывод js скриптов'; -$_['text_theme_lightshop_js_footorhead_tt'] = 'Вывод js скриптов. Для совместимости со сторонними дополнениями, рекомендуется положение - Вверху сайта'; -$_['text_theme_lightshop_js_footorhead_1'] = 'Вверху сайта'; -$_['text_theme_lightshop_js_footorhead_2'] = 'Внизу сайта'; -$_['text_theme_lightshop_fontawesome'] = 'Иконки fontawesome'; -$_['text_theme_lightshop_fontawesome_tt'] = 'Включите, если стороннее дополенение использует иконки fontawesome'; -$_['text_theme_lightshop_bootstrap'] = 'bootstrap компоненты'; -$_['text_theme_lightshop_bootstrap_tt'] = 'Включите, если стороннее дополенение использует bootstrap компоненты: modals, tooltip, tabs, dropdown'; -$_['text_theme_lightshop_header_type'] = 'Тип шапки'; -$_['text_theme_lightshop_header_type_1'] = 'Только главное меню'; -$_['text_theme_lightshop_header_type_2'] = 'Верхнее и главное меню, стиль 1'; -$_['text_theme_lightshop_header_type_3'] = 'Верхнее и главное меню, стиль 2'; -$_['text_theme_lightshop_header_type3_logo'] = 'Положение логотипа'; -$_['text_theme_lightshop_header_type3_logo_0'] = 'По центру'; -$_['text_theme_lightshop_header_type3_logo_1'] = 'Слева'; -$_['text_theme_lightshop_header_type3_logo_2'] = 'Справа'; -$_['text_theme_lightshop_header_type3_menu'] = 'Пункты в главном меню'; -$_['text_theme_lightshop_fixed_header'] = 'Фикс. меню'; -$_['text_theme_lightshop_fixed_header_tt'] = 'Фиксировать меню вверху сайта при скролле'; -$_['text_theme_lightshop_header_text_logo'] = 'Текстовый логотип или svg код'; -$_['text_theme_lightshop_header_logo'] = 'Логотип'; -$_['text_table_header_navs_0'] = 'Тип'; -$_['text_table_header_navs_1'] = 'Пункт меню'; -$_['text_table_header_navs_2'] = 'Порядок сортировки'; -$_['text_table_header_navs_name'] = 'Название подменю'; -$_['text_table_header_navs_href'] = 'Ссылка(http://)'; -$_['text_table_header_navs_href_0'] = 'Ссылки'; -$_['text_theme_lightshop_max_subcat'] = 'Ограничение категорий'; -$_['text_theme_lightshop_max_subcat_tt'] = 'Ограничить категории 3го уровня'; -$_['text_table_header_navs_1_tt'] = 'Для главных родительских категорий необходимо включить параметр «Главное меню» в настройках категории'; -$_['text_table_main_nav'] = 'Категории (по умолчанию все)'; -$_['text_table_main_add'] = 'Дополнительный элемент подменю'; -$_['text_table_main_add_0'] = 'Главная категория'; -$_['text_table_main_add_1'] = 'Правый элемент подменю 1'; -$_['text_theme_lightshop_main_rec'] = 'Можно использовать html'; -$_['text_theme_lightshop_main_rec_0'] = 'html контент'; -$_['text_theme_lightshop_product_detail'] = 'Быстрый просмотр'; -$_['text_theme_lightshop_product_detail_1'] = 'Вкл. (при клике на название/изображение товара)'; -$_['text_theme_lightshop_product_detail_2'] = 'Вкл. (при клике на кнопку быстрого просмотра)'; -$_['text_theme_lightshop_cart_call'] = 'В корзину'; -$_['text_theme_lightshop_cart_call_tt'] = 'Действие после добавления товара в корзину'; -$_['text_theme_lightshop_cart_call_0'] = 'Показывать подсказку вверху сайта'; -$_['text_theme_lightshop_cart_call_1'] = 'Открывать корзину'; -$_['text_theme_lightshop_category_background'] = 'Фон в каталоге'; -$_['text_theme_lightshop_category_background_tt'] = 'Отображать фоновое изображение в каталоге товаров'; -$_['text_theme_lightshop_category_categories'] = 'Категории в каталоге'; -$_['text_theme_lightshop_category_categories_tt'] = 'Варианты отображения плиток категорий в каталоге'; -$_['text_theme_lightshop_category_categories_0'] = 'Не отображать'; -$_['text_theme_lightshop_category_categories_4'] = 'По 3 в ряд'; -$_['text_theme_lightshop_category_categories_3'] = 'По 4 в ряд'; -$_['text_theme_lightshop_category_categories_2'] = 'По 6 в ряд'; -$_['text_theme_lightshop_category_sorts'] = 'Сортировка'; -$_['text_theme_lightshop_category_sorts_tt'] = 'Отображать варианты сортировки товаров'; -$_['text_theme_lightshop_category_limits'] = 'Лимиты'; -$_['text_theme_lightshop_category_limits_tt'] = 'Отображать лимиты вывода товаров в каталог'; -$_['text_theme_lightshop_pс_view'] = 'Вид каталога (ПК)'; -$_['text_theme_lightshop_pс_view_tt'] = 'Вид каталога товаров по умолчанию в ПК версии сайта, данный параметр на витрине сайта сохраняется в файлах cookies'; -$_['text_theme_lightshop_pс_view_3'] = 'Плитка по 3 товара в ряд'; -$_['text_theme_lightshop_pс_view_4'] = 'Плитка по 4 товара в ряд'; -$_['text_theme_lightshop_pс_view_5'] = 'Плитка по 5 товаров в ряд'; -$_['text_theme_lightshop_pс_view_list'] = 'Лист'; -$_['text_theme_lightshop_pс_view_table'] = 'Таблица'; -$_['text_theme_lightshop_mobile_view'] = 'Вид каталога (моб.)'; -$_['text_theme_lightshop_mobile_view_tt'] = 'Вид каталога товаров по умолчанию в мобильной версии сайта, данный параметр на витрине сайта сохраняется в файлах cookies'; -$_['text_theme_lightshop_mobile_view_main'] = 'Плитка'; -$_['text_theme_lightshop_catalog_type_tt'] = 'Вариант отображения плитки в каталоге товаров'; -$_['text_theme_lightshop_wishlist'] = 'Избранные без регистрации'; -$_['text_theme_lightshop_subcategory'] = 'Вывод в категории товаров из подкатегорий'; -$_['text_theme_lightshop_product_short_descr'] = 'Краткое описание'; -$_['text_theme_lightshop_product_short_tag'] = 'Разделитель краткого описания'; -$_['text_theme_lightshop_product_opt_select'] = 'Опции'; -$_['text_theme_lightshop_product_opt_select_0'] = 'в 2 столбца (по умолчанию)'; -$_['text_theme_lightshop_product_opt_select_'] = 'в 1 столбец'; -$_['text_theme_lightshop_product_att_select'] = 'Атрибуты'; -$_['text_theme_lightshop_product_zoom'] = 'Увеличение изображения'; -$_['text_theme_lightshop_product_zoom_0'] = 'Fancy box (по умолчанию)'; -$_['text_theme_lightshop_product_zoom_1'] = 'Cloud zoom'; -$_['text_theme_lightshop_product_cod'] = 'Код товара'; -$_['text_theme_lightshop_product_cod_0'] = 'model (по умолчанию)'; -$_['text_theme_lightshop_p_related_view'] = 'Рекомендуемые товары'; -$_['text_theme_lightshop_p_related_view_0'] = 'Слайдер (по умолчанию)'; -$_['text_theme_lightshop_p_related_view_3'] = 'Сетка по 3 товара в строке'; -$_['text_theme_lightshop_p_related_view_4'] = 'Сетка по 4 товара в строке'; -$_['text_theme_lightshop_p_related_view_5'] = 'Сетка по 5 товаров в строке'; -$_['text_theme_lightshop_product_review'] = 'Индексируемые отзывы'; -$_['text_theme_lightshop_tag'] = 'тег'; -$_['text_theme_lightshop_metatag'] = 'Метатег'; -$_['text_theme_lightshop_contact_map'] = 'Используемая карта'; -$_['text_theme_lightshop_contact_map_0'] = 'Без карты'; -$_['text_theme_lightshop_contact_map_1'] = 'Google карты'; -$_['text_theme_lightshop_contact_map_2'] = 'Яндекс карты'; -$_['text_theme_lightshop_contact_zoom'] = 'Масштаб карты'; -$_['text_theme_lightshop_contact_zoom_control'] = 'Кнопки увеличения'; -$_['text_theme_lightshop_contact_api_key'] = 'API ключ'; -$_['text_theme_lightshop_contact_api_key_i'] = 'Для получения ключа API Google Maps перейдите по ссылке https://developers.google.com/maps/documentation/geocoding/get-api-key?hl=ru'; -$_['text_theme_lightshop_checkout_st4_title'] = 'Заголовки'; -$_['text_theme_lightshop_checkout_st4_col'] = 'Вид отображения'; -$_['text_theme_lightshop_checkout_st4_col_0'] = 'В 1 колонку'; -$_['text_theme_lightshop_checkout_st4_col_1'] = 'В 2 колонки'; -$_['text_theme_lightshop_checkout_st3_sa'] = 'Адрес доставки'; -$_['text_theme_lightshop_checkout_shipping'] = 'Видимость доставки'; -$_['text_theme_lightshop_checkout_shipping_0'] = 'Скрыть (По умолчанию)'; -$_['text_theme_lightshop_checkout_shipping_1'] = 'Показывать'; -$_['text_theme_lightshop_che_legend'] = 'Поле'; -$_['text_theme_lightshop_che_name'] = 'Название'; -$_['text_theme_lightshop_che_customer_group'] = 'Группа покупателей'; -$_['text_theme_lightshop_che_required'] = 'Обязательно'; -$_['text_theme_lightshop_che_i'] = 'Для добавления дополнительного поля откройте раздел Покупатели > Произвольные поля'; -$_['text_theme_lightshop_che_st2_firstname'] = 'Если значение не задано, используется по умолчанию - Имя'; -$_['text_theme_lightshop_che_st2_lastname'] = 'Если значение не задано, используется по умолчанию - Фамилия'; -$_['text_theme_lightshop_che_st2_email'] = 'Если значение не задано, используется по умолчанию - E-mail'; -$_['text_theme_lightshop_che_st2_telephone'] = 'Если значение не задано, используется по умолчанию - Телефон'; -$_['text_theme_lightshop_che_st2_fax'] = 'Если значение не задано, используется по умолчанию - Факс'; -$_['text_theme_lightshop_che_st2_company'] = 'Если значение не задано, используется по умолчанию - Компания'; -$_['text_theme_lightshop_che_st2_address_1'] = 'Если значение не задано, используется по умолчанию - Адрес'; -$_['text_theme_lightshop_che_st2_address_2'] = 'Если значение не задано, используется по умолчанию - Адрес (дополнительно)'; -$_['text_theme_lightshop_che_st2_city'] = 'Если значение не задано, используется по умолчанию - Город'; -$_['text_theme_lightshop_che_st2_postcode'] = 'Если значение не задано, используется по умолчанию - Индекс'; -$_['text_theme_lightshop_che_st2_country_id'] = 'Если значение не задано, используется по умолчанию - Страна'; -$_['text_theme_lightshop_che_st2_zone_id'] = 'Если значение не задано, используется по умолчанию - Регион / Область'; -$_['text_theme_lightshop_blog_legend'] = 'Общая страница блога'; -$_['text_theme_lightshop_blog_legend_0'] = 'Запись блога'; -$_['text_theme_lightshop_blog_path'] = 'URL блога с категорией'; -$_['text_theme_lightshop_blog_background'] = 'Фон в записи'; -$_['text_theme_lightshop_blog_rev_st'] = 'Разрешить отзывы'; -$_['text_theme_lightshop_blog_rev_guest'] = 'Отзывы от гостей'; -$_['text_theme_lightshop_blog_rev_moder'] = 'Отзывы без модерации'; -$_['text_theme_lightshop_captcha'] = 'Captcha'; -$_['text_theme_lightshop_logo_404'] = 'Изображение'; -$_['text_theme_lightshop_footer_type'] = 'Тип футера'; -$_['text_theme_lightshop_footer_soc_stat'] = 'Соц. сети'; -$_['text_theme_lightshop_footer_text_logo'] = 'Текстовый логотип или svg код'; -$_['text_theme_lightshop_footer_logo'] = 'Логотип внизу сайта'; -$_['text_theme_lightshop_footer_text'] = 'Тектовый блок'; -$_['text_theme_lightshop_footer_copyright'] = 'Копирайт'; -$_['text_theme_lightshop_subscribe_email_alert'] = 'Оповещение e-mail администратору'; -$_['text_theme_lightshop_subscribe_title'] = 'Заголовок'; -$_['text_theme_lightshop_subscribe_subtitle'] = 'Подзаголовок'; -$_['text_theme_lightshop_vidg_extlinks_i'] = 'Дополнительные ссылки могут быть добавлены: Верх сайта > Верхнее мега-меню, Верх сайта > Главное мега-меню, Низ сайта > Нижнее мега-меню.'; -$_['text_theme_lightshop_social_nav'] = 'Соц. сеть'; -$_['text_theme_lightshop_soc_share_prod'] = 'Показывать на страницах товаров'; -$_['text_theme_lightshop_soc_share_blog'] = 'Показывать на страницах блога'; -$_['text_theme_lightshop_soc_share_code'] = 'Код share кнопок'; -$_['text_theme_lightshop_soc_share_code_0'] = 'Код share кнопок'; -$_['text_theme_lightshop_label_legend'] = 'СТИКЕР НОВИНКА'; -$_['text_theme_lightshop_label_legend_0'] = 'СТИКЕР СКИДКА'; -$_['text_theme_lightshop_label_legend_1'] = 'СТИКЕР ХИТ ПРОДАЖ'; -$_['text_theme_lightshop_label_legend_2'] = 'СТИКЕР ПОПУЛЯРНЫЙ ТОВАР'; -$_['text_theme_lightshop_label_legend_3'] = 'СТИКЕР УСПЕЙ КУПИТЬ'; -$_['text_theme_lightshop_label_new_periods'] = 'Активен'; -$_['text_theme_lightshop_label_legend_0_i'] = 'Отображается у товаров где добавлена цена по акции (есть перечеркнутая цена).'; -$_['text_theme_lightshop_label_sale_extra'] = 'Дополнительный элемент'; -$_['text_theme_lightshop_label_legend_1_i'] = 'Продаж'; -$_['text_theme_lightshop_label_hit_period'] = 'За период'; -$_['text_theme_lightshop_label_hit_qty'] = 'Продаж'; -$_['text_theme_lightshop_label_legend_2_i'] = 'Просмотров'; -$_['text_theme_lightshop_label_catch_qty'] = 'Количество'; -$_['text_theme_lightshop_label_catch'] = 'Дополнительное название'; -$_['text_theme_lightshop_order_status_id'] = 'Статус заказа'; -$_['text_theme_lightshop_label_popular_views'] = 'Просмотров'; -$_['text_theme_lightshop_buy_click_i'] = 'Настройки для функционала "Купить в один клик" (в карточке товара, каталоге и быстром просмотре) и "Быстрый заказ" (в стандартной и всплывающей корзине)'; -$_['text_theme_lightshop_scrolltt_pos'] = 'Позиция'; -$_['text_theme_lightshop_pdata_i'] = 'Перед выбором текст нужно добавить в раздел'; -$_['text_theme_lightshop_pdata_i_0'] = 'Каталог > Статьи'; -$_['text_theme_lightshop_callback_pdata'] = 'Заказ звонка'; -$_['text_theme_lightshop_subscribe_pdata'] = 'Форма подписки'; -$_['text_theme_lightshop_buy_click_pdata'] = 'Быстрый заказ'; -$_['text_theme_lightshop_contact_pdata'] = 'Контакты'; -$_['text_theme_lightshop_voucher_pdata'] = 'Сертификат'; -$_['text_theme_lightshop_review_pdata'] = 'Отзывы о товарах'; -$_['text_theme_lightshop_blog_pdata'] = 'Статьи блога'; -$_['text_theme_lightshop_cookies_pdata'] = 'Файлы cookies'; -$_['text_theme_lightshop_ecommerce'] = 'Электронная коммерция'; -$_['text_theme_lightshop_analytics_i'] = 'Код счетчиков можно добавить в '; -$_['text_theme_lightshop_analytics_i_0'] = 'соответствующем разделе панели управления '; -$_['text_theme_lightshop_analytics_ya_status'] = 'Коммерция Яндекс'; -$_['text_theme_lightshop_analytics_goole_status'] = 'Коммерция Google'; -$_['text_theme_lightshop_ecommerce_event'] = 'Общие метки событий'; -$_['text_theme_lightshop_ecommerce_event_i'] = 'Настройка целей для Яндекс.Метрики описана в разделе, используется идентификатор JavaScript-события из списка ниже. Настройка целей для Google Аналитики описана в разделе, используется «Вариант 2. Собственные цели» > Тип: Событие > Действие > Равно > Значение из списка ниже.'; -$_['text_lightshop_callback'] = 'Обратный звонок, форма'; -$_['text_lightshop_addtocart_catalog'] = 'Товар добавлен в корзину, список'; -$_['text_lightshop_addtocart_product'] = 'Товар добавлен в корзину, страница'; -$_['text_lightshop_buyclick'] = 'Купить в 1 клик, форма'; -$_['text_lightshop_buyclick_success'] = 'Купить в 1 клик, success'; -$_['text_lightshop_checkout_success'] = 'Стандартный заказ, success'; -$_['text_lightshop_settocart'] = 'Набор добавлен в корзину'; -$_['text_lightshop_subscribe'] = 'Подписался на новости, форма'; -$_['text_lightshop_contact'] = 'Форма обратной связи'; -$_['text_theme_lightshop_messenger_td'] = 'Мессенджер'; -$_['text_theme_lightshop_messenger_td_0'] = 'Идентификатор'; -$_['text_version'] = 'Версия'; -$_['text_new_version'] = 'Доступна новая версия'; -$_['text_support'] = 'Техническая поддержка'; -$_['text_support_0'] = 'Для продления технической поддержки напишите пожалуйста нам на почту'; -$_['text_support_1'] = 'Отправить запрос в службу поддержки:'; -$_['text_899themes'] = 'Разработчик'; -$_['text_license_0'] = 'Лицензионное соглашение'; -$_['text_theme_lightshop_news_limit'] = 'Сколько новостей показывать на одной странице'; -$_['text_theme_lightshop_blog_limit'] = 'Сколько записей блога показывать на одной странице'; -$_['text_theme_lightshop_title'] = 'Заголовок'; -$_['text_theme_lightshop_subtitle'] = 'Подзаголовок'; -$_['text_theme_lightshop_qty'] = 'Количество'; -$_['text_theme_lightshop_category_products'] = 'Товары с нулевым остатком'; -$_['text_theme_lightshop_category_products_0'] = 'По умолчанию'; -$_['text_theme_lightshop_category_products_1'] = 'Выводить в конце каталога'; - -// Entry -$_['entry_directory'] = 'Папка шаблона'; -$_['entry_status'] = 'Статус'; -$_['entry_product_limit'] = 'На странице'; -$_['entry_product_description_length'] = 'Краткое описание'; -$_['entry_image_category'] = 'Категории (Ш x В)'; -$_['entry_image_thumb'] = 'Миниатюры (Ш x В)'; -$_['entry_image_popup'] = 'Всплывающие (Ш x В)'; -$_['entry_image_product'] = 'Товара (Ш x В)'; -$_['entry_image_additional'] = 'Дополнительные (Ш x В)'; -$_['entry_image_related'] = 'Рекомендуемые (Ш x В)'; -$_['entry_image_compare'] = 'В сравнении (Ш x В)'; -$_['entry_image_wishlist'] = 'Закладки (Ш x В)'; -$_['entry_image_cart'] = 'В корзине (Ш x В)'; -$_['entry_image_location'] = 'Изображение магазина (Ш x В)'; -$_['entry_width'] = 'Ширина'; -$_['entry_height'] = 'Высота'; - -// Help -$_['help_directory'] = 'Это поле только для выбора старых шаблонов, что бы сделать их совместимыми с новым движком Opencart.'; -$_['help_product_limit'] = 'Сколько элементов показывать на одной странице (товары, категории, и т.п.)'; -$_['help_product_description_length'] = 'Сколько знаков показывать из описания товара в режиме список.'; -$_['help_product_tabs_main'] = 'Вкладка выводится в карточке товара после отзывов, всплывающее окно перед опциями в карточке товара и в быстром просмотре.'; -$_['help_product_tabs_select'] = 'Если товары не выбраны то вкладка показывается во всех товарах.'; -$_['help_product_tabs_cat_select'] = 'Если категории не выбраны то вкладка показывается во всех товарах.'; - -// Error -$_['error_permission'] = 'У вас не достаточно прав!'; -$_['error_limit'] = 'Укажите количество символов в кратком описании товара для режима список!'; -$_['error_image_thumb'] = 'Укажите размер миниатюр!'; -$_['error_image_popup'] = 'Укажите размер всплывающих изображений товара!'; -$_['error_image_product'] = 'Укажите размер изображения для товаров!'; -$_['error_image_category'] = 'Укажите размер изображения для категорий!'; -$_['error_image_additional'] = 'Укажите размер дополнительных изображений товара!'; -$_['error_image_related'] = 'Укажите размер изображений для рекомендуемых (похожих) товаров!'; -$_['error_image_compare'] = 'Укажите размер изображений товара для списка сравнений!'; -$_['error_image_wishlist'] = 'Укажите размер изображений товара для закладок!'; -$_['error_image_cart'] = 'Укажите размер изображений товара для корзины!'; -$_['error_image_location'] = 'Укажите размер изображений магазина!'; diff --git a/public/admin/language/ru-ru/extension/theme/theme_lightshop_ol.php b/public/admin/language/ru-ru/extension/theme/theme_lightshop_ol.php deleted file mode 100644 index 2137e26..0000000 --- a/public/admin/language/ru-ru/extension/theme/theme_lightshop_ol.php +++ /dev/null @@ -1,17 +0,0 @@ -db->query("INSERT INTO " . DB_PREFIX . "lightshop_blog SET sort_order = 0, bottom = '" . (isset($data['bottom']) ? (int)$data['bottom'] : 0) . "', status = '" . (int)$data['status'] . "', date_added = '" . $this->db->escape($data['date_added']) . "'"); - }else{ - $this->db->query("INSERT INTO " . DB_PREFIX . "lightshop_blog SET sort_order = 0, bottom = '" . (isset($data['bottom']) ? (int)$data['bottom'] : 0) . "', status = '" . (int)$data['status'] . "', date_added = NOW()"); - } - $blog_id = $this->db->getLastId(); - - if (isset($data['image'])) { - $this->db->query("UPDATE " . DB_PREFIX . "lightshop_blog SET image = '" . $this->db->escape($data['image']) . "' WHERE blog_id = '" . (int)$blog_id . "'"); - } - - foreach ($data['blog_description'] as $language_id => $value) { - $this->db->query("INSERT INTO " . DB_PREFIX . "lightshop_blog_description SET blog_id = '" . (int)$blog_id . "', language_id = '" . (int)$language_id . "', title = '" . $this->db->escape($value['title']) . "', description = '" . $this->db->escape($value['description']) . "', meta_title = '" . $this->db->escape($value['meta_title']) . "', meta_h1 = '" . $this->db->escape($value['meta_h1']) . "', meta_description = '" . $this->db->escape($value['meta_description']) . "', meta_keyword = '" . $this->db->escape($value['meta_keyword']) . "'"); - if($value['tag']){ - foreach (explode(',',$value['tag']) as $tag) { - $this->db->query("INSERT INTO " . DB_PREFIX . "lightshop_blog_tag SET blog_id = '" . (int)$blog_id . "', language_id = '" . (int)$language_id . "', tag = '" . $this->db->escape(trim($tag)) . "'"); - } - } - } - - if (isset($data['blog_store'])) { - foreach ($data['blog_store'] as $store_id) { - $this->db->query("INSERT INTO " . DB_PREFIX . "lightshop_blog_to_store SET blog_id = '" . (int)$blog_id . "', store_id = '" . (int)$store_id . "'"); - } - } - - if (isset($data['blog_related'])) { - foreach ($data['blog_related'] as $related_id) { - $this->db->query("DELETE FROM " . DB_PREFIX . "lightshop_blog_related WHERE blog_id = '" . (int)$blog_id . "' AND related_id = '" . (int)$related_id . "'"); - $this->db->query("INSERT INTO " . DB_PREFIX . "lightshop_blog_related SET blog_id = '" . (int)$blog_id . "', related_id = '" . (int)$related_id . "'"); - } - } - - if (isset($data['product_related'])) { - foreach ($data['product_related'] as $related_id) { - $this->db->query("DELETE FROM " . DB_PREFIX . "lightshop_blog_related_prod WHERE blog_id = '" . (int)$blog_id . "' AND related_id = '" . (int)$related_id . "'"); - $this->db->query("INSERT INTO " . DB_PREFIX . "lightshop_blog_related_prod SET blog_id = '" . (int)$blog_id . "', related_id = '" . (int)$related_id . "'"); - } - } - - if (isset($data['blog_layout'])) { - foreach ($data['blog_layout'] as $store_id => $layout_id) { - $this->db->query("INSERT INTO " . DB_PREFIX . "lightshop_blog_to_layout SET blog_id = '" . (int)$blog_id . "', store_id = '" . (int)$store_id . "', layout_id = '" . (int)$layout_id . "'"); - } - } - - // SEO URL - if (isset($data['blog_seo_url'])) { - foreach ($data['blog_seo_url'] as $store_id => $language) { - foreach ($language as $language_id => $keyword) { - if (!empty($keyword)) { - $this->db->query("INSERT INTO " . DB_PREFIX . "seo_url SET store_id = '" . (int)$store_id . "', language_id = '" . (int)$language_id . "', query = 'blog_id=" . (int)$blog_id . "', keyword = '" . $this->db->escape($keyword) . "'"); - } - } - } - } - - if(isset($data['main_category_id']) && $data['main_category_id'] > 0) { - $this->db->query("DELETE FROM " . DB_PREFIX . "lightshop_blog_to_category WHERE blog_id = '" . (int)$blog_id . "' AND category_id = '" . (int)$data['main_category_id'] . "'"); - $this->db->query("INSERT INTO " . DB_PREFIX . "lightshop_blog_to_category SET blog_id = '" . (int)$blog_id . "', category_id = '" . (int)$data['main_category_id'] . "', main_category = 1"); - } - - $this->cache->delete('blog'); - - return $blog_id; - } - - public function editBlog($blog_id, $data) { - $this->db->query("UPDATE " . DB_PREFIX . "lightshop_blog SET sort_order = 0, bottom = '" . (isset($data['bottom']) ? (int)$data['bottom'] : 0) . "', status = '" . (int)$data['status'] . "', date_added = '" . $this->db->escape($data['date_added']) . "' WHERE blog_id = '" . (int)$blog_id . "'"); - - if (isset($data['image'])) { - $this->db->query("UPDATE " . DB_PREFIX . "lightshop_blog SET image = '" . $this->db->escape($data['image']) . "' WHERE blog_id = '" . (int)$blog_id . "'"); - } - - $this->db->query("DELETE FROM " . DB_PREFIX . "lightshop_blog_description WHERE blog_id = '" . (int)$blog_id . "'"); - $this->db->query("DELETE FROM " . DB_PREFIX . "lightshop_blog_tag WHERE blog_id = '" . (int)$blog_id . "'"); - - foreach ($data['blog_description'] as $language_id => $value) { - $this->db->query("INSERT INTO " . DB_PREFIX . "lightshop_blog_description SET blog_id = '" . (int)$blog_id . "', language_id = '" . (int)$language_id . "', title = '" . $this->db->escape($value['title']) . "', description = '" . $this->db->escape($value['description']) . "', meta_title = '" . $this->db->escape($value['meta_title']) . "', meta_h1 = '" . $this->db->escape($value['meta_h1']) . "', meta_description = '" . $this->db->escape($value['meta_description']) . "', meta_keyword = '" . $this->db->escape($value['meta_keyword']) . "'"); - if($value['tag']){ - foreach (explode(',',$value['tag']) as $tag) { - $this->db->query("INSERT INTO " . DB_PREFIX . "lightshop_blog_tag SET blog_id = '" . (int)$blog_id . "', language_id = '" . (int)$language_id . "', tag = '" . $this->db->escape(trim($tag)) . "'"); - } - } - } - - - $this->db->query("DELETE FROM " . DB_PREFIX . "lightshop_blog_to_store WHERE blog_id = '" . (int)$blog_id . "'"); - - if (isset($data['blog_store'])) { - foreach ($data['blog_store'] as $store_id) { - $this->db->query("INSERT INTO " . DB_PREFIX . "lightshop_blog_to_store SET blog_id = '" . (int)$blog_id . "', store_id = '" . (int)$store_id . "'"); - } - } - - $this->db->query("DELETE FROM " . DB_PREFIX . "lightshop_blog_to_layout WHERE blog_id = '" . (int)$blog_id . "'"); - - if (isset($data['blog_layout'])) { - foreach ($data['blog_layout'] as $store_id => $layout_id) { - $this->db->query("INSERT INTO " . DB_PREFIX . "lightshop_blog_to_layout SET blog_id = '" . (int)$blog_id . "', store_id = '" . (int)$store_id . "', layout_id = '" . (int)$layout_id . "'"); - } - } - - $this->db->query("DELETE FROM " . DB_PREFIX . "lightshop_blog_related WHERE blog_id = '" . (int)$blog_id . "'"); - - - if (isset($data['blog_related'])) { - foreach ($data['blog_related'] as $related_id) { - $this->db->query("DELETE FROM " . DB_PREFIX . "lightshop_blog_related WHERE blog_id = '" . (int)$blog_id . "' AND related_id = '" . (int)$related_id . "'"); - $this->db->query("INSERT INTO " . DB_PREFIX . "lightshop_blog_related SET blog_id = '" . (int)$blog_id . "', related_id = '" . (int)$related_id . "'"); - } - } - - $this->db->query("DELETE FROM " . DB_PREFIX . "lightshop_blog_related_prod WHERE blog_id = '" . (int)$blog_id . "'"); - - if (isset($data['product_related'])) { - foreach ($data['product_related'] as $related_id) { - $this->db->query("DELETE FROM " . DB_PREFIX . "lightshop_blog_related_prod WHERE blog_id = '" . (int)$blog_id . "' AND related_id = '" . (int)$related_id . "'"); - $this->db->query("INSERT INTO " . DB_PREFIX . "lightshop_blog_related_prod SET blog_id = '" . (int)$blog_id . "', related_id = '" . (int)$related_id . "'"); - } - } - - $this->db->query("DELETE FROM " . DB_PREFIX . "seo_url WHERE query = 'blog_id=" . (int)$blog_id . "'"); - - // SEO URL - if (isset($data['blog_seo_url'])) { - foreach ($data['blog_seo_url'] as $store_id => $language) { - foreach ($language as $language_id => $keyword) { - if (!empty($keyword)) { - $this->db->query("INSERT INTO " . DB_PREFIX . "seo_url SET store_id = '" . (int)$store_id . "', language_id = '" . (int)$language_id . "', query = 'blog_id=" . (int)$blog_id . "', keyword = '" . $this->db->escape($keyword) . "'"); - } - } - } - } - - $this->db->query("DELETE FROM " . DB_PREFIX . "lightshop_blog_to_category WHERE blog_id = '" . (int)$blog_id . "'"); - - if(isset($data['main_category_id']) && $data['main_category_id'] > 0) { - $this->db->query("INSERT INTO " . DB_PREFIX . "lightshop_blog_to_category SET blog_id = '" . (int)$blog_id . "', category_id = '" . (int)$data['main_category_id'] . "', main_category = 1"); - } - - $this->cache->delete('blog'); - } - - public function deleteBlog($blog_id) { - $this->db->query("DELETE FROM " . DB_PREFIX . "lightshop_blog WHERE blog_id = '" . (int)$blog_id . "'"); - $this->db->query("DELETE FROM " . DB_PREFIX . "lightshop_blog_description WHERE blog_id = '" . (int)$blog_id . "'"); - $this->db->query("DELETE FROM " . DB_PREFIX . "lightshop_blog_to_store WHERE blog_id = '" . (int)$blog_id . "'"); - $this->db->query("DELETE FROM " . DB_PREFIX . "lightshop_blog_to_category WHERE blog_id = '" . (int)$blog_id . "'"); - $this->db->query("DELETE FROM " . DB_PREFIX . "lightshop_blog_to_layout WHERE blog_id = '" . (int)$blog_id . "'"); - $this->db->query("DELETE FROM " . DB_PREFIX . "seo_url WHERE query = 'blog_id=" . (int)$blog_id . "'"); - $this->db->query("DELETE FROM " . DB_PREFIX . "lightshop_blog_related WHERE blog_id = '" . (int)$blog_id . "'"); - $this->db->query("DELETE FROM " . DB_PREFIX . "lightshop_blog_tag WHERE blog_id = '" . (int)$blog_id . "'"); - $this->db->query("DELETE FROM " . DB_PREFIX . "lightshop_blog_related WHERE related_id = '" . (int)$blog_id . "'"); - $this->db->query("DELETE FROM " . DB_PREFIX . "lightshop_blog_related_prod WHERE blog_id = '" . (int)$blog_id . "'"); - $this->db->query("DELETE FROM " . DB_PREFIX . "lightshop_blog_comment WHERE blog_id = '" . (int)$blog_id . "'"); - - $this->cache->delete('blog'); - } - - public function getBlog($blog_id) { - $query = $this->db->query("SELECT DISTINCT *, (SELECT keyword FROM " . DB_PREFIX . "seo_url WHERE query = 'blog_id=" . (int)$blog_id . "' LIMIT 1) AS keyword FROM " . DB_PREFIX . "lightshop_blog i LEFT JOIN " . DB_PREFIX . "lightshop_blog_description id ON (i.blog_id = id.blog_id) WHERE i.blog_id = '" . (int)$blog_id . "'"); - - return $query->row; - } - - public function getBlogTag($blog_id) { - $query = $this->db->query("SELECT * FROM " . DB_PREFIX . "lightshop_blog_tag WHERE blog_id = '" . (int)$blog_id . "'"); - - return $query->rows; - } - - public function getBlogSeoUrls($blog_id) { - $blog_seo_url_data = array(); - - $query = $this->db->query("SELECT * FROM " . DB_PREFIX . "seo_url WHERE query = 'blog_id=" . (int)$blog_id . "'"); - - foreach ($query->rows as $result) { - $blog_seo_url_data[$result['store_id']][$result['language_id']] = $result['keyword']; - } - - return $blog_seo_url_data; - } - - public function getBlogs($data = array()) { - - $this->createTable(); - - if ($data) { - $sql = "SELECT * FROM " . DB_PREFIX . "lightshop_blog i LEFT JOIN " . DB_PREFIX . "lightshop_blog_description id ON (i.blog_id = id.blog_id) WHERE id.language_id = '" . (int)$this->config->get('config_language_id') . "'"; - - if (!empty($data['filter_name'])) { - $sql .= " AND id.title LIKE '" . $this->db->escape($data['filter_name']) . "%'"; - } - - $sort_data = array( - 'id.title', - 'i.sort_order', - 'i.date_added' - ); - - if (isset($data['sort']) && in_array($data['sort'], $sort_data)) { - $sql .= " ORDER BY " . $data['sort']; - } else { - $sql .= " ORDER BY i.date_added"; - } - - if (isset($data['order']) && ($data['order'] == 'DESC')) { - $sql .= " DESC"; - } else { - $sql .= " ASC"; - } - - if (isset($data['start']) || isset($data['limit'])) { - if ($data['start'] < 0) { - $data['start'] = 0; - } - - if ($data['limit'] < 1) { - $data['limit'] = 20; - } - - $sql .= " LIMIT " . (int)$data['start'] . "," . (int)$data['limit']; - } - - $query = $this->db->query($sql); - - return $query->rows; - } else { - $blog_data = $this->cache->get('blog.' . (int)$this->config->get('config_language_id')); - - if (!$blog_data) { - $query = $this->db->query("SELECT * FROM " . DB_PREFIX . "lightshop_blog i LEFT JOIN " . DB_PREFIX . "lightshop_blog_description id ON (i.blog_id = id.blog_id) WHERE id.language_id = '" . (int)$this->config->get('config_language_id') . "' ORDER BY id.title"); - - $blog_data = $query->rows; - - $this->cache->set('blog.' . (int)$this->config->get('config_language_id'), $blog_data); - } - - return $blog_data; - } - } - - public function getBlogDescriptions($blog_id) { - $blog_description_data = array(); - - $query = $this->db->query("SELECT * FROM " . DB_PREFIX . "lightshop_blog_description WHERE blog_id = '" . (int)$blog_id . "'"); - - foreach ($query->rows as $result) { - - $tag = ''; - $temp = array(); - $query1 = $this->db->query("SELECT tag FROM " . DB_PREFIX . "lightshop_blog_tag WHERE blog_id = '" . (int)$blog_id . "' AND language_id = '" . (int)$result['language_id'] . "'"); - - if($query1->num_rows){ - foreach ($query1->rows as $value) { - $temp[] = $value['tag']; - } - $tag = implode(',', $temp); - } - - $blog_description_data[$result['language_id']] = array( - 'title' => $result['title'], - 'description' => $result['description'], - 'meta_title' => $result['meta_title'], - 'meta_h1' => $result['meta_h1'], - 'meta_description' => $result['meta_description'], - 'meta_keyword' => $result['meta_keyword'], - 'tag' => $tag - ); - } - - return $blog_description_data; - } - - public function getBlogStores($blog_id) { - $blog_store_data = array(); - - $query = $this->db->query("SELECT * FROM " . DB_PREFIX . "lightshop_blog_to_store WHERE blog_id = '" . (int)$blog_id . "'"); - - foreach ($query->rows as $result) { - $blog_store_data[] = $result['store_id']; - } - - return $blog_store_data; - } - - public function getBlogLayouts($blog_id) { - $blog_layout_data = array(); - - $query = $this->db->query("SELECT * FROM " . DB_PREFIX . "lightshop_blog_to_layout WHERE blog_id = '" . (int)$blog_id . "'"); - - foreach ($query->rows as $result) { - $blog_layout_data[$result['store_id']] = $result['layout_id']; - } - - return $blog_layout_data; - } - - public function getTotalBlogs() { - $query = $this->db->query("SELECT COUNT(*) AS total FROM " . DB_PREFIX . "lightshop_blog"); - - return $query->row['total']; - } - - public function getTotalBlogsByLayoutId($layout_id) { - $query = $this->db->query("SELECT COUNT(*) AS total FROM " . DB_PREFIX . "lightshop_blog_to_layout WHERE layout_id = '" . (int)$layout_id . "'"); - - return $query->row['total']; - } - - public function getBlogRelated($blog_id) { - $blog_related_data = array(); - - $query = $this->db->query("SELECT * FROM " . DB_PREFIX . "lightshop_blog_related WHERE blog_id = '" . (int)$blog_id . "'"); - - foreach ($query->rows as $result) { - $blog_related_data[] = $result['related_id']; - } - - return $blog_related_data; - } - - public function getBlogRelatedProds($blog_id) { - $product_related_data = array(); - - $query = $this->db->query("SELECT * FROM " . DB_PREFIX . "lightshop_blog_related_prod WHERE blog_id = '" . (int)$blog_id . "'"); - - foreach ($query->rows as $result) { - $product_related_data[] = $result['related_id']; - } - - return $product_related_data; - } - - public function getBlogMainCategoryId($blog_id) { - $query = $this->db->query("SELECT category_id FROM " . DB_PREFIX . "lightshop_blog_to_category WHERE blog_id = '" . (int)$blog_id . "' AND main_category = '1' LIMIT 1"); - - return ($query->num_rows ? (int)$query->row['category_id'] : 0); - } - - public function getCommentNewCount() { - - $this->db->query(" - CREATE TABLE IF NOT EXISTS " . DB_PREFIX . "lightshop_blog_comment ( - `comment_id` int(11) NOT NULL AUTO_INCREMENT, - `blog_id` int(11) NOT NULL, - `customer_id` int(11) NOT NULL, - `author` varchar(64) NOT NULL, - `text` text NOT NULL, - `rating` int(1) NOT NULL, - `status` tinyint(1) NOT NULL DEFAULT '0', - `date_added` datetime NOT NULL, - `date_modified` datetime NOT NULL, - PRIMARY KEY (`comment_id`) - ) ENGINE=MyISAM DEFAULT CHARSET=utf8; - "); - - $query = $this->db->query("SELECT COUNT(status) as total FROM " . DB_PREFIX . "lightshop_blog_comment WHERE status = '0'"); - - return $query->row; - } - - public function createTable() { - $this->db->query(" - CREATE TABLE IF NOT EXISTS " . DB_PREFIX . "lightshop_blog ( - `blog_id` int(11) NOT NULL AUTO_INCREMENT, - `bottom` int(1) NOT NULL DEFAULT '0', - `sort_order` int(3) NOT NULL DEFAULT '0', - `status` tinyint(1) NOT NULL DEFAULT '1', - `date_added` date NOT NULL, - PRIMARY KEY (`blog_id`) - ) ENGINE=MyISAM DEFAULT CHARSET=utf8; - "); - $this->db->query(" - CREATE TABLE IF NOT EXISTS " . DB_PREFIX . "lightshop_blog_description ( - `blog_id` int(11) NOT NULL, - `language_id` int(11) NOT NULL, - `title` varchar(200) NOT NULL, - `description` text NOT NULL, - `meta_title` varchar(255) NOT NULL, - `meta_h1` varchar(255) NOT NULL, - `meta_description` varchar(255) NOT NULL, - `meta_keyword` varchar(255) NOT NULL - ) ENGINE=MyISAM DEFAULT CHARSET=utf8; - "); - $this->db->query(" - CREATE TABLE IF NOT EXISTS " . DB_PREFIX . "lightshop_blog_to_layout ( - `blog_id` int(11) NOT NULL, - `store_id` int(11) NOT NULL, - `layout_id` int(11) NOT NULL, - PRIMARY KEY (`blog_id`) - ) ENGINE=MyISAM DEFAULT CHARSET=utf8; - "); - $this->db->query(" - CREATE TABLE IF NOT EXISTS " . DB_PREFIX . "lightshop_blog_to_store ( - `blog_id` int(11) NOT NULL, - `store_id` int(11) NOT NULL, - PRIMARY KEY (`blog_id`) - ) ENGINE=MyISAM DEFAULT CHARSET=utf8; - "); - $this->db->query(" - CREATE TABLE IF NOT EXISTS " . DB_PREFIX . "lightshop_blog_related ( - `news_id` int(11) NOT NULL, - `related_id` int(11) NOT NULL - ) ENGINE=MyISAM DEFAULT CHARSET=utf8; - "); - } - -} diff --git a/public/admin/model/extension/theme/lightshopblogreview.php b/public/admin/model/extension/theme/lightshopblogreview.php deleted file mode 100644 index 803f65c..0000000 --- a/public/admin/model/extension/theme/lightshopblogreview.php +++ /dev/null @@ -1,131 +0,0 @@ -db->query("INSERT INTO " . DB_PREFIX . "lightshop_blog_comment SET author = '" . $this->db->escape($data['author']) . "', blog_id = '" . (int)$data['blog_id'] . "', text = '" . $this->db->escape(strip_tags($data['text'])) . "', status = '" . (int)$data['status'] . "', date_added = '" . $this->db->escape($data['date_added']) . "'"); - - $comment_id = $this->db->getLastId(); - - $this->cache->delete('blog'); - - return $comment_id; - } - - public function editReview($comment_id, $data) { - $this->db->query("UPDATE " . DB_PREFIX . "lightshop_blog_comment SET author = '" . $this->db->escape($data['author']) . "', blog_id = '" . (int)$data['blog_id'] . "', text = '" . $this->db->escape(strip_tags($data['text'])) . "', status = '" . (int)$data['status'] . "', date_added = '" . $this->db->escape($data['date_added']) . "', date_modified = NOW() WHERE comment_id = '" . (int)$comment_id . "'"); - - $this->cache->delete('blog'); - } - - public function deleteReview($comment_id) { - $this->db->query("DELETE FROM " . DB_PREFIX . "lightshop_blog_comment WHERE comment_id = '" . (int)$comment_id . "'"); - - $this->cache->delete('blog'); - } - - public function getReview($comment_id) { - $query = $this->db->query("SELECT DISTINCT *, (SELECT pd.title FROM " . DB_PREFIX . "lightshop_blog_description pd WHERE pd.blog_id = r.blog_id AND pd.language_id = '" . (int)$this->config->get('config_language_id') . "') AS blog FROM " . DB_PREFIX . "lightshop_blog_comment r WHERE r.comment_id = '" . (int)$comment_id . "'"); - - return $query->row; - } - - public function getReviews($data = array()) { - $sql = "SELECT r.comment_id, pd.title, r.author, r.status, r.date_added FROM " . DB_PREFIX . "lightshop_blog_comment r LEFT JOIN " . DB_PREFIX . "lightshop_blog_description pd ON (r.blog_id = pd.blog_id) WHERE pd.language_id = '" . (int)$this->config->get('config_language_id') . "'"; - - if (!empty($data['filter_blog'])) { - $sql .= " AND pd.title LIKE '" . $this->db->escape($data['filter_blog']) . "%'"; - } - - if (!empty($data['filter_author'])) { - $sql .= " AND r.author LIKE '" . $this->db->escape($data['filter_author']) . "%'"; - } - - if (isset($data['filter_status']) && !is_null($data['filter_status'])) { - $sql .= " AND r.status = '" . (int)$data['filter_status'] . "'"; - } - - if (!empty($data['filter_date_added'])) { - $sql .= " AND DATE(r.date_added) = DATE('" . $this->db->escape($data['filter_date_added']) . "')"; - } - - $sort_data = array( - 'pd.title', - 'r.author', - 'r.status', - 'r.date_added' - ); - - if (isset($data['sort']) && in_array($data['sort'], $sort_data)) { - $sql .= " ORDER BY " . $data['sort']; - } else { - $sql .= " ORDER BY r.date_added"; - } - - if (isset($data['order']) && ($data['order'] == 'DESC')) { - $sql .= " DESC"; - } else { - $sql .= " ASC"; - } - - if (isset($data['start']) || isset($data['limit'])) { - if ($data['start'] < 0) { - $data['start'] = 0; - } - - if ($data['limit'] < 1) { - $data['limit'] = 20; - } - - $sql .= " LIMIT " . (int)$data['start'] . "," . (int)$data['limit']; - } - - $query = $this->db->query($sql); - - return $query->rows; - } - - public function getTotalReviews($data = array()) { - - $this->db->query(" - CREATE TABLE IF NOT EXISTS " . DB_PREFIX . "lightshop_blog_comment ( - `comment_id` int(11) NOT NULL AUTO_INCREMENT, - `blog_id` int(11) NOT NULL, - `customer_id` int(11) NOT NULL, - `author` varchar(64) NOT NULL, - `text` text NOT NULL, - `rating` int(1) NOT NULL, - `status` tinyint(1) NOT NULL DEFAULT '0', - `date_added` datetime NOT NULL, - `date_modified` datetime NOT NULL, - PRIMARY KEY (`comment_id`) - ) ENGINE=MyISAM DEFAULT CHARSET=utf8; - "); - - $sql = "SELECT COUNT(*) AS total FROM " . DB_PREFIX . "lightshop_blog_comment r LEFT JOIN " . DB_PREFIX . "lightshop_blog_description pd ON (r.blog_id = pd.blog_id) WHERE pd.language_id = '" . (int)$this->config->get('config_language_id') . "'"; - - if (!empty($data['filter_blog'])) { - $sql .= " AND pd.title LIKE '" . $this->db->escape($data['filter_blog']) . "%'"; - } - - if (!empty($data['filter_author'])) { - $sql .= " AND r.author LIKE '" . $this->db->escape($data['filter_author']) . "%'"; - } - - if (isset($data['filter_status']) && !is_null($data['filter_status'])) { - $sql .= " AND r.status = '" . (int)$data['filter_status'] . "'"; - } - - if (!empty($data['filter_date_added'])) { - $sql .= " AND DATE(r.date_added) = DATE('" . $this->db->escape($data['filter_date_added']) . "')"; - } - - $query = $this->db->query($sql); - - return $query->row['total']; - } - - public function getTotalReviewsAwaitingApproval() { - $query = $this->db->query("SELECT COUNT(*) AS total FROM " . DB_PREFIX . "lightshop_blog_commentWHERE status = '0'"); - - return $query->row['total']; - } -} \ No newline at end of file diff --git a/public/admin/model/extension/theme/lightshopcatblog.php b/public/admin/model/extension/theme/lightshopcatblog.php deleted file mode 100644 index 46e6195..0000000 --- a/public/admin/model/extension/theme/lightshopcatblog.php +++ /dev/null @@ -1,365 +0,0 @@ -db->query("INSERT INTO " . DB_PREFIX . "lightshopcat_blog SET parent_id = '" . (int)$data['parent_id'] . "', `top` = '" . (isset($data['top']) ? (int)$data['top'] : 0) . "', `column` = '" . (int)$data['column'] . "', sort_order = '" . (int)$data['sort_order'] . "', status = '" . (int)$data['status'] . "', date_modified = NOW(), date_added = NOW()"); - - $category_id = $this->db->getLastId(); - - if (isset($data['image'])) { - $this->db->query("UPDATE " . DB_PREFIX . "lightshopcat_blog SET image = '" . $this->db->escape($data['image']) . "' WHERE category_id = '" . (int)$category_id . "'"); - } - - foreach ($data['lightshopcatblog_description'] as $language_id => $value) { - $this->db->query("INSERT INTO " . DB_PREFIX . "lightshopcat_blog_description SET category_id = '" . (int)$category_id . "', language_id = '" . (int)$language_id . "', name = '" . $this->db->escape($value['name']) . "', description = '" . $this->db->escape($value['description']) . "', meta_title = '" . $this->db->escape($value['meta_title']) . "', meta_h1 = '" . $this->db->escape($value['meta_h1']) . "', meta_description = '" . $this->db->escape($value['meta_description']) . "', meta_keyword = '" . $this->db->escape($value['meta_keyword']) . "'"); - } - - // MySQL Hierarchical Data Closure Table Pattern - $level = 0; - - $query = $this->db->query("SELECT * FROM `" . DB_PREFIX . "lightshopcat_blog_path` WHERE category_id = '" . (int)$data['parent_id'] . "' ORDER BY `level` ASC"); - - foreach ($query->rows as $result) { - $this->db->query("INSERT INTO `" . DB_PREFIX . "lightshopcat_blog_path` SET `category_id` = '" . (int)$category_id . "', `path_id` = '" . (int)$result['path_id'] . "', `level` = '" . (int)$level . "'"); - - $level++; - } - - $this->db->query("INSERT INTO `" . DB_PREFIX . "lightshopcat_blog_path` SET `category_id` = '" . (int)$category_id . "', `path_id` = '" . (int)$category_id . "', `level` = '" . (int)$level . "'"); - - if (isset($data['category_filter'])) { - foreach ($data['category_filter'] as $filter_id) { - $this->db->query("INSERT INTO " . DB_PREFIX . "lightshopcat_blog_filter SET category_id = '" . (int)$category_id . "', filter_id = '" . (int)$filter_id . "'"); - } - } - - if (isset($data['lightshopcatblog_store'])) { - foreach ($data['lightshopcatblog_store'] as $store_id) { - $this->db->query("INSERT INTO " . DB_PREFIX . "lightshopcat_blog_to_store SET category_id = '" . (int)$category_id . "', store_id = '" . (int)$store_id . "'"); - } - } - - // Set which layout to use with this category - if (isset($data['category_layout'])) { - foreach ($data['category_layout'] as $store_id => $layout_id) { - $this->db->query("INSERT INTO " . DB_PREFIX . "lightshopcat_blog_to_layout SET category_id = '" . (int)$category_id . "', store_id = '" . (int)$store_id . "', layout_id = '" . (int)$layout_id . "'"); - } - } - - $this->db->query("DELETE FROM " . DB_PREFIX . "seo_url WHERE query = 'lightshopcatblog_id=" . (int)$category_id . "'"); - - // SEO URL - if (isset($data['category_seo_url'])) { - foreach ($data['category_seo_url'] as $store_id => $language) { - foreach ($language as $language_id => $keyword) { - if (!empty($keyword)) { - $this->db->query("INSERT INTO " . DB_PREFIX . "seo_url SET store_id = '" . (int)$store_id . "', language_id = '" . (int)$language_id . "', query = 'lightshopcatblog_id=" . (int)$category_id . "', keyword = '" . $this->db->escape($keyword) . "'"); - } - } - } - } - - $this->cache->delete('category'); - - return $category_id; - } - - public function editCategoryBlog($category_id, $data) { - $this->db->query("UPDATE " . DB_PREFIX . "lightshopcat_blog SET parent_id = '" . (int)$data['parent_id'] . "', `top` = '" . (isset($data['top']) ? (int)$data['top'] : 0) . "', `column` = '" . (int)$data['column'] . "', sort_order = '" . (int)$data['sort_order'] . "', status = '" . (int)$data['status'] . "', date_modified = NOW() WHERE category_id = '" . (int)$category_id . "'"); - - if (isset($data['image'])) { - $this->db->query("UPDATE " . DB_PREFIX . "lightshopcat_blog SET image = '" . $this->db->escape($data['image']) . "' WHERE category_id = '" . (int)$category_id . "'"); - } - - $this->db->query("DELETE FROM " . DB_PREFIX . "lightshopcat_blog_description WHERE category_id = '" . (int)$category_id . "'"); - - foreach ($data['lightshopcatblog_description'] as $language_id => $value) { - $this->db->query("INSERT INTO " . DB_PREFIX . "lightshopcat_blog_description SET category_id = '" . (int)$category_id . "', language_id = '" . (int)$language_id . "', name = '" . $this->db->escape($value['name']) . "', description = '" . $this->db->escape($value['description']) . "', meta_title = '" . $this->db->escape($value['meta_title']) . "', meta_h1 = '" . $this->db->escape($value['meta_h1']) . "', meta_description = '" . $this->db->escape($value['meta_description']) . "', meta_keyword = '" . $this->db->escape($value['meta_keyword']) . "'"); - } - - // MySQL Hierarchical Data Closure Table Pattern - $query = $this->db->query("SELECT * FROM `" . DB_PREFIX . "lightshopcat_blog_path` WHERE path_id = '" . (int)$category_id . "' ORDER BY level ASC"); - - if ($query->rows) { - foreach ($query->rows as $category_path) { - // Delete the path below the current one - $this->db->query("DELETE FROM `" . DB_PREFIX . "lightshopcat_blog_path` WHERE category_id = '" . (int)$category_path['category_id'] . "' AND level < '" . (int)$category_path['level'] . "'"); - - $path = array(); - - // Get the nodes new parents - $query = $this->db->query("SELECT * FROM `" . DB_PREFIX . "lightshopcat_blog_path` WHERE category_id = '" . (int)$data['parent_id'] . "' ORDER BY level ASC"); - - foreach ($query->rows as $result) { - $path[] = $result['path_id']; - } - - // Get whats left of the nodes current path - $query = $this->db->query("SELECT * FROM `" . DB_PREFIX . "lightshopcat_blog_path` WHERE category_id = '" . (int)$category_path['category_id'] . "' ORDER BY level ASC"); - - foreach ($query->rows as $result) { - $path[] = $result['path_id']; - } - - // Combine the paths with a new level - $level = 0; - - foreach ($path as $path_id) { - $this->db->query("REPLACE INTO `" . DB_PREFIX . "lightshopcat_blog_path` SET category_id = '" . (int)$category_path['category_id'] . "', `path_id` = '" . (int)$path_id . "', level = '" . (int)$level . "'"); - - $level++; - } - } - } else { - // Delete the path below the current one - $this->db->query("DELETE FROM `" . DB_PREFIX . "lightshopcat_blog_path` WHERE category_id = '" . (int)$category_id . "'"); - - // Fix for records with no paths - $level = 0; - - $query = $this->db->query("SELECT * FROM `" . DB_PREFIX . "lightshopcat_blog_path` WHERE category_id = '" . (int)$data['parent_id'] . "' ORDER BY level ASC"); - - foreach ($query->rows as $result) { - $this->db->query("INSERT INTO `" . DB_PREFIX . "lightshopcat_blog_path` SET category_id = '" . (int)$category_id . "', `path_id` = '" . (int)$result['path_id'] . "', level = '" . (int)$level . "'"); - - $level++; - } - - $this->db->query("REPLACE INTO `" . DB_PREFIX . "lightshopcat_blog_path` SET category_id = '" . (int)$category_id . "', `path_id` = '" . (int)$category_id . "', level = '" . (int)$level . "'"); - } - - $this->db->query("DELETE FROM " . DB_PREFIX . "lightshopcat_blog_filter WHERE category_id = '" . (int)$category_id . "'"); - - if (isset($data['category_filter'])) { - foreach ($data['category_filter'] as $filter_id) { - $this->db->query("INSERT INTO " . DB_PREFIX . "lightshopcat_blog_filter SET category_id = '" . (int)$category_id . "', filter_id = '" . (int)$filter_id . "'"); - } - } - - $this->db->query("DELETE FROM " . DB_PREFIX . "lightshopcat_blog_to_store WHERE category_id = '" . (int)$category_id . "'"); - - if (isset($data['lightshopcatblog_store'])) { - foreach ($data['lightshopcatblog_store'] as $store_id) { - $this->db->query("INSERT INTO " . DB_PREFIX . "lightshopcat_blog_to_store SET category_id = '" . (int)$category_id . "', store_id = '" . (int)$store_id . "'"); - } - } - - $this->db->query("DELETE FROM " . DB_PREFIX . "lightshopcat_blog_to_layout WHERE category_id = '" . (int)$category_id . "'"); - - if (isset($data['category_layout'])) { - foreach ($data['category_layout'] as $store_id => $layout_id) { - $this->db->query("INSERT INTO " . DB_PREFIX . "lightshopcat_blog_to_layout SET category_id = '" . (int)$category_id . "', store_id = '" . (int)$store_id . "', layout_id = '" . (int)$layout_id . "'"); - } - } - - $this->db->query("DELETE FROM " . DB_PREFIX . "seo_url WHERE query = 'lightshopcatblog_id=" . (int)$category_id . "'"); - - // SEO URL - if (isset($data['category_seo_url'])) { - foreach ($data['category_seo_url'] as $store_id => $language) { - foreach ($language as $language_id => $keyword) { - if (!empty($keyword)) { - $this->db->query("INSERT INTO " . DB_PREFIX . "seo_url SET store_id = '" . (int)$store_id . "', language_id = '" . (int)$language_id . "', query = 'lightshopcatblog_id=" . (int)$category_id . "', keyword = '" . $this->db->escape($keyword) . "'"); - } - } - } - } - - $this->cache->delete('category'); - } - - public function deleteCategoryBlog($category_id) { - $this->db->query("DELETE FROM " . DB_PREFIX . "lightshopcat_blog_path WHERE category_id = '" . (int)$category_id . "'"); - - $query = $this->db->query("SELECT * FROM " . DB_PREFIX . "lightshopcat_blog_path WHERE path_id = '" . (int)$category_id . "'"); - - foreach ($query->rows as $result) { - $this->deleteCategory($result['category_id']); - } - - $this->db->query("DELETE FROM " . DB_PREFIX . "lightshopcat_blog WHERE category_id = '" . (int)$category_id . "'"); - $this->db->query("DELETE FROM " . DB_PREFIX . "lightshopcat_blog_description WHERE category_id = '" . (int)$category_id . "'"); - $this->db->query("DELETE FROM " . DB_PREFIX . "lightshopcat_blog_filter WHERE category_id = '" . (int)$category_id . "'"); - $this->db->query("DELETE FROM " . DB_PREFIX . "lightshopcat_blog_to_store WHERE category_id = '" . (int)$category_id . "'"); - $this->db->query("DELETE FROM " . DB_PREFIX . "lightshopcat_blog_to_layout WHERE category_id = '" . (int)$category_id . "'"); - $this->db->query("DELETE FROM " . DB_PREFIX . "lightshop_blog_to_category WHERE category_id = '" . (int)$category_id . "'"); - $this->db->query("DELETE FROM " . DB_PREFIX . "seo_url WHERE query = 'lightshopcatblog_id=" . (int)$category_id . "'"); - - $this->cache->delete('category'); - } - - public function repairCategoriesBlog($parent_id = 0) { - $query = $this->db->query("SELECT * FROM " . DB_PREFIX . "lightshopcat_blog WHERE parent_id = '" . (int)$parent_id . "'"); - - foreach ($query->rows as $category) { - // Delete the path below the current one - $this->db->query("DELETE FROM `" . DB_PREFIX . "lightshopcat_blog_path` WHERE category_id = '" . (int)$category['category_id'] . "'"); - - // Fix for records with no paths - $level = 0; - - $query = $this->db->query("SELECT * FROM `" . DB_PREFIX . "lightshopcat_blog_path` WHERE category_id = '" . (int)$parent_id . "' ORDER BY level ASC"); - - foreach ($query->rows as $result) { - $this->db->query("INSERT INTO `" . DB_PREFIX . "lightshopcat_blog_path` SET category_id = '" . (int)$category['category_id'] . "', `path_id` = '" . (int)$result['path_id'] . "', level = '" . (int)$level . "'"); - - $level++; - } - - $this->db->query("REPLACE INTO `" . DB_PREFIX . "lightshopcat_blog_path` SET category_id = '" . (int)$category['category_id'] . "', `path_id` = '" . (int)$category['category_id'] . "', level = '" . (int)$level . "'"); - - $this->repairCategories($category['category_id']); - } - } - - public function getCategorySeoUrls($category_id) { - $category_seo_url_data = array(); - - $query = $this->db->query("SELECT * FROM " . DB_PREFIX . "seo_url WHERE query = 'lightshopcatblog_id=" . (int)$category_id . "'"); - - foreach ($query->rows as $result) { - $category_seo_url_data[$result['store_id']][$result['language_id']] = $result['keyword']; - } - - return $category_seo_url_data; - } - - public function getCategoryBlog($category_id) { - $query = $this->db->query("SELECT DISTINCT *, (SELECT GROUP_CONCAT(cd1.name ORDER BY level SEPARATOR '  >  ') FROM " . DB_PREFIX . "lightshopcat_blog_path cp LEFT JOIN " . DB_PREFIX . "lightshopcat_blog_description cd1 ON (cp.path_id = cd1.category_id AND cp.category_id != cp.path_id) WHERE cp.category_id = c.category_id AND cd1.language_id = '" . (int)$this->config->get('config_language_id') . "' GROUP BY cp.category_id) AS path FROM " . DB_PREFIX . "lightshopcat_blog c LEFT JOIN " . DB_PREFIX . "lightshopcat_blog_description cd2 ON (c.category_id = cd2.category_id) WHERE c.category_id = '" . (int)$category_id . "' AND cd2.language_id = '" . (int)$this->config->get('config_language_id') . "'"); - - return $query->row; - } - - public function getCategoriesBlogByParentId($parent_id = 0) { - $query = $this->db->query("SELECT *, (SELECT COUNT(parent_id) FROM " . DB_PREFIX . "lightshopcat_blog WHERE parent_id = c.category_id) AS children FROM " . DB_PREFIX . "lightshopcat_blog c LEFT JOIN " . DB_PREFIX . "lightshopcat_blog_description cd ON (c.category_id = cd.category_id) WHERE c.parent_id = '" . (int)$parent_id . "' AND cd.language_id = '" . (int)$this->config->get('config_language_id') . "' ORDER BY c.sort_order, cd.name"); - - return $query->rows; - } - - public function getCategoriesBlog($data = array()) { - $sql = "SELECT cp.category_id AS category_id, GROUP_CONCAT(cd1.name ORDER BY cp.level SEPARATOR '  >  ') AS name, c1.parent_id, c1.sort_order, c1.status,(select count(product_id) as product_count from " . DB_PREFIX . "product_to_category pc where pc.category_id = c1.category_id) as product_count FROM " . DB_PREFIX . "lightshopcat_blog_path cp LEFT JOIN " . DB_PREFIX . "lightshopcat_blog c1 ON (cp.category_id = c1.category_id) LEFT JOIN " . DB_PREFIX . "lightshopcat_blog c2 ON (cp.path_id = c2.category_id) LEFT JOIN " . DB_PREFIX . "lightshopcat_blog_description cd1 ON (cp.path_id = cd1.category_id) LEFT JOIN " . DB_PREFIX . "lightshopcat_blog_description cd2 ON (cp.category_id = cd2.category_id) WHERE cd1.language_id = '" . (int)$this->config->get('config_language_id') . "' AND cd2.language_id = '" . (int)$this->config->get('config_language_id') . "'"; - - if (!empty($data['filter_name'])) { - $sql .= " AND cd2.name LIKE '%" . $this->db->escape($data['filter_name']) . "%'"; - } - - $sql .= " GROUP BY cp.category_id"; - - $sort_data = array( - 'product_count', - 'name', - 'sort_order' - ); - - if (isset($data['sort']) && in_array($data['sort'], $sort_data)) { - $sql .= " ORDER BY " . $data['sort']; - } else { - $sql .= " ORDER BY sort_order"; - } - - if (isset($data['order']) && ($data['order'] == 'DESC')) { - $sql .= " DESC"; - } else { - $sql .= " ASC"; - } - - if (isset($data['start']) || isset($data['limit'])) { - if ($data['start'] < 0) { - $data['start'] = 0; - } - - if ($data['limit'] < 1) { - $data['limit'] = 20; - } - - $sql .= " LIMIT " . (int)$data['start'] . "," . (int)$data['limit']; - } - - $query = $this->db->query($sql); - - return $query->rows; - } - - public function getCategoryBlogDescriptions($category_id) { - $category_description_data = array(); - - $query = $this->db->query("SELECT * FROM " . DB_PREFIX . "lightshopcat_blog_description WHERE category_id = '" . (int)$category_id . "'"); - - foreach ($query->rows as $result) { - $category_description_data[$result['language_id']] = array( - 'name' => $result['name'], - 'meta_title' => $result['meta_title'], - 'meta_h1' => $result['meta_h1'], - 'meta_description' => $result['meta_description'], - 'meta_keyword' => $result['meta_keyword'], - 'description' => $result['description'] - ); - } - - return $category_description_data; - } - - public function getCategoryBlogPath($category_id) { - $query = $this->db->query("SELECT category_id, path_id, level FROM " . DB_PREFIX . "lightshopcat_blog_path WHERE category_id = '" . (int)$category_id . "'"); - - return $query->rows; - } - - public function getCategoryBlogFilters($category_id) { - $category_filter_data = array(); - - $query = $this->db->query("SELECT * FROM " . DB_PREFIX . "lightshopcat_blog_filter WHERE category_id = '" . (int)$category_id . "'"); - - foreach ($query->rows as $result) { - $category_filter_data[] = $result['filter_id']; - } - - return $category_filter_data; - } - - public function getCategoryBlogStores($category_id) { - $category_store_data = array(); - - $query = $this->db->query("SELECT * FROM " . DB_PREFIX . "lightshopcat_blog_to_store WHERE category_id = '" . (int)$category_id . "'"); - - foreach ($query->rows as $result) { - $category_store_data[] = $result['store_id']; - } - - return $category_store_data; - } - - public function getCategoryBlogLayouts($category_id) { - $category_layout_data = array(); - - $query = $this->db->query("SELECT * FROM " . DB_PREFIX . "lightshopcat_blog_to_layout WHERE category_id = '" . (int)$category_id . "'"); - - foreach ($query->rows as $result) { - $category_layout_data[$result['store_id']] = $result['layout_id']; - } - - return $category_layout_data; - } - - public function getTotalCategoriesBlog() { - $query = $this->db->query("SELECT COUNT(*) AS total FROM " . DB_PREFIX . "lightshopcat_blog"); - - return $query->row['total']; - } - - public function getAllCategoriesBlog() { - $query = $this->db->query("SELECT * FROM " . DB_PREFIX . "lightshopcat_blog c LEFT JOIN " . DB_PREFIX . "lightshopcat_blog_description cd ON (c.category_id = cd.category_id) LEFT JOIN " . DB_PREFIX . "lightshopcat_blog_to_store c2s ON (c.category_id = c2s.category_id) WHERE cd.language_id = '" . (int)$this->config->get('config_language_id') . "' AND c2s.store_id = '" . (int)$this->config->get('config_store_id') . "' ORDER BY c.parent_id, c.sort_order, cd.name"); - - $category_data = array(); - foreach ($query->rows as $row) { - $category_data[$row['parent_id']][$row['category_id']] = $row; - } - - return $category_data; - } - - public function getTotalCategoriesBlogByLayoutId($layout_id) { - $query = $this->db->query("SELECT COUNT(*) AS total FROM " . DB_PREFIX . "lightshopcat_blog_to_layout WHERE layout_id = '" . (int)$layout_id . "'"); - - return $query->row['total']; - } -} diff --git a/public/admin/model/extension/theme/lightshopnews.php b/public/admin/model/extension/theme/lightshopnews.php deleted file mode 100644 index 193eed2..0000000 --- a/public/admin/model/extension/theme/lightshopnews.php +++ /dev/null @@ -1,298 +0,0 @@ -db->query("INSERT INTO " . DB_PREFIX . "lightshop_news SET sort_order = 0, bottom = '" . (isset($data['bottom']) ? (int)$data['bottom'] : 0) . "', status = '" . (int)$data['status'] . "', date_added = '" . $this->db->escape($data['date_added']) . "'"); - }else{ - $this->db->query("INSERT INTO " . DB_PREFIX . "lightshop_news SET sort_order = 0, bottom = '" . (isset($data['bottom']) ? (int)$data['bottom'] : 0) . "', status = '" . (int)$data['status'] . "', date_added = NOW()"); - } - $news_id = $this->db->getLastId(); - - foreach ($data['news_description'] as $language_id => $value) { - $this->db->query("INSERT INTO " . DB_PREFIX . "lightshop_news_description SET news_id = '" . (int)$news_id . "', language_id = '" . (int)$language_id . "', title = '" . $this->db->escape($value['title']) . "', description = '" . $this->db->escape($value['description']) . "', meta_title = '" . $this->db->escape($value['meta_title']) . "', meta_h1 = '" . $this->db->escape($value['meta_h1']) . "', meta_description = '" . $this->db->escape($value['meta_description']) . "', meta_keyword = '" . $this->db->escape($value['meta_keyword']) . "'"); - } - - if (isset($data['news_store'])) { - foreach ($data['news_store'] as $store_id) { - $this->db->query("INSERT INTO " . DB_PREFIX . "lightshop_news_to_store SET news_id = '" . (int)$news_id . "', store_id = '" . (int)$store_id . "'"); - } - } - - if (isset($data['product_related'])) { - foreach ($data['product_related'] as $related_id) { - $this->db->query("DELETE FROM " . DB_PREFIX . "lightshop_news_related WHERE news_id = '" . (int)$news_id . "' AND related_id = '" . (int)$related_id . "'"); - $this->db->query("INSERT INTO " . DB_PREFIX . "lightshop_news_related SET news_id = '" . (int)$news_id . "', related_id = '" . (int)$related_id . "'"); - } - } - - if (isset($data['news_layout'])) { - foreach ($data['news_layout'] as $store_id => $layout_id) { - $this->db->query("INSERT INTO " . DB_PREFIX . "lightshop_news_to_layout SET news_id = '" . (int)$news_id . "', store_id = '" . (int)$store_id . "', layout_id = '" . (int)$layout_id . "'"); - } - } - - // SEO URL - if (isset($data['news_seo_url'])) { - foreach ($data['news_seo_url'] as $store_id => $language) { - foreach ($language as $language_id => $keyword) { - if (!empty($keyword)) { - $this->db->query("INSERT INTO " . DB_PREFIX . "seo_url SET store_id = '" . (int)$store_id . "', language_id = '" . (int)$language_id . "', query = 'news_id=" . (int)$news_id . "', keyword = '" . $this->db->escape($keyword) . "'"); - } - } - } - } - - $this->cache->delete('news'); - - return $news_id; - } - - public function editNews($news_id, $data) { - $this->db->query("UPDATE " . DB_PREFIX . "lightshop_news SET sort_order = 0, bottom = '" . (isset($data['bottom']) ? (int)$data['bottom'] : 0) . "', status = '" . (int)$data['status'] . "', date_added = '" . $this->db->escape($data['date_added']) . "' WHERE news_id = '" . (int)$news_id . "'"); - - $this->db->query("DELETE FROM " . DB_PREFIX . "lightshop_news_description WHERE news_id = '" . (int)$news_id . "'"); - - foreach ($data['news_description'] as $language_id => $value) { - $this->db->query("INSERT INTO " . DB_PREFIX . "lightshop_news_description SET news_id = '" . (int)$news_id . "', language_id = '" . (int)$language_id . "', title = '" . $this->db->escape($value['title']) . "', description = '" . $this->db->escape($value['description']) . "', meta_title = '" . $this->db->escape($value['meta_title']) . "', meta_h1 = '" . $this->db->escape($value['meta_h1']) . "', meta_description = '" . $this->db->escape($value['meta_description']) . "', meta_keyword = '" . $this->db->escape($value['meta_keyword']) . "'"); - } - - $this->db->query("DELETE FROM " . DB_PREFIX . "lightshop_news_to_store WHERE news_id = '" . (int)$news_id . "'"); - - if (isset($data['news_store'])) { - foreach ($data['news_store'] as $store_id) { - $this->db->query("INSERT INTO " . DB_PREFIX . "lightshop_news_to_store SET news_id = '" . (int)$news_id . "', store_id = '" . (int)$store_id . "'"); - } - } - - $this->db->query("DELETE FROM " . DB_PREFIX . "lightshop_news_to_layout WHERE news_id = '" . (int)$news_id . "'"); - - if (isset($data['news_layout'])) { - foreach ($data['news_layout'] as $store_id => $layout_id) { - $this->db->query("INSERT INTO " . DB_PREFIX . "lightshop_news_to_layout SET news_id = '" . (int)$news_id . "', store_id = '" . (int)$store_id . "', layout_id = '" . (int)$layout_id . "'"); - } - } - - $this->db->query("DELETE FROM " . DB_PREFIX . "lightshop_news_related WHERE news_id = '" . (int)$news_id . "'"); - - - if (isset($data['product_related'])) { - foreach ($data['product_related'] as $related_id) { - $this->db->query("DELETE FROM " . DB_PREFIX . "lightshop_news_related WHERE news_id = '" . (int)$news_id . "' AND related_id = '" . (int)$related_id . "'"); - $this->db->query("INSERT INTO " . DB_PREFIX . "lightshop_news_related SET news_id = '" . (int)$news_id . "', related_id = '" . (int)$related_id . "'"); - } - } - - $this->db->query("DELETE FROM " . DB_PREFIX . "seo_url WHERE query = 'news_id=" . (int)$news_id . "'"); - - if (isset($data['news_seo_url'])) { - foreach ($data['news_seo_url'] as $store_id => $language) { - foreach ($language as $language_id => $keyword) { - if (trim($keyword)) { - $this->db->query("INSERT INTO `" . DB_PREFIX . "seo_url` SET store_id = '" . (int)$store_id . "', language_id = '" . (int)$language_id . "', query = 'news_id=" . (int)$news_id . "', keyword = '" . $this->db->escape($keyword) . "'"); - } - } - } - } - - $this->cache->delete('news'); - } - - public function deleteNews($news_id) { - $this->db->query("DELETE FROM " . DB_PREFIX . "lightshop_news WHERE news_id = '" . (int)$news_id . "'"); - $this->db->query("DELETE FROM " . DB_PREFIX . "lightshop_news_description WHERE news_id = '" . (int)$news_id . "'"); - $this->db->query("DELETE FROM " . DB_PREFIX . "lightshop_news_to_store WHERE news_id = '" . (int)$news_id . "'"); - $this->db->query("DELETE FROM " . DB_PREFIX . "lightshop_news_to_layout WHERE news_id = '" . (int)$news_id . "'"); - $this->db->query("DELETE FROM " . DB_PREFIX . "seo_url WHERE query = 'news_id=" . (int)$news_id . "'"); - $this->db->query("DELETE FROM " . DB_PREFIX . "lightshop_news_related WHERE news_id = '" . (int)$news_id . "'"); - $this->db->query("DELETE FROM " . DB_PREFIX . "lightshop_news_related WHERE related_id = '" . (int)$news_id . "'"); - - $this->cache->delete('news'); - } - - public function getNews($news_id) { - $query = $this->db->query("SELECT DISTINCT *, (SELECT keyword FROM " . DB_PREFIX . "seo_url WHERE query = 'news_id=" . (int)$news_id . "' LIMIT 1) AS keyword FROM " . DB_PREFIX . "lightshop_news WHERE news_id = '" . (int)$news_id . "'"); - - return $query->row; - } - - public function getNewsSeoUrls($news_id) { - $news_seo_url_data = array(); - - $query = $this->db->query("SELECT * FROM " . DB_PREFIX . "seo_url WHERE query = 'news_id=" . (int)$news_id . "'"); - - foreach ($query->rows as $result) { - $news_seo_url_data[$result['store_id']][$result['language_id']] = $result['keyword']; - } - - return $news_seo_url_data; - } - - public function getNewss($data = array()) { - - $this->createTable(); - - if ($data) { - $sql = "SELECT * FROM " . DB_PREFIX . "lightshop_news i LEFT JOIN " . DB_PREFIX . "lightshop_news_description id ON (i.news_id = id.news_id) WHERE id.language_id = '" . (int)$this->config->get('config_language_id') . "'"; - - $sort_data = array( - 'id.title', - 'i.sort_order', - 'i.date_added' - ); - - if (isset($data['sort']) && in_array($data['sort'], $sort_data)) { - $sql .= " ORDER BY " . $data['sort']; - } else { - $sql .= " ORDER BY i.date_added"; - } - - if (isset($data['order']) && ($data['order'] == 'DESC')) { - $sql .= " DESC"; - } else { - $sql .= " ASC"; - } - - if (isset($data['start']) || isset($data['limit'])) { - if ($data['start'] < 0) { - $data['start'] = 0; - } - - if ($data['limit'] < 1) { - $data['limit'] = 20; - } - - $sql .= " LIMIT " . (int)$data['start'] . "," . (int)$data['limit']; - } - - $query = $this->db->query($sql); - - return $query->rows; - } else { - $news_data = $this->cache->get('news.' . (int)$this->config->get('config_language_id')); - - if (!$news_data) { - $query = $this->db->query("SELECT * FROM " . DB_PREFIX . "lightshop_news i LEFT JOIN " . DB_PREFIX . "lightshop_news_description id ON (i.news_id = id.news_id) WHERE id.language_id = '" . (int)$this->config->get('config_language_id') . "' ORDER BY id.title"); - - $news_data = $query->rows; - - $this->cache->set('news.' . (int)$this->config->get('config_language_id'), $news_data); - } - - return $news_data; - } - } - - public function getNewsDescriptions($news_id) { - $news_description_data = array(); - - $query = $this->db->query("SELECT * FROM " . DB_PREFIX . "lightshop_news_description WHERE news_id = '" . (int)$news_id . "'"); - - foreach ($query->rows as $result) { - $news_description_data[$result['language_id']] = array( - 'title' => $result['title'], - 'description' => $result['description'], - 'meta_title' => $result['meta_title'], - 'meta_h1' => $result['meta_h1'], - 'meta_description' => $result['meta_description'], - 'meta_keyword' => $result['meta_keyword'] - ); - } - - return $news_description_data; - } - - public function getNewsStores($news_id) { - $news_store_data = array(); - - $query = $this->db->query("SELECT * FROM " . DB_PREFIX . "lightshop_news_to_store WHERE news_id = '" . (int)$news_id . "'"); - - foreach ($query->rows as $result) { - $news_store_data[] = $result['store_id']; - } - - return $news_store_data; - } - - public function getNewsLayouts($news_id) { - $news_layout_data = array(); - - $query = $this->db->query("SELECT * FROM " . DB_PREFIX . "lightshop_news_to_layout WHERE news_id = '" . (int)$news_id . "'"); - - foreach ($query->rows as $result) { - $news_layout_data[$result['store_id']] = $result['layout_id']; - } - - return $news_layout_data; - } - - public function getTotalNewss() { - $query = $this->db->query("SELECT COUNT(*) AS total FROM " . DB_PREFIX . "lightshop_news"); - - return $query->row['total']; - } - - public function getTotalNewssByLayoutId($layout_id) { - $query = $this->db->query("SELECT COUNT(*) AS total FROM " . DB_PREFIX . "lightshop_news_to_layout WHERE layout_id = '" . (int)$layout_id . "'"); - - return $query->row['total']; - } - - public function getProductRelated($news_id) { - $product_related_data = array(); - - $query = $this->db->query("SELECT * FROM " . DB_PREFIX . "lightshop_news_related WHERE news_id = '" . (int)$news_id . "'"); - - foreach ($query->rows as $result) { - $product_related_data[] = $result['related_id']; - } - - return $product_related_data; - } - - public function createTable() { - $this->db->query(" - CREATE TABLE IF NOT EXISTS " . DB_PREFIX . "lightshop_news ( - `news_id` int(11) NOT NULL AUTO_INCREMENT, - `bottom` int(1) NOT NULL DEFAULT '0', - `sort_order` int(3) NOT NULL DEFAULT '0', - `status` tinyint(1) NOT NULL DEFAULT '1', - `date_added` date NOT NULL, - PRIMARY KEY (`news_id`) - ) ENGINE=MyISAM DEFAULT CHARSET=utf8; - "); - $this->db->query(" - CREATE TABLE IF NOT EXISTS " . DB_PREFIX . "lightshop_news_description ( - `news_id` int(11) NOT NULL, - `language_id` int(11) NOT NULL, - `title` varchar(200) NOT NULL, - `description` text NOT NULL, - `meta_title` varchar(255) NOT NULL, - `meta_h1` varchar(255) NOT NULL, - `meta_description` varchar(255) NOT NULL, - `meta_keyword` varchar(255) NOT NULL - ) ENGINE=MyISAM DEFAULT CHARSET=utf8; - "); - $this->db->query(" - CREATE TABLE IF NOT EXISTS " . DB_PREFIX . "lightshop_news_to_layout ( - `news_id` int(11) NOT NULL, - `store_id` int(11) NOT NULL, - `layout_id` int(11) NOT NULL, - PRIMARY KEY (`news_id`) - ) ENGINE=MyISAM DEFAULT CHARSET=utf8; - "); - $this->db->query(" - CREATE TABLE IF NOT EXISTS " . DB_PREFIX . "lightshop_news_to_store ( - `news_id` int(11) NOT NULL, - `store_id` int(11) NOT NULL, - PRIMARY KEY (`news_id`) - ) ENGINE=MyISAM DEFAULT CHARSET=utf8; - "); - $this->db->query(" - CREATE TABLE IF NOT EXISTS " . DB_PREFIX . "lightshop_news_related ( - `news_id` int(11) NOT NULL, - `related_id` int(11) NOT NULL - ) ENGINE=MyISAM DEFAULT CHARSET=utf8; - "); - } - -} diff --git a/public/admin/model/extension/theme/lightshopsets.php b/public/admin/model/extension/theme/lightshopsets.php deleted file mode 100644 index da502d5..0000000 --- a/public/admin/model/extension/theme/lightshopsets.php +++ /dev/null @@ -1,277 +0,0 @@ -db->query("INSERT INTO " . DB_PREFIX . "lightshop_set SET sort_order = 0, mode = '" . (isset($data['mode']) ? (int)$data['mode'] : 0) . "', discount = '" . (isset($data['discount']) ? (int)$data['discount'] : 0) . "', status = '" . (int)$data['status'] . "', date_added = NOW()"); - - $set_id = $this->db->getLastId(); - - foreach ($data['set_description'] as $language_id => $value) { - $this->db->query("INSERT INTO " . DB_PREFIX . "lightshop_set_description SET set_id = '" . (int)$set_id . "', language_id = '" . (int)$language_id . "', title = '" . $this->db->escape($value['title']) . "'"); - } - - if (isset($data['set_store'])) { - foreach ($data['set_store'] as $store_id) { - $this->db->query("INSERT INTO " . DB_PREFIX . "lightshop_set_to_store SET set_id = '" . (int)$set_id . "', store_id = '" . (int)$store_id . "'"); - } - } - - if (isset($data['product'])) { - foreach ($data['product'] as $key => $rowProducts) { - if(!isset($rowProducts['items'])){ continue; } - foreach ($rowProducts['items'] as $product) { - - $this->db->query("INSERT INTO " . DB_PREFIX . "lightshop_product_to_set SET set_id = '" . (int)$set_id . "', row_id = '" . (int)$key . "', product_id = '" . (int)$product['id'] . "', quantity = '" . (int)$rowProducts['qty'] . "', sort_order = " . (int)$rowProducts['sort_order'] . ""); - } - } - - } - - - $this->cache->delete('set'); - - return $set_id; - } - - public function editSet($set_id, $data) { - $this->db->query("UPDATE " . DB_PREFIX . "lightshop_set SET mode = '" . (isset($data['mode']) ? (int)$data['mode'] : 0) . "', discount = '" . (isset($data['discount']) ? (int)$data['discount'] : 0) . "', status = '" . (int)$data['status'] . "' WHERE set_id = '" . (int)$set_id . "'"); - - $this->db->query("DELETE FROM " . DB_PREFIX . "lightshop_set_description WHERE set_id = '" . (int)$set_id . "'"); - - foreach ($data['set_description'] as $language_id => $value) { - $this->db->query("INSERT INTO " . DB_PREFIX . "lightshop_set_description SET set_id = '" . (int)$set_id . "', language_id = '" . (int)$language_id . "', title = '" . $this->db->escape($value['title']) . "'"); - } - - $this->db->query("DELETE FROM " . DB_PREFIX . "lightshop_set_to_store WHERE set_id = '" . (int)$set_id . "'"); - - if (isset($data['set_store'])) { - foreach ($data['set_store'] as $store_id) { - $this->db->query("INSERT INTO " . DB_PREFIX . "lightshop_set_to_store SET set_id = '" . (int)$set_id . "', store_id = '" . (int)$store_id . "'"); - } - } - - - $this->db->query("DELETE FROM " . DB_PREFIX . "lightshop_product_to_set WHERE set_id = '" . (int)$set_id . "'"); - - - if (isset($data['product'])) { - foreach ($data['product'] as $key => $rowProducts) { - if(!isset($rowProducts['items'])){ continue; } - foreach ($rowProducts['items'] as $product) { - - $this->db->query("INSERT INTO " . DB_PREFIX . "lightshop_product_to_set SET set_id = '" . (int)$set_id . "', row_id = '" . (int)$key . "', product_id = '" . (int)$product['id'] . "', quantity = '" . (int)$rowProducts['qty'] . "', sort_order = " . (int)$rowProducts['sort_order'] . ""); - } - } - - } - - $this->db->query("DELETE FROM " . DB_PREFIX . "seo_url WHERE query = 'set_id=" . (int)$set_id . "'"); - - - $this->cache->delete('set'); - } - - public function deleteSet($set_id) { - $this->db->query("DELETE FROM " . DB_PREFIX . "lightshop_set WHERE set_id = '" . (int)$set_id . "'"); - $this->db->query("DELETE FROM " . DB_PREFIX . "lightshop_set_description WHERE set_id = '" . (int)$set_id . "'"); - $this->db->query("DELETE FROM " . DB_PREFIX . "lightshop_set_to_store WHERE set_id = '" . (int)$set_id . "'"); - $this->db->query("DELETE FROM " . DB_PREFIX . "lightshop_set_to_layout WHERE set_id = '" . (int)$set_id . "'"); - $this->db->query("DELETE FROM " . DB_PREFIX . "lightshop_product_to_set WHERE set_id = '" . (int)$set_id . "'"); - - $this->cache->delete('set'); - } - - public function getSet($set_id) { - - $sql = "SELECT * FROM " . DB_PREFIX . "lightshop_set i LEFT JOIN " . DB_PREFIX . "lightshop_set_description id ON (i.set_id = id.set_id) WHERE id.language_id = '" . (int)$this->config->get('config_language_id') . "' AND i.set_id = '" . (int)$set_id . "'"; - - $query = $this->db->query($sql); - - return $query->row; - - } - - public function getSetProduct($set_id) { - $products = array(); - - $sql = "SELECT * FROM " . DB_PREFIX . "lightshop_product_to_set WHERE set_id = '" . (int)$set_id . "' ORDER BY row_id,set_product_id ASC"; - - $query = $this->db->query($sql); - - foreach ($query->rows as $key => $product) { - $products[$product['row_id']][] = array( - 'id' => $product['product_id'], - 'qty' => $product['quantity'], - 'sort_order' => $product['sort_order'] - ); - } - - return $products; - - } - - public function getSets($data = array()) { - - $this->createTable(); - - if ($data) { - $sql = "SELECT * FROM " . DB_PREFIX . "lightshop_set i LEFT JOIN " . DB_PREFIX . "lightshop_set_description id ON (i.set_id = id.set_id) WHERE id.language_id = '" . (int)$this->config->get('config_language_id') . "'"; - - $sort_data = array( - 'id.title', - 'i.sort_order', - 'i.date_added' - ); - - if (isset($data['sort']) && in_array($data['sort'], $sort_data)) { - $sql .= " ORDER BY " . $data['sort']; - } else { - $sql .= " ORDER BY i.date_added"; - } - - if (isset($data['order']) && ($data['order'] == 'DESC')) { - $sql .= " DESC"; - } else { - $sql .= " ASC"; - } - - if (isset($data['start']) || isset($data['limit'])) { - if ($data['start'] < 0) { - $data['start'] = 0; - } - - if ($data['limit'] < 1) { - $data['limit'] = 20; - } - - $sql .= " LIMIT " . (int)$data['start'] . "," . (int)$data['limit']; - } - - $query = $this->db->query($sql); - - return $query->rows; - } else { - $set_data = $this->cache->get('lightshopset.' . (int)$this->config->get('config_language_id')); - - if (!$set_data) { - $query = $this->db->query("SELECT * FROM " . DB_PREFIX . "lightshop_set i LEFT JOIN " . DB_PREFIX . "lightshop_set_description id ON (i.set_id = id.set_id) WHERE id.language_id = '" . (int)$this->config->get('config_language_id') . "' ORDER BY id.title"); - - $set_data = $query->rows; - - $this->cache->set('lightshopset.' . (int)$this->config->get('config_language_id'), $set_data); - } - - return $set_data; - } - } - - public function getSetDescriptions($set_id) { - $set_description_data = array(); - - $query = $this->db->query("SELECT * FROM " . DB_PREFIX . "lightshop_set_description WHERE set_id = '" . (int)$set_id . "'"); - - foreach ($query->rows as $result) { - $set_description_data[$result['language_id']] = array( - 'title' => $result['title'], - ); - } - - return $set_description_data; - } - - public function getSetStores($set_id) { - $set_store_data = array(); - - $query = $this->db->query("SELECT * FROM " . DB_PREFIX . "lightshop_set_to_store WHERE set_id = '" . (int)$set_id . "'"); - - foreach ($query->rows as $result) { - $set_store_data[] = $result['store_id']; - } - - return $set_store_data; - } - - - public function getTotalSets() { - $query = $this->db->query("SELECT COUNT(*) AS total FROM " . DB_PREFIX . "lightshop_set"); - - return $query->row['total']; - } - - public function getTotalNewssByLayoutId($layout_id) { - $query = $this->db->query("SELECT COUNT(*) AS total FROM " . DB_PREFIX . "lightshop_news_to_layout WHERE layout_id = '" . (int)$layout_id . "'"); - - return $query->row['total']; - } - - public function getProductRelated($news_id) { - $product_related_data = array(); - - $query = $this->db->query("SELECT * FROM " . DB_PREFIX . "lightshop_news_related WHERE news_id = '" . (int)$news_id . "'"); - - foreach ($query->rows as $result) { - $product_related_data[] = $result['related_id']; - } - - return $product_related_data; - } - - public function createTable() { - $this->db->query(" - CREATE TABLE IF NOT EXISTS " . DB_PREFIX . "lightshop_set ( - `set_id` int(11) NOT NULL AUTO_INCREMENT, - `mode` int(1) NOT NULL DEFAULT '0', - `discount` int(11) NOT NULL DEFAULT '0', - `sort_order` int(3) NOT NULL DEFAULT '0', - `status` tinyint(1) NOT NULL DEFAULT '1', - `date_added` date NOT NULL, - PRIMARY KEY (`set_id`) - ) ENGINE=MyISAM DEFAULT CHARSET=utf8; - "); - $this->db->query(" - CREATE TABLE IF NOT EXISTS " . DB_PREFIX . "lightshop_set_description ( - `set_id` int(11) NOT NULL, - `language_id` int(11) NOT NULL, - `title` varchar(200) NOT NULL, - `description` text NOT NULL, - `meta_title` varchar(255) NOT NULL, - `meta_h1` varchar(255) NOT NULL, - `meta_description` varchar(255) NOT NULL, - `meta_keyword` varchar(255) NOT NULL - ) ENGINE=MyISAM DEFAULT CHARSET=utf8; - "); - $this->db->query(" - CREATE TABLE IF NOT EXISTS " . DB_PREFIX . "lightshop_product_to_set ( - `set_product_id` int(11) NOT NULL AUTO_INCREMENT, - `set_id` int(11) NOT NULL, - `row_id` int(11) NOT NULL, - `product_id` int(11) NOT NULL, - `quantity` int(11) NOT NULL DEFAULT '0', - `sort_order` int(3) NOT NULL DEFAULT '0', - PRIMARY KEY (`set_product_id`) - ) ENGINE=MyISAM DEFAULT CHARSET=utf8; - "); - $this->db->query(" - CREATE TABLE IF NOT EXISTS " . DB_PREFIX . "lightshop_set_to_layout ( - `set_id` int(11) NOT NULL, - `store_id` int(11) NOT NULL, - `layout_id` int(11) NOT NULL, - PRIMARY KEY (`set_id`,`store_id`) - ) ENGINE=MyISAM DEFAULT CHARSET=utf8; - "); - $this->db->query(" - CREATE TABLE IF NOT EXISTS " . DB_PREFIX . "lightshop_set_to_store ( - `set_id` int(11) NOT NULL, - `store_id` int(11) NOT NULL, - PRIMARY KEY (`set_id`,`store_id`) - ) ENGINE=MyISAM DEFAULT CHARSET=utf8; - "); - $this->db->query(" - CREATE TABLE IF NOT EXISTS " . DB_PREFIX . "lightshop_news_related ( - `news_id` int(11) NOT NULL, - `related_id` int(11) NOT NULL - ) ENGINE=MyISAM DEFAULT CHARSET=utf8; - "); - } - -} diff --git a/public/admin/view/image/lightshop/catalog-type1.png b/public/admin/view/image/lightshop/catalog-type1.png deleted file mode 100644 index 7fa2cd36e0eb515f959d9be860e5aed7974f8980..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9882 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 E0H{OxqyPW_ diff --git a/public/admin/view/image/lightshop/catalog-type2.png b/public/admin/view/image/lightshop/catalog-type2.png deleted file mode 100644 index b11a0264aabc22e1710c4cead97d1414248d4b7e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12398 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 diff --git a/public/admin/view/image/lightshop/footer-type-1.png b/public/admin/view/image/lightshop/footer-type-1.png deleted file mode 100644 index 472c5d2693dba94b813400c7199112af41ad5b11..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6463 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 diff --git a/public/admin/view/image/lightshop/footer-type-2.png b/public/admin/view/image/lightshop/footer-type-2.png deleted file mode 100644 index 5526b7e3ab53bb3344f9a41426004667968e0f37..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17266 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 LtO-SU&vX9+1V^?q diff --git a/public/admin/view/image/lightshop/header-type-2.png b/public/admin/view/image/lightshop/header-type-2.png deleted file mode 100644 index cfe2aedfdb3e97e45360de51fe4e7bce216b5029..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7356 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�F9E!e%Xmg?=F0*si_%% zrKjw=i~!IT;BNJEB1+bezoyLHHij(g>_@X@-SF`711^6}1E4>Aw$bbQ>aykH;BJ-G zCr$ih0iDNR>x5&J(S0dZ&1a9>f(eC%g>&S+lza|W0W6o;;`{5d&;7>3_X*P{z4G@m zh}Ol$#B{6%KjRAa8pcQ}Dq1cq`~RG($j)Z>LI3oB`0<#g!E>7xTXz3VxQbk=*WIzg zj|!q9B0qm`&+hE(9ONo*Mjw`1pB)ZXE=wNZNw9>uj;-T#yK~p~N3*Z-#~v7)tmq^a zPzz^p7=#cV9KgRaOW#o{@%jq(T+vA#YmyL0s^xvOd9XSnH6;*s*Od#Cm>P%R|8V2} zT1D;wtG2EoflKs9zHx6^8(F47{xdii48@a_oGiP$xv6#AUTE!e7&+5O#9QM0hJz@Bj)SOfyn(L+rq`eR<*N)j_5d8YvA!A_5s^Bo^lUPd<@!`s z@lqpteQ+oD2}W=mfVN?Vz2scB5{d~sp9{uwbb@qK7x$0z`qfpkl% zyUA-;$!(ot_5ACTs!s=fB4BS6swh5wc&zyDzU>e_J~5fB!R+ zgzW&coV!o~)lE6Xo$o;2>g)^>l%1)z?f`DdfRm+&^z?K9o1dMZci?5O-b(yEi)nE! zJal^xEIj|+G)c_D#kihwY+Rhxdq?n?Xa7%XvU9SsGdwLQLI$)4nGIfH8ss0=dcoxn01{2=VGE1X8}@wo1z;C=~kr zCvb1m($bPNKD(6j+McbCC!n~WXe7J)cO;7$KTj04DgVK(vJ^I&&fAT zoSef&BbKr;fr2B#XA*BmgouKqX`7y1`j+7ybyl&$9D78;1Vp;xFa3X;zA>%<5|Uu~ z$*PAhgK^U4-r5Zp-+cjQFw)SewjE@Rn|<$Ot`rbB{wD_3i-CY?xxSJ=qscHi0J6~} zqtOgq*FZollHMdY6aT!QEY(1h3?-_3c|`v<+_yB8T_g0Z0rgE;Y-nVwZ(n*m?NF{_ zR=W4rBr~UkHujrE+nd2~7?mq72Rj6HxG9Tpjd_chFh{ zOOa@nwoOkn(FIBQ9`9T(`0did69lAaxg~*wX@8|#O|ed}hnSj!osMp-)SwU-pNQs1 zCv`^bNq*JH$Ou`61c6oaQx>AcZ7yMt%ZrO1i2H5-L0k{XEuzV!gviHJJawTo8-rQ( z9zUnB?qso4Y_M`5TQ0zvAR6yg{u0s7EZ#ZznCMMAE8xUr=_;d|uFs#fmSQSQE?ar; zUGkYZ^7|Q65Xe$+OG%}M8Qi3Ns_{I0cS#HGWi;R6RkBMBZlF}XZuKE1BQRzg^QUDB5nzy9lq{^G+zS52WW1*+cug1^es zf8{yWvSqPV)2-rBAEe%5rtW&h&Gg-GARW>*h5NELFTAltCrcxhKu15OW1RpN`^{(L zW-XqRCS7QK&npXl{vKAATHXYulf@7+7DBQ@zAc>o)`x~V$IPPeEk;dti;OEvN zR6^T>sh)4_Ep@DYPcch1pg*Nsjk(uDlGRF8+ax$Fs0-8->oE^0;2`U5P8yn4en+86 z5M8x7aP&h+9_F+09c_Ivg6W+dZFay3WMhIMNyf$Uk>R+tuwZ8t6P_{Jq7EUm2A(76 zHkf|WVVH3*U#u$_}$+#S4D-#0!5`9hrLPAK3_dAIuji@`gszGW)SG#jJ z`)C&N#(J{^dG7nUC{>D*gO=05Bd z(`Qr5OXB~Tf_(6TQ4T@j|42@TNtOn5bJVgUoD!&}X{Ir!#o!4aGEM~wEJnY1P?bc{ zKpq_Ul-s{F!p~Jo$$-r^F@iXILt`Q&leT?=%YuWgL9W#YF`5(vAOSdsGcQ3w3Q7&O z<~h`J==Mci;7z_VnaaDFw(%gWow2b)g77VfXD!JA3)B~znpp5WhKVYSg@sBxO4y_m z%#$Xr&F&WZo;evA9!R*yZZ?+3ev4mFaGchxcR_Ki$Y?4$C@AOzr!rEwba^!B4tqcz zFBuhccGMM++-j4pB>5RMN8y)7PzqD+xn(j&{C?R&tFHj!s)aevVYknI?NyJ27Cz_Z z&c9qfn=_vq*-GwxSzKI_Id}s^XTRHWyqlNTdhV!OB5wLY0ahZN{n2*t!`0==kBQfo zy{mCqhI3182!VT=Tk5xOOWaC-fsJ8R0D-7{IWuEY5SNUgO3`r~N$&~b zEmdrc{u)t6zijf!SBe(Ste?@<-A#WNC@LoSlC_7O{jyGh=a(Y%Q+H=uTKrH&pRv+R zZI#5-H+6NJ;gEYMkurnvS8lK3j%RaTJf!R6!MQ4;a>3qzg|RUNP@f=;+3#EbMzTPO y{SUfb{R2?R_`Uug{Qe8*{+Hnksf(95_&5gKQSa_<66*f>KT%6v7f}g+6#Ref6ID$B diff --git a/public/admin/view/image/lightshop/header-type-3.png b/public/admin/view/image/lightshop/header-type-3.png deleted file mode 100644 index fcbd1a9f49e1e5fddf03d82127632d71d5b9f729..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8000 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 diff --git a/public/admin/view/javascript/lightshop/codemirror/lib/codemirror.js b/public/admin/view/javascript/lightshop/codemirror/lib/codemirror.js deleted file mode 100644 index 83c3acf..0000000 --- a/public/admin/view/javascript/lightshop/codemirror/lib/codemirror.js +++ /dev/null @@ -1,9690 +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.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 = !edge && /AppleWebKit/.test(userAgent) && /Mobile\/\w+/.test(userAgent) -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}; -Delayed.prototype.set = function (ms, f) { - clearTimeout(this.id) - this.id = setTimeout(f, ms) -}; - -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 = 30 - -// 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}; -var sel_mouse = {origin: "*mouse"}; -var 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 } - } -} - -// 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) { - 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") - - // 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 - - input.init(d) -} - -// 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 -} - -// Optimize some code when these features are not used. -var sawReadOnlySpans = false; -var 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) { - line.markedSpans = line.markedSpans ? line.markedSpans.concat([span]) : [span] - 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 - } - }) -} - -// 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 - 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)) } - 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)) - 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 -} - -var modes = {}; -var 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 this$1 = this; - - var start = this.pos - while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) { ++this$1.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) -}; - -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) { - var this$1 = this; - - if (!this.baseTokens) { return null } - while (this.baseTokens[this.baseTokenPos] <= n) - { this$1.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) -} - -// 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 = {}; -var 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: (ie || webkit) && 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, title, css) { - 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) { - var fullStyle = style || "" - if (startStyle) { fullStyle += startStyle } - if (endStyle) { fullStyle += endStyle } - var token = elt("span", [content], fullStyle, css) - if (title) { token.title = title } - return builder.content.appendChild(token) - } - builder.content.appendChild(content) -} - -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, title, css) { - 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, title, css) } - inner(builder, text.slice(0, part.to - start), style, startStyle, null, title, css) - 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, title, collapsed - for (;;) { - if (nextChange == pos) { // Update current marker set - spanStyle = spanEndStyle = spanStartStyle = title = css = "" - 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) } - if (m.title && !title) { title = m.title } - 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 : "", title, css) - } - 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")) - 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.options.gutters.length; ++k) { - var id = cm.options.gutters[k], 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 } - for (var node = lineView.node.firstChild, next = (void 0); node; node = next) { - next = node.nextSibling - if (node.className == "CodeMirror-linewidget") - { 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") - 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")) - 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} } - 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 height = 0 - if (lineObj.widgets) { for (var i = 0; i < lineObj.widgets.length; ++i) { if (lineObj.widgets[i].above) - { height += widgetHeight(lineObj.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 = true } - 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, true, -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, true, 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 ? 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 || y >= coords.bottom - } - - 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") - // 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]) - 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) { - left[cm.options.gutters[i]] = n.offsetLeft + n.clientLeft + gutterLeft - width[cm.options.gutters[i]] = 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) { return null } - var coords = coordsChar(cm, x, y), line - if (forRect && coords.xRel == 1 && (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 } - } -} - -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() - - 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 (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 (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 () { return 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.state.focused) { cm.display.input.focus(); onFocus(cm) } -} - -function delayBlurEvent(cm) { - cm.state.delayingBlurEvent = true - setTimeout(function () { if (cm.state.delayingBlurEvent) { - cm.state.delayingBlurEvent = false - onBlur(cm) - } }, 100) -} - -function onFocus(cm, e) { - if (cm.state.delayingBlurEvent) { 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 - for (var i = 0; i < display.view.length; i++) { - var cur = display.view[i], height = (void 0) - if (cur.hidden) { continue } - 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 - } - var diff = cur.line.height - height - if (height < 2) { height = textHeight(display) } - if (diff > .005 || diff < -.005) { - updateLineHeight(cur.line, height) - updateWidgetHeight(cur.line) - if (cur.rest) { for (var j = 0; j < cur.rest.length; j++) - { updateWidgetHeight(cur.rest[j]) } } - } - } -} - -// 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)} -} - -// 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) - return true - } - return false -} - -// 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 - pos = pos.ch ? Pos(pos.line, pos.sticky == "before" ? pos.ch - 1 : pos.ch, "after") : pos - end = pos.sticky == "before" ? Pos(pos.line, pos.ch + 1, "before") : 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 screenleft = cm.curOp && cm.curOp.scrollLeft != null ? cm.curOp.scrollLeft : display.scroller.scrollLeft - var screenw = displayWidth(cm) - (cm.options.fixedGutter ? display.gutters.offsetWidth : 0) - 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 - (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.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.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.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: null, // 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 - } - pushOperation(cm.curOp) -} - -// Finish an operation, updating the display and signalling delayed events -function endOperation(cm) { - var op = cm.curOp - 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) } - } -} - -// 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 -} - -// 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 () { - var this$1 = this; - - for (var i = 0; i < this.events.length; i++) - { signal.apply(null, this$1.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 (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 } - } - 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(cm) { - var width = cm.display.gutters.offsetWidth - cm.display.sizer.style.marginLeft = width + "px" -} - -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" -} - -// Rebuild the gutter elements, ensure the margin to the left of the -// code matches their width. -function updateGutters(cm) { - var gutters = cm.display.gutters, specs = cm.options.gutters - removeChildren(gutters) - var i = 0 - for (; i < specs.length; ++i) { - var gutterClass = specs[i] - var gElt = gutters.appendChild(elt("div", null, "CodeMirror-gutter " + gutterClass)) - if (gutterClass == "CodeMirror-linenumbers") { - cm.display.lineGutter = gElt - gElt.style.width = (cm.display.lineNumWidth || 1) + "px" - } - } - gutters.style.display = i ? "" : "none" - updateGutterSpace(cm) -} - -// Make sure the gutters options contains the element -// "CodeMirror-linenumbers" when the lineNumbers option is true. -function setGuttersForLineNumbers(options) { - var found = indexOf(options.gutters, "CodeMirror-linenumbers") - if (found == -1 && options.lineNumbers) { - options.gutters = options.gutters.concat(["CodeMirror-linenumbers"]) - } else if (found > -1 && !options.lineNumbers) { - options.gutters = options.gutters.slice(0) - options.gutters.splice(found, 1) - } -} - -var wheelSamples = 0; -var 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 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 && wheelPixelsPerUnit != null) { - if (dy && canScrollY) - { updateScrollTop(cm, Math.max(0, scroll.scrollTop + dy * wheelPixelsPerUnit)) } - setScrollLeft(cm, Math.max(0, scroll.scrollLeft + dx * wheelPixelsPerUnit)) - // 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 && wheelPixelsPerUnit != null) { - var pixels = dy * wheelPixelsPerUnit - 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) { - 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) { - var this$1 = this; - - 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$1.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 this$1 = this; - - var out = [] - for (var i = 0; i < this.ranges.length; i++) - { out[i] = new Range(copyPos(this$1.ranges[i].anchor), copyPos(this$1.ranges[i].head)) } - return new Selection(out, this.primIndex) -}; - -Selection.prototype.somethingSelected = function () { - var this$1 = this; - - for (var i = 0; i < this.ranges.length; i++) - { if (!this$1.ranges[i].empty()) { return true } } - return false -}; - -Selection.prototype.contains = function (pos, end) { - var this$1 = this; - - if (!end) { end = pos } - for (var i = 0; i < this.ranges.length; i++) { - var range = this$1.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(ranges, primIndex) { - 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] - if (cmp(prev.to(), cur.from()) >= 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(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) - 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(startGen) { - // 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 = 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 = startGen || 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(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(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) { - var this$1 = this; - - this.ranges = [] - for (var i = 0; i < ranges.length; i++) - { this$1.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(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) - { ensureCursorVisible(doc.cm) } -} - -function setSelectionInner(doc, sel) { - if (sel.equals(doc.sel)) { return } - - doc.sel = sel - - if (doc.cm) { - doc.cm.curOp.updateInput = 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(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 - if ((sp.from == null || (m.inclusiveLeft ? sp.from <= pos.ch : sp.from < pos.ch)) && - (sp.to == null || (m.inclusiveRight ? 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 ? m.inclusiveRight : m.inclusiveLeft) - { 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 ? m.inclusiveLeft : m.inclusiveRight) - { 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) { 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) -} - -// 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) { - if (!to) { to = from } - if (cmp(to, from) < 0) { var assign; - (assign = [to, from], from = assign[0], to = assign[1], assign) } - 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) { - var this$1 = this; - - this.lines = lines - this.parent = null - var height = 0 - for (var i = 0; i < lines.length; ++i) { - lines[i].parent = this$1 - height += lines[i].height - } - this.height = height -} - -LeafChunk.prototype = { - chunkSize: function chunkSize() { return this.lines.length }, - - // Remove the n lines at offset 'at'. - removeInner: function removeInner(at, n) { - var this$1 = this; - - for (var i = at, e = at + n; i < e; ++i) { - var line = this$1.lines[i] - this$1.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 collapse(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 insertInner(at, lines, height) { - var this$1 = this; - - 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$1 } - }, - - // Used to iterate over a part of the tree. - iterN: function iterN(at, n, op) { - var this$1 = this; - - for (var e = at + n; at < e; ++at) - { if (op(this$1.lines[at])) { return true } } - } -} - -function BranchChunk(children) { - var this$1 = this; - - 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$1 - } - this.size = size - this.height = height - this.parent = null -} - -BranchChunk.prototype = { - chunkSize: function chunkSize() { return this.size }, - - removeInner: function removeInner(at, n) { - var this$1 = this; - - this.size -= n - for (var i = 0; i < this.children.length; ++i) { - var child = this$1.children[i], sz = child.chunkSize() - if (at < sz) { - var rm = Math.min(n, sz - at), oldHeight = child.height - child.removeInner(at, rm) - this$1.height -= oldHeight - child.height - if (sz == rm) { this$1.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 collapse(lines) { - var this$1 = this; - - for (var i = 0; i < this.children.length; ++i) { this$1.children[i].collapse(lines) } - }, - - insertInner: function insertInner(at, lines, height) { - var this$1 = this; - - this.size += lines.length - this.height += height - for (var i = 0; i < this.children.length; ++i) { - var child = this$1.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$1.children.splice(++i, 0, leaf) - leaf.parent = this$1 - } - child.lines = child.lines.slice(0, remaining) - this$1.maybeSpill() - } - break - } - at -= sz - } - }, - - // When a node has grown, check whether it should be split. - maybeSpill: function maybeSpill() { - 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 iterN(at, n, op) { - var this$1 = this; - - for (var i = 0; i < this.children.length; ++i) { - var child = this$1.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) { - var this$1 = this; - - if (options) { for (var opt in options) { if (options.hasOwnProperty(opt)) - { this$1[opt] = options[opt] } } } - this.doc = doc - this.node = node -}; - -LineWidget.prototype.clear = function () { - var this$1 = this; - - 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$1) { 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 - 1, 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 () { - var this$1 = this; - - 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$1.lines[i] - var span = getMarkedSpanFor(line.markedSpans, this$1) - if (cm && !this$1.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$1.collapsed && !lineIsHidden(this$1.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$1.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) { - var this$1 = this; - - if (side == null && this.type == "bookmark") { side = 1 } - var from, to - for (var i = 0; i < this.lines.length; ++i) { - var line = this$1.lines[i] - var span = getMarkedSpanFor(line.markedSpans, this$1) - 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)) - ++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.title || marker.startStyle || marker.endStyle || marker.css) - { 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) { - var this$1 = this; - - this.markers = markers - this.primary = primary - for (var i = 0; i < markers.length; ++i) - { markers[i].parent = this$1 } -}; - -SharedTextMarker.prototype.clear = function () { - var this$1 = this; - - if (this.explicitlyCleared) { return } - this.explicitlyCleared = true - for (var i = 0; i < this.markers.length; ++i) - { this$1.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 } - 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) { - var this$1 = this; - - if (!ranges.length) { return } - var out = [] - for (var i = 0; i < ranges.length; i++) - { out[i] = new Range(clipPos(this$1, ranges[i].anchor), - clipPos(this$1, ranges[i].head)) } - if (primary == null) { primary = Math.min(ranges.length - 1, this.sel.primIndex) } - setSelection(this, normalizeSelection(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(ranges, ranges.length - 1), options) - }), - - getSelection: function(lineSep) { - var this$1 = this; - - var ranges = this.sel.ranges, lines - for (var i = 0; i < ranges.length; i++) { - var sel = getBetween(this$1, 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 this$1 = this; - - var parts = [], ranges = this.sel.ranges - for (var i = 0; i < ranges.length; i++) { - var sel = getBetween(this$1, ranges[i].from(), ranges[i].to()) - if (lineSep !== false) { sel = sel.join(lineSep || this$1.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 this$1 = this; - - 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$1.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$1, 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() {this.history = new History(this.history.maxGeneration)}, - - 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.maxGeneration) - 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) { - var this$1 = this; - - if (other instanceof CodeMirror) { other = other.doc } - if (this.linked) { for (var i = 0; i < this.linked.length; ++i) { - var link = this$1.linked[i] - if (link.doc != other) { continue } - this$1.linked.splice(i, 1) - other.unlinkDoc(this$1) - detachSharedMarkers(findSharedMarkers(this$1)) - 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 loadFile = function (file, i) { - if (cm.options.allowDropFileTypes && - indexOf(cm.options.allowDropFileTypes, file.type) == -1) - { return } - - var reader = new FileReader - reader.onload = operation(cm, function () { - var content = reader.result - if (/[\x00-\x08\x0e-\x1f]{2}/.test(content)) { content = "" } - text[i] = content - if (++read == n) { - pos = clipPos(cm.doc, pos) - var change = {from: pos, to: pos, - text: cm.doc.splitLines(text.join(cm.doc.lineSeparator())), - origin: "paste"} - makeChange(cm.doc, change) - setSelectionReplaceHistory(cm.doc, simpleSelection(pos, changeEnd(change))) - } - }) - reader.readAsText(file) - } - for (var i = 0; i < n; ++i) { loadFile(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){} - } -} - -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") - for (var i = 0; i < byClass.length; i++) { - var cm = byClass[i].CodeMirror - if (cm) { f(cm) } - } -} - -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: "/", 127: "Delete", 145: "ScrollLock", - 173: "-", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\", - 221: "]", 222: "'", 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", - "Alt-F": "goWordRight", "Alt-B": "goWordLeft", "Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd", - "Ctrl-V": "goPageDown", "Shift-Ctrl-V": "goPageUp", "Ctrl-D": "delCharAfter", "Ctrl-H": "delCharBefore", - "Alt-D": "delWordAfter", "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 != "Cmd") { 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) { - 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, "char"); }, - 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(0, 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 - 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") } - } - - // 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 (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; -var 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) { onContextMenu(cm, 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 - 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 || ie && ie_version == 9) - { setTimeout(function () {display.wrapper.ownerDocument.body.focus(); 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 - // IE's approach to draggable - if (display.scroller.dragDrop) { display.scroller.dragDrop() } - on(display.wrapper.ownerDocument, "mouseup", dragEnd) - on(display.wrapper.ownerDocument, "mousemove", mouseMove) - on(display.scroller, "dragstart", dragStart) - on(display.scroller, "drop", dragEnd) - - delayBlurEvent(cm) - setTimeout(function () { return display.input.focus(); }, 20) -} - -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) { - 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(ranges.concat([ourRange]), ourIndex), - {scroll: false, origin: "*mouse"}) - } else if (ranges.length > 1 && ranges[ourIndex].empty() && behavior.unit == "char" && !behavior.extend) { - setSelection(doc, normalizeSelection(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(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(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 - 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) { 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.options.gutters.length; ++i) { - var g = display.gutters.childNodes[i] - if (g && g.getBoundingClientRect().right >= mX) { - var line = lineAtHeight(cm.doc, mY) - var gutter = cm.options.gutters[i] - signal(cm, type, cm, line, gutter, 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 } - 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-\u200f\u2028\u2029\ufeff]/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("rtlMoveVisually", !windows) - option("wholeLineUpdateBefore", true) - - option("theme", "default", function (cm) { - themeChanged(cm) - guttersChanged(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) { - setGuttersForLineNumbers(cm.options) - guttersChanged(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) { - setGuttersForLineNumbers(cm.options) - guttersChanged(cm) - }, true) - option("firstLineNumber", 1, guttersChanged, true) - option("lineNumberFormatter", function (integer) { return integer; }, guttersChanged, true) - option("showCursorWhenSelecting", false, updateSelection, true) - - option("resetSelectionOnContextMenu", true) - option("lineWiseCopyCut", true) - option("pasteLinesPerSelection", true) - - option("readOnly", false, function (cm, val) { - if (val == "nocursor") { - onBlur(cm) - cm.display.input.blur() - } - cm.display.input.readOnlyChanged(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 guttersChanged(cm) { - updateGutters(cm) - regChange(cm) - alignHorizontally(cm) -} - -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) - setGuttersForLineNumbers(options) - - 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) - display.wrapper.CodeMirror = this - updateGutters(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: false, cutIncoming: false, // 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(bind(onFocus, this), 20) } - else - { onBlur(this) } - - for (var opt in optionHandlers) { if (optionHandlers.hasOwnProperty(opt)) - { optionHandlers[opt](this$1, options[opt], Init) } } - maybeUpdateLineNumberWidth(this) - if (options.finishInit) { options.finishInit(this) } - for (var i = 0; i < initHooks.length; ++i) { initHooks[i](this$1) } - 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. - if (!captureRightClick) { on(d.scroller, "contextmenu", function (e) { return 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 paste = cm.state.pasteIncoming || origin == "paste" - 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 - // 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 (lastCopied && lastCopied.lineWise && lastCopied.text.join("\n") == inserted) - { from = to = Pos(from.line, 0) } - } - updateInput = cm.curOp.updateInput - var changeEvent = {from: from, to: to, text: multiPaste ? multiPaste[i$1 % multiPaste.length] : textLines, - origin: origin || (paste ? "paste" : cm.state.cutIncoming ? "cut" : "+input")} - makeChange(cm.doc, changeEvent) - signalLater(cm, "inputRead", cm, changeEvent) - } - if (inserted && !paste) - { triggerElectric(cm, inserted) } - - ensureCursorVisible(cm) - cm.curOp.updateInput = updateInput - cm.curOp.typing = true - cm.state.pasteIncoming = cm.state.cutIncoming = false -} - -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) { - field.setAttribute("autocorrect", "off") - field.setAttribute("autocapitalize", "off") - field.setAttribute("spellcheck", !!spellcheck) -} - -function hiddenTextarea() { - var te = elt("textarea", null, null, "position: absolute; bottom: -1em; padding: 0; width: 1px; 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 this$1 = this; - - 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$1.state.modeGen++ - regChange(this$1) - 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 this$1 = this; - - 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$1.lastLine(), to.line - (to.ch ? 0 : 1)) + 1 - for (var j = start; j < end; ++j) - { indentLine(this$1, j, how) } - var newRanges = this$1.doc.sel.ranges - if (from.ch == 0 && ranges.length == newRanges.length && newRanges[i].from().ch > 0) - { replaceOneSelection(this$1.doc, i, new Range(from, newRanges[i].to()), sel_dontScroll) } - } else if (range.head.line > end) { - indentLine(this$1, range.head.line, how, true) - end = range.head.line - if (i == this$1.doc.sel.primIndex) { ensureCursorVisible(this$1) } - } - } - }), - - // 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 this$1 = this; - - 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$1) && 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 this$1 = this; - - 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$1.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 this$1 = this; - - 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$1, cur, "div") - if (x == null) { x = coords.left } - else { coords.left = x } - cur = findPosV(this$1, 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) - if (oldHeight == null || Math.abs(oldHeight - textHeight(this.display)) > .5) - { estimateLineHeights(this) } - signal(this, "refresh", this) - }), - - swapDoc: methodOp(function(doc) { - var old = this.doc - old.cm = null - 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 "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) - function findNextLine() { - var l = pos.line + dir - 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 (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, dir) } - else - { return false } - } else { - pos = next - } - return true - } - - if (unit == "char") { - 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 - disableBrowserMagic(div, cm.options.spellcheck) - - on(div, "paste", function (e) { - if (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 (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 = document.activeElement - 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.prepareSelection = function () { - var result = prepareSelection(this.cm, false) - result.focus = this.cm.state.focused - 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()) - { 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 input = this - if (this.selectionInEditor()) - { this.pollSelection() } - 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.options.gutters.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 = true - 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 = true } - } - on(te, "cut", prepareCopyCut) - on(te, "copy", prepareCopyCut) - - on(display.scroller, "paste", function (e) { - if (eventInWidget(display, e) || signalDOMEvent(cm, e)) { return } - cm.state.pasteIncoming = true - input.focus() - }) - - // 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.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 - 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 - input.wrapper.style.cssText = "position: absolute" - var wrapperBox = input.wrapper.getBoundingClientRect() - 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 = true - 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() { - 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" -}; - -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 (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) - -// INPUT HANDLING - -CodeMirror.inputStyles = {"textarea": TextareaInput, "contenteditable": ContentEditableInput} - -// MODE DEFINITION AND QUERYING - -// 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.40.0" - -return CodeMirror; - -}))); \ No newline at end of file diff --git a/public/admin/view/javascript/lightshop/codemirror/mode/css/css.js b/public/admin/view/javascript/lightshop/codemirror/mode/css/css.js deleted file mode 100644 index 4c1319b..0000000 --- a/public/admin/view/javascript/lightshop/codemirror/mode/css/css.js +++ /dev/null @@ -1,832 +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; - - 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 (((ch == "u" || ch == "U") && stream.match(/rl(-prefix)?\(/i)) || - ((ch == "d" || ch == "D") && stream.match("omain(", true, true)) || - ((ch == "r" || ch == "R") && stream.match("egexp(", true, true))) { - stream.backUp(1); - state.tokenize = tokenParenthesized; - return ret("property", "word"); - } 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 = "string-2"; - 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 = "string-2"; - 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" - ], mediaFeatures = keySet(mediaFeatures_); - - var mediaValueKeywords_ = [ - "landscape", "portrait", "none", "coarse", "fine", "on-demand", "hover", - "interlace", "progressive" - ], mediaValueKeywords = keySet(mediaValueKeywords_); - - var propertyKeywords_ = [ - "align-content", "align-items", "align-self", "alignment-adjust", - "alignment-baseline", "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", "backface-visibility", - "background", "background-attachment", "background-blend-mode", "background-clip", - "background-color", "background-image", "background-origin", "background-position", - "background-repeat", "background-size", "baseline-shift", "binding", - "bleed", "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", "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-position", "flex", "flex-basis", - "flex-direction", "flex-flow", "flex-grow", "flex-shrink", "flex-wrap", - "float", "float-offset", "flow-from", "flow-into", "font", "font-feature-settings", - "font-family", "font-kerning", "font-language-override", "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-weight", "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", "justify-content", "justify-items", "justify-self", "left", "letter-spacing", - "line-break", "line-height", "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", "max-height", - "max-width", "min-height", "min-width", "move-to", "nav-down", "nav-index", - "nav-left", "nav-right", "nav-up", "object-fit", "object-position", - "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", "rotation", "rotation-point", "ruby-align", "ruby-overhang", - "ruby-position", "ruby-span", "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-decoration", - "text-decoration-color", "text-decoration-line", "text-decoration-skip", - "text-decoration-style", "text-emphasis", "text-emphasis-color", - "text-emphasis-position", "text-emphasis-style", "text-height", - "text-indent", "text-justify", "text-outline", "text-overflow", "text-shadow", - "text-size-adjust", "text-space-collapse", "text-transform", "text-underline-position", - "text-wrap", "top", "transform", "transform-origin", "transform-style", - "transition", "transition-delay", "transition-duration", - "transition-property", "transition-timing-function", "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", "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", "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_ = [ - "scrollbar-arrow-color", "scrollbar-base-color", "scrollbar-dark-shadow-color", - "scrollbar-face-color", "scrollbar-highlight-color", "scrollbar-shadow-color", - "scrollbar-3d-light-color", "scrollbar-track-color", "shape-inside", - "searchfield-cancel-button", "searchfield-decoration", "searchfield-results-button", - "searchfield-results-decoration", "zoom" - ], nonStandardPropertyKeywords = keySet(nonStandardPropertyKeywords_); - - var fontProperties_ = [ - "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", "darkkhaki", "darkmagenta", "darkolivegreen", - "darkorange", "darkorchid", "darkred", "darksalmon", "darkseagreen", - "darkslateblue", "darkslategray", "darkturquoise", "darkviolet", - "deeppink", "deepskyblue", "dimgray", "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", "lightpink", - "lightsalmon", "lightseagreen", "lightskyblue", "lightslategray", - "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", "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", "background", "backwards", "baseline", "below", "bidi-override", "binary", - "bengali", "blink", "block", "block-axis", "bold", "bolder", "border", "border-box", - "both", "bottom", "break", "break-all", "break-word", "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", "contain", "content", "contents", - "content-box", "context-menu", "continuous", "copy", "counter", "counters", "cover", "crop", - "cross", "crosshair", "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", "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", "fixed", "flat", "flex", "flex-end", "flex-start", "footnotes", - "forwards", "from", "geometricPrecision", "georgian", "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", "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", "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", "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", "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", "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", "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", "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", "sub", - "subpixel-antialiased", "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", "unset", "up", - "upper-alpha", "upper-armenian", "upper-greek", "upper-hexadecimal", - "upper-latin", "upper-norwegian", "upper-roman", "uppercase", "urdu", "url", - "var", "vertical", "vertical-text", "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/public/admin/view/javascript/lightshop/codemirror/mode/css/gss.html b/public/admin/view/javascript/lightshop/codemirror/mode/css/gss.html deleted file mode 100644 index 33bc548..0000000 --- a/public/admin/view/javascript/lightshop/codemirror/mode/css/gss.html +++ /dev/null @@ -1,103 +0,0 @@ - - -CodeMirror: Closure Stylesheets (GSS) mode - - - - - - - - - - -

- -
-

Closure Stylesheets (GSS) mode

-
- - -

A mode for Closure Stylesheets (GSS).

-

MIME type defined: text/x-gss.

- -

Parsing/Highlighting Tests: normal, verbose.

- -
diff --git a/public/admin/view/javascript/lightshop/codemirror/mode/css/gss_test.js b/public/admin/view/javascript/lightshop/codemirror/mode/css/gss_test.js deleted file mode 100644 index 3f8689a..0000000 --- a/public/admin/view/javascript/lightshop/codemirror/mode/css/gss_test.js +++ /dev/null @@ -1,17 +0,0 @@ -// CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE - -(function() { - "use strict"; - - var mode = CodeMirror.getMode({indentUnit: 2}, "text/x-gss"); - function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1), "gss"); } - - MT("atComponent", - "[def @component] {", - "[tag foo] {", - " [property color]: [keyword black];", - "}", - "}"); - -})(); diff --git a/public/admin/view/javascript/lightshop/codemirror/mode/css/index.html b/public/admin/view/javascript/lightshop/codemirror/mode/css/index.html deleted file mode 100644 index a1ecf67..0000000 --- a/public/admin/view/javascript/lightshop/codemirror/mode/css/index.html +++ /dev/null @@ -1,75 +0,0 @@ - - -CodeMirror: CSS mode - - - - - - - - - - - - -
-

CSS mode

-
- - -

MIME types defined: text/css, text/x-scss (demo), text/x-less (demo).

- -

Parsing/Highlighting Tests: normal, verbose.

- -
diff --git a/public/admin/view/javascript/lightshop/codemirror/mode/css/less.html b/public/admin/view/javascript/lightshop/codemirror/mode/css/less.html deleted file mode 100644 index 17b6de4..0000000 --- a/public/admin/view/javascript/lightshop/codemirror/mode/css/less.html +++ /dev/null @@ -1,152 +0,0 @@ - - -CodeMirror: LESS mode - - - - - - - - - - -
-

LESS mode

-
- - -

The LESS mode is a sub-mode of the CSS mode (defined in css.js).

- -

Parsing/Highlighting Tests: normal, verbose.

-
diff --git a/public/admin/view/javascript/lightshop/codemirror/mode/css/less_test.js b/public/admin/view/javascript/lightshop/codemirror/mode/css/less_test.js deleted file mode 100644 index 444b0e7..0000000 --- a/public/admin/view/javascript/lightshop/codemirror/mode/css/less_test.js +++ /dev/null @@ -1,54 +0,0 @@ -// CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE - -(function() { - "use strict"; - - var mode = CodeMirror.getMode({indentUnit: 2}, "text/x-less"); - function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1), "less"); } - - MT("variable", - "[variable-2 @base]: [atom #f04615];", - "[qualifier .class] {", - " [property width]: [variable percentage]([number 0.5]); [comment // returns `50%`]", - " [property color]: [variable saturate]([variable-2 @base], [number 5%]);", - "}"); - - MT("amp", - "[qualifier .child], [qualifier .sibling] {", - " [qualifier .parent] [atom &] {", - " [property color]: [keyword black];", - " }", - " [atom &] + [atom &] {", - " [property color]: [keyword red];", - " }", - "}"); - - MT("mixin", - "[qualifier .mixin] ([variable dark]; [variable-2 @color]) {", - " [property color]: [atom darken]([variable-2 @color], [number 10%]);", - "}", - "[qualifier .mixin] ([variable light]; [variable-2 @color]) {", - " [property color]: [atom lighten]([variable-2 @color], [number 10%]);", - "}", - "[qualifier .mixin] ([variable-2 @_]; [variable-2 @color]) {", - " [property display]: [atom block];", - "}", - "[variable-2 @switch]: [variable light];", - "[qualifier .class] {", - " [qualifier .mixin]([variable-2 @switch]; [atom #888]);", - "}"); - - MT("nest", - "[qualifier .one] {", - " [def @media] ([property width]: [number 400px]) {", - " [property font-size]: [number 1.2em];", - " [def @media] [attribute print] [keyword and] [property color] {", - " [property color]: [keyword blue];", - " }", - " }", - "}"); - - - MT("interpolation", ".@{[variable foo]} { [property font-weight]: [atom bold]; }"); -})(); diff --git a/public/admin/view/javascript/lightshop/codemirror/mode/css/scss.html b/public/admin/view/javascript/lightshop/codemirror/mode/css/scss.html deleted file mode 100644 index d4767ea..0000000 --- a/public/admin/view/javascript/lightshop/codemirror/mode/css/scss.html +++ /dev/null @@ -1,157 +0,0 @@ - - -CodeMirror: SCSS mode - - - - - - - - - -
-

SCSS mode

-
- - -

The SCSS mode is a sub-mode of the CSS mode (defined in css.js).

- -

Parsing/Highlighting Tests: normal, verbose.

- -
diff --git a/public/admin/view/javascript/lightshop/codemirror/mode/css/scss_test.js b/public/admin/view/javascript/lightshop/codemirror/mode/css/scss_test.js deleted file mode 100644 index 3d22403..0000000 --- a/public/admin/view/javascript/lightshop/codemirror/mode/css/scss_test.js +++ /dev/null @@ -1,110 +0,0 @@ -// CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE - -(function() { - var mode = CodeMirror.getMode({indentUnit: 2}, "text/x-scss"); - function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1), "scss"); } - - MT('url_with_quotation', - "[tag foo] { [property background]:[atom url]([string test.jpg]) }"); - - MT('url_with_double_quotes', - "[tag foo] { [property background]:[atom url]([string \"test.jpg\"]) }"); - - MT('url_with_single_quotes', - "[tag foo] { [property background]:[atom url]([string \'test.jpg\']) }"); - - MT('string', - "[def @import] [string \"compass/css3\"]"); - - MT('important_keyword', - "[tag foo] { [property background]:[atom url]([string \'test.jpg\']) [keyword !important] }"); - - MT('variable', - "[variable-2 $blue]:[atom #333]"); - - MT('variable_as_attribute', - "[tag foo] { [property color]:[variable-2 $blue] }"); - - MT('numbers', - "[tag foo] { [property padding]:[number 10px] [number 10] [number 10em] [number 8in] }"); - - MT('number_percentage', - "[tag foo] { [property width]:[number 80%] }"); - - MT('selector', - "[builtin #hello][qualifier .world]{}"); - - MT('singleline_comment', - "[comment // this is a comment]"); - - MT('multiline_comment', - "[comment /*foobar*/]"); - - MT('attribute_with_hyphen', - "[tag foo] { [property font-size]:[number 10px] }"); - - MT('string_after_attribute', - "[tag foo] { [property content]:[string \"::\"] }"); - - MT('directives', - "[def @include] [qualifier .mixin]"); - - MT('basic_structure', - "[tag p] { [property background]:[keyword red]; }"); - - MT('nested_structure', - "[tag p] { [tag a] { [property color]:[keyword red]; } }"); - - MT('mixin', - "[def @mixin] [tag table-base] {}"); - - MT('number_without_semicolon', - "[tag p] {[property width]:[number 12]}", - "[tag a] {[property color]:[keyword red];}"); - - MT('atom_in_nested_block', - "[tag p] { [tag a] { [property color]:[atom #000]; } }"); - - MT('interpolation_in_property', - "[tag foo] { #{[variable-2 $hello]}:[number 2]; }"); - - MT('interpolation_in_selector', - "[tag foo]#{[variable-2 $hello]} { [property color]:[atom #000]; }"); - - MT('interpolation_error', - "[tag foo]#{[variable foo]} { [property color]:[atom #000]; }"); - - MT("divide_operator", - "[tag foo] { [property width]:[number 4] [operator /] [number 2] }"); - - MT('nested_structure_with_id_selector', - "[tag p] { [builtin #hello] { [property color]:[keyword red]; } }"); - - MT('indent_mixin', - "[def @mixin] [tag container] (", - " [variable-2 $a]: [number 10],", - " [variable-2 $b]: [number 10])", - "{}"); - - MT('indent_nested', - "[tag foo] {", - " [tag bar] {", - " }", - "}"); - - MT('indent_parentheses', - "[tag foo] {", - " [property color]: [atom darken]([variable-2 $blue],", - " [number 9%]);", - "}"); - - MT('indent_vardef', - "[variable-2 $name]:", - " [string 'val'];", - "[tag tag] {", - " [tag inner] {", - " [property margin]: [number 3px];", - " }", - "}"); -})(); diff --git a/public/admin/view/javascript/lightshop/codemirror/mode/css/test.js b/public/admin/view/javascript/lightshop/codemirror/mode/css/test.js deleted file mode 100644 index 446588d..0000000 --- a/public/admin/view/javascript/lightshop/codemirror/mode/css/test.js +++ /dev/null @@ -1,209 +0,0 @@ -// CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE - -(function() { - var mode = CodeMirror.getMode({indentUnit: 2}, "css"); - function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); } - - // Error, because "foobarhello" is neither a known type or property, but - // property was expected (after "and"), and it should be in parentheses. - MT("atMediaUnknownType", - "[def @media] [attribute screen] [keyword and] [error foobarhello] { }"); - - // Soft error, because "foobarhello" is not a known property or type. - MT("atMediaUnknownProperty", - "[def @media] [attribute screen] [keyword and] ([error foobarhello]) { }"); - - // Make sure nesting works with media queries - MT("atMediaMaxWidthNested", - "[def @media] [attribute screen] [keyword and] ([property max-width]: [number 25px]) { [tag foo] { } }"); - - MT("atMediaFeatureValueKeyword", - "[def @media] ([property orientation]: [keyword landscape]) { }"); - - MT("atMediaUnknownFeatureValueKeyword", - "[def @media] ([property orientation]: [error upsidedown]) { }"); - - MT("atMediaUppercase", - "[def @MEDIA] ([property orienTAtion]: [keyword landScape]) { }"); - - MT("tagSelector", - "[tag foo] { }"); - - MT("classSelector", - "[qualifier .foo-bar_hello] { }"); - - MT("idSelector", - "[builtin #foo] { [error #foo] }"); - - MT("tagSelectorUnclosed", - "[tag foo] { [property margin]: [number 0] } [tag bar] { }"); - - MT("tagStringNoQuotes", - "[tag foo] { [property font-family]: [variable hello] [variable world]; }"); - - MT("tagStringDouble", - "[tag foo] { [property font-family]: [string \"hello world\"]; }"); - - MT("tagStringSingle", - "[tag foo] { [property font-family]: [string 'hello world']; }"); - - MT("tagColorKeyword", - "[tag foo] {", - " [property color]: [keyword black];", - " [property color]: [keyword navy];", - " [property color]: [keyword yellow];", - "}"); - - MT("tagColorHex3", - "[tag foo] { [property background]: [atom #fff]; }"); - - MT("tagColorHex4", - "[tag foo] { [property background]: [atom #ffff]; }"); - - MT("tagColorHex6", - "[tag foo] { [property background]: [atom #ffffff]; }"); - - MT("tagColorHex8", - "[tag foo] { [property background]: [atom #ffffffff]; }"); - - MT("tagColorHex5Invalid", - "[tag foo] { [property background]: [atom&error #fffff]; }"); - - MT("tagColorHexInvalid", - "[tag foo] { [property background]: [atom&error #ffg]; }"); - - MT("tagNegativeNumber", - "[tag foo] { [property margin]: [number -5px]; }"); - - MT("tagPositiveNumber", - "[tag foo] { [property padding]: [number 5px]; }"); - - MT("tagVendor", - "[tag foo] { [meta -foo-][property box-sizing]: [meta -foo-][atom border-box]; }"); - - MT("tagBogusProperty", - "[tag foo] { [property&error barhelloworld]: [number 0]; }"); - - MT("tagTwoProperties", - "[tag foo] { [property margin]: [number 0]; [property padding]: [number 0]; }"); - - MT("tagTwoPropertiesURL", - "[tag foo] { [property background]: [atom url]([string //example.com/foo.png]); [property padding]: [number 0]; }"); - - MT("indent_tagSelector", - "[tag strong], [tag em] {", - " [property background]: [atom rgba](", - " [number 255], [number 255], [number 0], [number .2]", - " );", - "}"); - - MT("indent_atMedia", - "[def @media] {", - " [tag foo] {", - " [property color]:", - " [keyword yellow];", - " }", - "}"); - - MT("indent_comma", - "[tag foo] {", - " [property font-family]: [variable verdana],", - " [atom sans-serif];", - "}"); - - MT("indent_parentheses", - "[tag foo]:[variable-3 before] {", - " [property background]: [atom url](", - "[string blahblah]", - "[string etc]", - "[string ]) [keyword !important];", - "}"); - - MT("font_face", - "[def @font-face] {", - " [property font-family]: [string 'myfont'];", - " [error nonsense]: [string 'abc'];", - " [property src]: [atom url]([string http://blah]),", - " [atom url]([string http://foo]);", - "}"); - - MT("empty_url", - "[def @import] [atom url]() [attribute screen];"); - - MT("parens", - "[qualifier .foo] {", - " [property background-image]: [variable fade]([atom #000], [number 20%]);", - " [property border-image]: [atom linear-gradient](", - " [atom to] [atom bottom],", - " [variable fade]([atom #000], [number 20%]) [number 0%],", - " [variable fade]([atom #000], [number 20%]) [number 100%]", - " );", - "}"); - - MT("css_variable", - ":[variable-3 root] {", - " [variable-2 --main-color]: [atom #06c];", - "}", - "[tag h1][builtin #foo] {", - " [property color]: [atom var]([variable-2 --main-color]);", - "}"); - - MT("supports", - "[def @supports] ([keyword not] (([property text-align-last]: [atom justify]) [keyword or] ([meta -moz-][property text-align-last]: [atom justify])) {", - " [property text-align-last]: [atom justify];", - "}"); - - MT("document", - "[def @document] [tag url]([string http://blah]),", - " [tag url-prefix]([string https://]),", - " [tag domain]([string blah.com]),", - " [tag regexp]([string \".*blah.+\"]) {", - " [builtin #id] {", - " [property background-color]: [keyword white];", - " }", - " [tag foo] {", - " [property font-family]: [variable Verdana], [atom sans-serif];", - " }", - "}"); - - MT("document_url", - "[def @document] [tag url]([string http://blah]) { [qualifier .class] { } }"); - - MT("document_urlPrefix", - "[def @document] [tag url-prefix]([string https://]) { [builtin #id] { } }"); - - MT("document_domain", - "[def @document] [tag domain]([string blah.com]) { [tag foo] { } }"); - - MT("document_regexp", - "[def @document] [tag regexp]([string \".*blah.+\"]) { [builtin #id] { } }"); - - MT("counter-style", - "[def @counter-style] [variable binary] {", - " [property system]: [atom numeric];", - " [property symbols]: [number 0] [number 1];", - " [property suffix]: [string \".\"];", - " [property range]: [atom infinite];", - " [property speak-as]: [atom numeric];", - "}"); - - MT("counter-style-additive-symbols", - "[def @counter-style] [variable simple-roman] {", - " [property system]: [atom additive];", - " [property additive-symbols]: [number 10] [variable X], [number 5] [variable V], [number 1] [variable I];", - " [property range]: [number 1] [number 49];", - "}"); - - MT("counter-style-use", - "[tag ol][qualifier .roman] { [property list-style]: [variable simple-roman]; }"); - - MT("counter-style-symbols", - "[tag ol] { [property list-style]: [atom symbols]([atom cyclic] [string \"*\"] [string \"\\2020\"] [string \"\\2021\"] [string \"\\A7\"]); }"); - - MT("comment-does-not-disrupt", - "[def @font-face] [comment /* foo */] {", - " [property src]: [atom url]([string x]);", - " [property font-family]: [variable One];", - "}") -})(); diff --git a/public/admin/view/javascript/lightshop/codemirror/mode/javascript/index.html b/public/admin/view/javascript/lightshop/codemirror/mode/javascript/index.html deleted file mode 100644 index 0ef8238..0000000 --- a/public/admin/view/javascript/lightshop/codemirror/mode/javascript/index.html +++ /dev/null @@ -1,114 +0,0 @@ - - -CodeMirror: JavaScript mode - - - - - - - - - - - - -
-

JavaScript mode

- - -
- - - -

- JavaScript mode supports several configuration options: -

    -
  • json which will set the mode to expect JSON - data rather than a JavaScript program.
  • -
  • jsonld which will set the mode to expect - JSON-LD linked data rather - than a JavaScript program (demo).
  • -
  • typescript which will activate additional - syntax highlighting and some other things for TypeScript code - (demo).
  • -
  • statementIndent which (given a number) will - determine the amount of indentation to use for statements - continued on a new line.
  • -
  • wordCharacters, a regexp that indicates which - characters should be considered part of an identifier. - Defaults to /[\w$]/, which does not handle - non-ASCII identifiers. Can be set to something more elaborate - to improve Unicode support.
  • -
-

- -

MIME types defined: text/javascript, application/json, application/ld+json, text/typescript, application/typescript.

-
diff --git a/public/admin/view/javascript/lightshop/codemirror/mode/javascript/javascript.js b/public/admin/view/javascript/lightshop/codemirror/mode/javascript/javascript.js deleted file mode 100644 index 617f4ec..0000000 --- a/public/admin/view/javascript/lightshop/codemirror/mode/javascript/javascript.js +++ /dev/null @@ -1,896 +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 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+(?:[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-f]+|o[0-7]+|b[01]+)n?/i)) { - 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.skipToEnd(); - return ret("error", "error"); - } 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) - } - } - 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)) { - return; - } 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, "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) { - 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 (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 - } - 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"), forspec, statement, poplex); - if (type == "class" || (isTS && value == "interface")) { cx.marked = "keyword"; return cont(pushlex("form"), 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(typeexpr, 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, block, 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(")"), expression, 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)); - if (type == "import") return cont(expression); - return cont(); - } - function maybeexpression(type) { - if (type.match(/[;\}\)\],]/)) return pass(); - return pass(expression); - } - - function maybeoperatorComma(type, value) { - if (type == ",") return cont(expression); - 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(expression, 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(); - 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 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") { - cx.marked = "keyword" - return cont(value == "keyof" ? typeexpr : expressionNoComma) - } - if (type == "variable" || value == "void") { - cx.marked = "type" - return cont(afterType) - } - if (type == "string" || type == "number" || type == "atom") return cont(afterType); - if (type == "[") return cont(pushlex("]"), commasep(typeexpr, "]", ","), poplex, afterType) - if (type == "{") return cont(pushlex("}"), commasep(typeprop, "}", ",;"), poplex, afterType) - if (type == "(") return cont(commasep(typearg, ")"), maybeReturnType) - if (type == "<") return cont(commasep(typeexpr, ">"), typeexpr) - } - function maybeReturnType(type) { - if (type == "=>") return cont(typeexpr) - } - function typeprop(type, value) { - if (type == "variable" || cx.style == "keyword") { - cx.marked = "property" - return cont(typeprop) - } else if (value == "?") { - return cont(typeprop) - } else if (type == ":") { - return cont(typeexpr) - } else if (type == "[") { - return cont(expression, maybetype, expect("]"), typeprop) - } - } - function typearg(type, value) { - if (type == "variable" && cx.stream.match(/^\s*[?:]/, false) || value == "?") return cont(typearg) - if (type == ":") return cont(typeexpr) - 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(expect("]"), afterType) - if (value == "extends" || value == "implements") { cx.marked = "keyword"; return cont(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(pattern, "]"); - 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(); - return cont(expect(":"), 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, expect(")"), poplex); - } - function forspec1(type) { - if (type == "var") return cont(vardef, expect(";"), forspec2); - if (type == ";") return cont(forspec2); - if (type == "variable") return cont(formaybeinof); - return pass(expression, expect(";"), forspec2); - } - function formaybeinof(_type, value) { - if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); } - return cont(maybeoperatorComma, forspec2); - } - function forspec2(type, value) { - if (type == ";") return cont(forspec3); - if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); } - return pass(expression, expect(";"), forspec3); - } - function forspec3(type) { - if (type != ")") cont(expression); - } - 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 funarg(type, value) { - if (value == "@") cont(expression, funarg) - if (type == "spread") return cont(funarg); - if (isTS && isModifier(value)) { cx.marked = "keyword"; return cont(funarg); } - 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(isTS ? classfield : functiondef, classBody); - } - if (type == "[") - return cont(expression, maybetype, expect("]"), isTS ? classfield : functiondef, classBody) - if (value == "*") { - cx.marked = "keyword"; - return cont(classBody); - } - if (type == ";") return cont(classBody); - if (type == "}") return cont(); - if (value == "@") return cont(expression, classBody) - } - function classfield(type, value) { - if (value == "?") return cont(classfield) - if (type == ":") return cont(typeexpr, maybeAssign) - if (value == "=") return cont(expressionNoComma) - return pass(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); - 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) 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) 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) { - var top = state.cc[state.cc.length - 1] - if (top == expression || top == expressionNoComma) state.cc.pop() - } - }; -}); - -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/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/public/admin/view/javascript/lightshop/codemirror/mode/javascript/json-ld.html b/public/admin/view/javascript/lightshop/codemirror/mode/javascript/json-ld.html deleted file mode 100644 index aea2ef4..0000000 --- a/public/admin/view/javascript/lightshop/codemirror/mode/javascript/json-ld.html +++ /dev/null @@ -1,72 +0,0 @@ - - -CodeMirror: JSON-LD mode - - - - - - - - - - - - -
-

JSON-LD mode

- - -
- - - -

This is a specialization of the JavaScript mode.

-
diff --git a/public/admin/view/javascript/lightshop/codemirror/mode/javascript/test.js b/public/admin/view/javascript/lightshop/codemirror/mode/javascript/test.js deleted file mode 100644 index 9dff7a0..0000000 --- a/public/admin/view/javascript/lightshop/codemirror/mode/javascript/test.js +++ /dev/null @@ -1,482 +0,0 @@ -// CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE - -(function() { - var mode = CodeMirror.getMode({indentUnit: 2}, "javascript"); - function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); } - - MT("locals", - "[keyword function] [def foo]([def a], [def b]) { [keyword var] [def c] [operator =] [number 10]; [keyword return] [variable-2 a] [operator +] [variable-2 c] [operator +] [variable d]; }"); - - MT("comma-and-binop", - "[keyword function](){ [keyword var] [def x] [operator =] [number 1] [operator +] [number 2], [def y]; }"); - - MT("destructuring", - "([keyword function]([def a], [[[def b], [def c] ]]) {", - " [keyword let] {[def d], [property foo]: [def c][operator =][number 10], [def x]} [operator =] [variable foo]([variable-2 a]);", - " [[[variable-2 c], [variable y] ]] [operator =] [variable-2 c];", - "})();"); - - MT("destructure_trailing_comma", - "[keyword let] {[def a], [def b],} [operator =] [variable foo];", - "[keyword let] [def c];"); // Parser still in good state? - - MT("class_body", - "[keyword class] [def Foo] {", - " [property constructor]() {}", - " [property sayName]() {", - " [keyword return] [string-2 `foo${][variable foo][string-2 }oo`];", - " }", - "}"); - - MT("class", - "[keyword class] [def Point] [keyword extends] [variable SuperThing] {", - " [keyword get] [property prop]() { [keyword return] [number 24]; }", - " [property constructor]([def x], [def y]) {", - " [keyword super]([string 'something']);", - " [keyword this].[property x] [operator =] [variable-2 x];", - " }", - "}"); - - MT("anonymous_class_expression", - "[keyword const] [def Adder] [operator =] [keyword class] [keyword extends] [variable Arithmetic] {", - " [property add]([def a], [def b]) {}", - "};"); - - MT("named_class_expression", - "[keyword const] [def Subber] [operator =] [keyword class] [def Subtract] {", - " [property sub]([def a], [def b]) {}", - "};"); - - MT("class_async_method", - "[keyword class] [def Foo] {", - " [property sayName1]() {}", - " [keyword async] [property sayName2]() {}", - "}"); - - MT("import", - "[keyword function] [def foo]() {", - " [keyword import] [def $] [keyword from] [string 'jquery'];", - " [keyword import] { [def encrypt], [def decrypt] } [keyword from] [string 'crypto'];", - "}"); - - MT("import_trailing_comma", - "[keyword import] {[def foo], [def bar],} [keyword from] [string 'baz']") - - MT("import_dynamic", - "[keyword import]([string 'baz']).[property then]") - - MT("import_dynamic", - "[keyword const] [def t] [operator =] [keyword import]([string 'baz']).[property then]") - - MT("const", - "[keyword function] [def f]() {", - " [keyword const] [[ [def a], [def b] ]] [operator =] [[ [number 1], [number 2] ]];", - "}"); - - MT("for/of", - "[keyword for]([keyword let] [def of] [keyword of] [variable something]) {}"); - - MT("for await", - "[keyword for] [keyword await]([keyword let] [def of] [keyword of] [variable something]) {}"); - - MT("generator", - "[keyword function*] [def repeat]([def n]) {", - " [keyword for]([keyword var] [def i] [operator =] [number 0]; [variable-2 i] [operator <] [variable-2 n]; [operator ++][variable-2 i])", - " [keyword yield] [variable-2 i];", - "}"); - - MT("let_scoping", - "[keyword function] [def scoped]([def n]) {", - " { [keyword var] [def i]; } [variable-2 i];", - " { [keyword let] [def j]; [variable-2 j]; } [variable j];", - " [keyword if] ([atom true]) { [keyword const] [def k]; [variable-2 k]; } [variable k];", - "}"); - - MT("switch_scoping", - "[keyword switch] ([variable x]) {", - " [keyword default]:", - " [keyword let] [def j];", - " [keyword return] [variable-2 j]", - "}", - "[variable j];") - - MT("leaving_scope", - "[keyword function] [def a]() {", - " {", - " [keyword const] [def x] [operator =] [number 1]", - " [keyword if] ([atom true]) {", - " [keyword let] [def y] [operator =] [number 2]", - " [keyword var] [def z] [operator =] [number 3]", - " [variable console].[property log]([variable-2 x], [variable-2 y], [variable-2 z])", - " }", - " [variable console].[property log]([variable-2 x], [variable y], [variable-2 z])", - " }", - " [variable console].[property log]([variable x], [variable y], [variable-2 z])", - "}") - - MT("quotedStringAddition", - "[keyword let] [def f] [operator =] [variable a] [operator +] [string 'fatarrow'] [operator +] [variable c];"); - - MT("quotedFatArrow", - "[keyword let] [def f] [operator =] [variable a] [operator +] [string '=>'] [operator +] [variable c];"); - - MT("fatArrow", - "[variable array].[property filter]([def a] [operator =>] [variable-2 a] [operator +] [number 1]);", - "[variable a];", // No longer in scope - "[keyword let] [def f] [operator =] ([[ [def a], [def b] ]], [def c]) [operator =>] [variable-2 a] [operator +] [variable-2 c];", - "[variable c];"); - - MT("spread", - "[keyword function] [def f]([def a], [meta ...][def b]) {", - " [variable something]([variable-2 a], [meta ...][variable-2 b]);", - "}"); - - MT("quasi", - "[variable re][string-2 `fofdlakj${][variable x] [operator +] ([variable re][string-2 `foo`]) [operator +] [number 1][string-2 }fdsa`] [operator +] [number 2]"); - - MT("quasi_no_function", - "[variable x] [operator =] [string-2 `fofdlakj${][variable x] [operator +] [string-2 `foo`] [operator +] [number 1][string-2 }fdsa`] [operator +] [number 2]"); - - MT("indent_statement", - "[keyword var] [def x] [operator =] [number 10]", - "[variable x] [operator +=] [variable y] [operator +]", - " [atom Infinity]", - "[keyword debugger];"); - - MT("indent_if", - "[keyword if] ([number 1])", - " [keyword break];", - "[keyword else] [keyword if] ([number 2])", - " [keyword continue];", - "[keyword else]", - " [number 10];", - "[keyword if] ([number 1]) {", - " [keyword break];", - "} [keyword else] [keyword if] ([number 2]) {", - " [keyword continue];", - "} [keyword else] {", - " [number 10];", - "}"); - - MT("indent_for", - "[keyword for] ([keyword var] [def i] [operator =] [number 0];", - " [variable i] [operator <] [number 100];", - " [variable i][operator ++])", - " [variable doSomething]([variable i]);", - "[keyword debugger];"); - - MT("indent_c_style", - "[keyword function] [def foo]()", - "{", - " [keyword debugger];", - "}"); - - MT("indent_else", - "[keyword for] (;;)", - " [keyword if] ([variable foo])", - " [keyword if] ([variable bar])", - " [number 1];", - " [keyword else]", - " [number 2];", - " [keyword else]", - " [number 3];"); - - MT("indent_funarg", - "[variable foo]([number 10000],", - " [keyword function]([def a]) {", - " [keyword debugger];", - "};"); - - MT("indent_below_if", - "[keyword for] (;;)", - " [keyword if] ([variable foo])", - " [number 1];", - "[number 2];"); - - MT("indent_semicolonless_if", - "[keyword function] [def foo]() {", - " [keyword if] ([variable x])", - " [variable foo]()", - "}") - - MT("indent_semicolonless_if_with_statement", - "[keyword function] [def foo]() {", - " [keyword if] ([variable x])", - " [variable foo]()", - " [variable bar]()", - "}") - - MT("multilinestring", - "[keyword var] [def x] [operator =] [string 'foo\\]", - "[string bar'];"); - - MT("scary_regexp", - "[string-2 /foo[[/]]bar/];"); - - MT("indent_strange_array", - "[keyword var] [def x] [operator =] [[", - " [number 1],,", - " [number 2],", - "]];", - "[number 10];"); - - MT("param_default", - "[keyword function] [def foo]([def x] [operator =] [string-2 `foo${][number 10][string-2 }bar`]) {", - " [keyword return] [variable-2 x];", - "}"); - - MT("new_target", - "[keyword function] [def F]([def target]) {", - " [keyword if] ([variable-2 target] [operator &&] [keyword new].[keyword target].[property name]) {", - " [keyword return] [keyword new]", - " .[keyword target];", - " }", - "}"); - - MT("async", - "[keyword async] [keyword function] [def foo]([def args]) { [keyword return] [atom true]; }"); - - MT("async_assignment", - "[keyword const] [def foo] [operator =] [keyword async] [keyword function] ([def args]) { [keyword return] [atom true]; };"); - - MT("async_object", - "[keyword let] [def obj] [operator =] { [property async]: [atom false] };"); - - // async be highlighet as keyword and foo as def, but it requires potentially expensive look-ahead. See #4173 - MT("async_object_function", - "[keyword let] [def obj] [operator =] { [property async] [property foo]([def args]) { [keyword return] [atom true]; } };"); - - MT("async_object_properties", - "[keyword let] [def obj] [operator =] {", - " [property prop1]: [keyword async] [keyword function] ([def args]) { [keyword return] [atom true]; },", - " [property prop2]: [keyword async] [keyword function] ([def args]) { [keyword return] [atom true]; },", - " [property prop3]: [keyword async] [keyword function] [def prop3]([def args]) { [keyword return] [atom true]; },", - "};"); - - MT("async_arrow", - "[keyword const] [def foo] [operator =] [keyword async] ([def args]) [operator =>] { [keyword return] [atom true]; };"); - - MT("async_jquery", - "[variable $].[property ajax]({", - " [property url]: [variable url],", - " [property async]: [atom true],", - " [property method]: [string 'GET']", - "});"); - - MT("async_variable", - "[keyword const] [def async] [operator =] {[property a]: [number 1]};", - "[keyword const] [def foo] [operator =] [string-2 `bar ${][variable async].[property a][string-2 }`];") - - MT("bigint", "[number 1n] [operator +] [number 0x1afn] [operator +] [number 0o064n] [operator +] [number 0b100n];") - - MT("async_comment", - "[keyword async] [comment /**/] [keyword function] [def foo]([def args]) { [keyword return] [atom true]; }"); - - MT("indent_switch", - "[keyword switch] ([variable x]) {", - " [keyword default]:", - " [keyword return] [number 2]", - "}") - - MT("regexp_corner_case", - "[operator +]{} [operator /] [atom undefined];", - "[[[meta ...][string-2 /\\//] ]];", - "[keyword void] [string-2 /\\//];", - "[keyword do] [string-2 /\\//]; [keyword while] ([number 0]);", - "[keyword if] ([number 0]) {} [keyword else] [string-2 /\\//];", - "[string-2 `${][variable async][operator ++][string-2 }//`];", - "[string-2 `${]{} [operator /] [string-2 /\\//}`];") - - MT("return_eol", - "[keyword return]", - "{} [string-2 /5/]") - - var ts_mode = CodeMirror.getMode({indentUnit: 2}, "application/typescript") - function TS(name) { - test.mode(name, ts_mode, Array.prototype.slice.call(arguments, 1)) - } - - TS("typescript_extend_type", - "[keyword class] [def Foo] [keyword extends] [type Some][operator <][type Type][operator >] {}") - - TS("typescript_arrow_type", - "[keyword let] [def x]: ([variable arg]: [type Type]) [operator =>] [type ReturnType]") - - TS("typescript_class", - "[keyword class] [def Foo] {", - " [keyword public] [keyword static] [property main]() {}", - " [keyword private] [property _foo]: [type string];", - "}") - - TS("typescript_literal_types", - "[keyword import] [keyword *] [keyword as] [def Sequelize] [keyword from] [string 'sequelize'];", - "[keyword interface] [def MyAttributes] {", - " [property truthy]: [string 'true'] [operator |] [number 1] [operator |] [atom true];", - " [property falsy]: [string 'false'] [operator |] [number 0] [operator |] [atom false];", - "}", - "[keyword interface] [def MyInstance] [keyword extends] [type Sequelize].[type Instance] [operator <] [type MyAttributes] [operator >] {", - " [property rawAttributes]: [type MyAttributes];", - " [property truthy]: [string 'true'] [operator |] [number 1] [operator |] [atom true];", - " [property falsy]: [string 'false'] [operator |] [number 0] [operator |] [atom false];", - "}") - - TS("typescript_extend_operators", - "[keyword export] [keyword interface] [def UserModel] [keyword extends]", - " [type Sequelize].[type Model] [operator <] [type UserInstance], [type UserAttributes] [operator >] {", - " [property findById]: (", - " [variable userId]: [type number]", - " ) [operator =>] [type Promise] [operator <] [type Array] [operator <] { [property id], [property name] } [operator >>];", - " [property updateById]: (", - " [variable userId]: [type number],", - " [variable isActive]: [type boolean]", - " ) [operator =>] [type Promise] [operator <] [type AccountHolderNotificationPreferenceInstance] [operator >];", - " }") - - TS("typescript_interface_with_const", - "[keyword const] [def hello]: {", - " [property prop1][operator ?]: [type string];", - " [property prop2][operator ?]: [type string];", - "} [operator =] {};") - - TS("typescript_double_extend", - "[keyword export] [keyword interface] [def UserAttributes] {", - " [property id][operator ?]: [type number];", - " [property createdAt][operator ?]: [type Date];", - "}", - "[keyword export] [keyword interface] [def UserInstance] [keyword extends] [type Sequelize].[type Instance][operator <][type UserAttributes][operator >], [type UserAttributes] {", - " [property id]: [type number];", - " [property createdAt]: [type Date];", - "}"); - - TS("typescript_index_signature", - "[keyword interface] [def A] {", - " [[ [variable prop]: [type string] ]]: [type any];", - " [property prop1]: [type any];", - "}"); - - TS("typescript_generic_class", - "[keyword class] [def Foo][operator <][type T][operator >] {", - " [property bar]() {}", - " [property foo](): [type Foo] {}", - "}") - - TS("typescript_type_when_keyword", - "[keyword export] [keyword type] [type AB] [operator =] [type A] [operator |] [type B];", - "[keyword type] [type Flags] [operator =] {", - " [property p1]: [type string];", - " [property p2]: [type boolean];", - "};") - - TS("typescript_type_when_not_keyword", - "[keyword class] [def HasType] {", - " [property type]: [type string];", - " [property constructor]([def type]: [type string]) {", - " [keyword this].[property type] [operator =] [variable-2 type];", - " }", - " [property setType]({ [def type] }: { [property type]: [type string]; }) {", - " [keyword this].[property type] [operator =] [variable-2 type];", - " }", - "}") - - TS("typescript_function_generics", - "[keyword function] [def a]() {}", - "[keyword function] [def b][operator <][type IA] [keyword extends] [type object], [type IB] [keyword extends] [type object][operator >]() {}", - "[keyword function] [def c]() {}") - - TS("typescript_complex_return_type", - "[keyword function] [def A]() {", - " [keyword return] [keyword this].[property property];", - "}", - "[keyword function] [def B](): [type Promise][operator <]{ [[ [variable key]: [type string] ]]: [type any] } [operator |] [atom null][operator >] {", - " [keyword return] [keyword this].[property property];", - "}") - - TS("typescript_complex_type_casting", - "[keyword const] [def giftpay] [operator =] [variable config].[property get]([string 'giftpay']) [keyword as] { [[ [variable platformUuid]: [type string] ]]: { [property version]: [type number]; [property apiCode]: [type string]; } };") - - TS("typescript_keyof", - "[keyword function] [def x][operator <][type T] [keyword extends] [keyword keyof] [type X][operator >]([def a]: [type T]) {", - " [keyword return]") - - TS("typescript_new_typeargs", - "[keyword let] [def x] [operator =] [keyword new] [variable Map][operator <][type string], [type Date][operator >]([string-2 `foo${][variable bar][string-2 }`])") - - TS("modifiers", - "[keyword class] [def Foo] {", - " [keyword public] [keyword abstract] [property bar]() {}", - " [property constructor]([keyword readonly] [keyword private] [def x]) {}", - "}") - - TS("arrow prop", - "({[property a]: [def p] [operator =>] [variable-2 p]})") - - TS("generic in function call", - "[keyword this].[property a][operator <][type Type][operator >]([variable foo]);", - "[keyword this].[property a][operator <][variable Type][operator >][variable foo];") - - TS("type guard", - "[keyword class] [def Appler] {", - " [keyword static] [property assertApple]([def fruit]: [type Fruit]): [variable-2 fruit] [keyword is] [type Apple] {", - " [keyword if] ([operator !]([variable-2 fruit] [keyword instanceof] [variable Apple]))", - " [keyword throw] [keyword new] [variable Error]();", - " }", - "}") - - TS("type as variable", - "[variable type] [operator =] [variable x] [keyword as] [type Bar];"); - - TS("enum body", - "[keyword export] [keyword const] [keyword enum] [def CodeInspectionResultType] {", - " [def ERROR] [operator =] [string 'problem_type_error'],", - " [def WARNING] [operator =] [string 'problem_type_warning'],", - " [def META],", - "}") - - TS("parenthesized type", - "[keyword class] [def Foo] {", - " [property x] [operator =] [keyword new] [variable A][operator <][type B], [type string][operator |](() [operator =>] [type void])[operator >]();", - " [keyword private] [property bar]();", - "}") - - TS("abstract class", - "[keyword export] [keyword abstract] [keyword class] [def Foo] {}") - - var jsonld_mode = CodeMirror.getMode( - {indentUnit: 2}, - {name: "javascript", jsonld: true} - ); - function LD(name) { - test.mode(name, jsonld_mode, Array.prototype.slice.call(arguments, 1)); - } - - LD("json_ld_keywords", - '{', - ' [meta "@context"]: {', - ' [meta "@base"]: [string "http://example.com"],', - ' [meta "@vocab"]: [string "http://xmlns.com/foaf/0.1/"],', - ' [property "likesFlavor"]: {', - ' [meta "@container"]: [meta "@list"]', - ' [meta "@reverse"]: [string "@beFavoriteOf"]', - ' },', - ' [property "nick"]: { [meta "@container"]: [meta "@set"] },', - ' [property "nick"]: { [meta "@container"]: [meta "@index"] }', - ' },', - ' [meta "@graph"]: [[ {', - ' [meta "@id"]: [string "http://dbpedia.org/resource/John_Lennon"],', - ' [property "name"]: [string "John Lennon"],', - ' [property "modified"]: {', - ' [meta "@value"]: [string "2010-05-29T14:17:39+02:00"],', - ' [meta "@type"]: [string "http://www.w3.org/2001/XMLSchema#dateTime"]', - ' }', - ' } ]]', - '}'); - - LD("json_ld_fake", - '{', - ' [property "@fake"]: [string "@fake"],', - ' [property "@contextual"]: [string "@identifier"],', - ' [property "user@domain.com"]: [string "@graphical"],', - ' [property "@ID"]: [string "@@ID"]', - '}'); -})(); diff --git a/public/admin/view/javascript/lightshop/codemirror/mode/javascript/typescript.html b/public/admin/view/javascript/lightshop/codemirror/mode/javascript/typescript.html deleted file mode 100644 index 58d0fe1..0000000 --- a/public/admin/view/javascript/lightshop/codemirror/mode/javascript/typescript.html +++ /dev/null @@ -1,61 +0,0 @@ - - -CodeMirror: TypeScript mode - - - - - - - - - -
-

TypeScript mode

- - -
- - - -

This is a specialization of the JavaScript mode.

-
diff --git a/public/admin/view/javascript/lightshop/colorpicker/css/bootstrap-colorpicker.min.css b/public/admin/view/javascript/lightshop/colorpicker/css/bootstrap-colorpicker.min.css deleted file mode 100644 index 58164ea..0000000 --- a/public/admin/view/javascript/lightshop/colorpicker/css/bootstrap-colorpicker.min.css +++ /dev/null @@ -1,10 +0,0 @@ -/*! - * Bootstrap Colorpicker v2.5.2 - * https://itsjavi.com/bootstrap-colorpicker/ - * - * Originally written by (c) 2012 Stefan Petre - * Licensed under the Apache License v2.0 - * http://www.apache.org/licenses/LICENSE-2.0.txt - * - */.colorpicker-saturation{width:100px;height:100px;background-image:url(data:image/png;base64,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);cursor:crosshair;float:left}.colorpicker-saturation i{display:block;height:5px;width:5px;border:1px solid #000;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;position:absolute;top:0;left:0;margin:-4px 0 0 -4px}.colorpicker-saturation i b{display:block;height:5px;width:5px;border:1px solid #fff;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.colorpicker-alpha,.colorpicker-hue{width:15px;height:100px;float:left;cursor:row-resize;margin-left:4px;margin-bottom:4px}.colorpicker-alpha i,.colorpicker-hue i{display:block;height:1px;background:#000;border-top:1px solid #fff;position:absolute;top:0;left:0;width:100%;margin-top:-1px}.colorpicker-hue{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAABkCAMAAABw8qpSAAABLFBMVEXqFBb/ABH/ACL/ADH/AEH/AFD/AGD/AG7/AH7/AI3/AJ3/AKz/ALz/AMr/ANv/AOr/APr2AP/mAP/XAP/HAP+4AP+oAP+aAP+JAP97AP9rAP9cAP9MAP8+AP8tAP8fAP8PAP8BAv8AEP8AH/8AL/8APv8ATv8AXP8Abf8Ae/8Ai/8Amv8Aqv8AuP8Ayf8A1/8A5/8A9/8A//gA/+kA/9kA/8oA/7oA/6wA/5sA/40A/30A/24A/14A/1AA/z8A/zEA/yEA/xEB/wMN/wAd/wAs/wA8/wBK/wBb/wBp/wB5/wCI/wCY/wCm/wC3/wDF/wDV/wDk/wD1/wD/+gD/7AD/3AD/zAD/vgD/rQD/nwD/jgD/gAD/cAD/YgD/UQD/QwD/MgD/JAD/FAD4Eg42qAedAAAAh0lEQVR4XgXAg3EDAAAAwI9to7Zt27a1/w49BASFhEVExcQlJKWkZWTl5BUUlZRVVNXUNTS1tHXo1KVbj159+g0YNGTYiFFjxk2YNGXajFlz5i1YtGTZilVr1m3YtGXbjl179h04dOTYiVNnzl24dOXajVt37j149OTZi1dv3n349OXbj19//wOxE1dQ8reGAAAAAElFTkSuQmCC)}.colorpicker-alpha{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAABkCAQAAAAVxWkcAAABr0lEQVR4Xo2VwU0DQQxF7dmRuNIFlzlSAR3QAaXQQdIBJVABFXDcOVAAd67cjJLR07dkhcSrkZKfb/t7bG88rFo3B5gZPMNycItu2xloGV7MWHzM9zuzFWCkmA0nK6AszCUJDW6+mG6R03ncw5v8EMTEvZ2O3AliYjpslblc0RF9LmZYWxURU6aKytWZYsoWCAe+xwOZp1GsEukGiIkYxcQCHck99+gRgB7JncyIB5SGEhP3Yh5P6JwX+u6AnYot104d8DJT7uH7M9JH6OZbimj0vfMVaYnJIZFJDBW9kHlerL2C6JV4mSt7uuo2N57RxnZ+usQjn0R1jwBJBrNO3evJpVYUWsJ/E3UiXRlv24/7YZ04xmEdWlzcKS+B/eapeyMvFd2k0+hRk/T0AmTW8h69s2sjYMsdPntECiILhAeIMZAeH4QvUwfn6ijC0tTV+fT9ky8jM9nK2g7Ly1VjSpKYq6IvsAm7MtNu1orEqa/K3KNvgMFdhfquPfJmp2dbh0/8Gzb6Y22ViaNr6n5410zXdngVhbu6XqdOtWOuin5hjABGp4a2uotZ71MVCfwDBt2/v37yo6AAAAAASUVORK5CYII=);display:none}.colorpicker-alpha,.colorpicker-hue,.colorpicker-saturation{background-size:contain}.colorpicker{padding:4px;min-width:130px;margin-top:1px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;z-index:2500}.colorpicker:after,.colorpicker:before{display:table;content:"";line-height:0}.colorpicker:after{clear:both}.colorpicker:before{content:'';display:inline-block;border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-bottom-color:rgba(0,0,0,.2);position:absolute;top:-7px;left:6px}.colorpicker:after{content:'';display:inline-block;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #fff;position:absolute;top:-6px;left:7px}.colorpicker div{position:relative}.colorpicker.colorpicker-with-alpha{min-width:140px}.colorpicker.colorpicker-with-alpha .colorpicker-alpha{display:block}.colorpicker-color{height:10px;margin-top:5px;clear:both;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAABkCAQAAAAVxWkcAAABr0lEQVR4Xo2VwU0DQQxF7dmRuNIFlzlSAR3QAaXQQdIBJVABFXDcOVAAd67cjJLR07dkhcSrkZKfb/t7bG88rFo3B5gZPMNycItu2xloGV7MWHzM9zuzFWCkmA0nK6AszCUJDW6+mG6R03ncw5v8EMTEvZ2O3AliYjpslblc0RF9LmZYWxURU6aKytWZYsoWCAe+xwOZp1GsEukGiIkYxcQCHck99+gRgB7JncyIB5SGEhP3Yh5P6JwX+u6AnYot104d8DJT7uH7M9JH6OZbimj0vfMVaYnJIZFJDBW9kHlerL2C6JV4mSt7uuo2N57RxnZ+usQjn0R1jwBJBrNO3evJpVYUWsJ/E3UiXRlv24/7YZ04xmEdWlzcKS+B/eapeyMvFd2k0+hRk/T0AmTW8h69s2sjYMsdPntECiILhAeIMZAeH4QvUwfn6ijC0tTV+fT9ky8jM9nK2g7Ly1VjSpKYq6IvsAm7MtNu1orEqa/K3KNvgMFdhfquPfJmp2dbh0/8Gzb6Y22ViaNr6n5410zXdngVhbu6XqdOtWOuin5hjABGp4a2uotZ71MVCfwDBt2/v37yo6AAAAAASUVORK5CYII=);background-position:0 100%}.colorpicker-color div{height:10px}.colorpicker-selectors{display:none;height:10px;margin-top:5px;clear:both}.colorpicker-selectors i{cursor:pointer;float:left;height:10px;width:10px}.colorpicker-selectors i+i{margin-left:3px}.colorpicker-element .add-on i,.colorpicker-element .input-group-addon i{display:inline-block;cursor:pointer;height:16px;vertical-align:text-top;width:16px}.colorpicker.colorpicker-inline{position:relative;display:inline-block;float:none;z-index:auto}.colorpicker.colorpicker-horizontal{width:110px;min-width:110px;height:auto}.colorpicker.colorpicker-horizontal .colorpicker-saturation{margin-bottom:4px}.colorpicker.colorpicker-horizontal .colorpicker-color{width:100px}.colorpicker.colorpicker-horizontal .colorpicker-alpha,.colorpicker.colorpicker-horizontal .colorpicker-hue{width:100px;height:15px;float:left;cursor:col-resize;margin-left:0;margin-bottom:4px}.colorpicker.colorpicker-horizontal .colorpicker-alpha i,.colorpicker.colorpicker-horizontal .colorpicker-hue i{display:block;height:15px;background:#fff;position:absolute;top:0;left:0;width:1px;border:none;margin-top:0}.colorpicker.colorpicker-horizontal .colorpicker-hue{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAAABCAMAAAAfBfuPAAABLFBMVEXqFBb/ABH/ACL/ADH/AEH/AFD/AGD/AG7/AH7/AI3/AJ3/AKz/ALz/AMr/ANv/AOr/APr2AP/mAP/XAP/HAP+4AP+oAP+aAP+JAP97AP9rAP9cAP9MAP8+AP8tAP8fAP8PAP8BAv8AEP8AH/8AL/8APv8ATv8AXP8Abf8Ae/8Ai/8Amv8Aqv8AuP8Ayf8A1/8A5/8A9/8A//gA/+kA/9kA/8oA/7oA/6wA/5sA/40A/30A/24A/14A/1AA/z8A/zEA/yEA/xEB/wMN/wAd/wAs/wA8/wBK/wBb/wBp/wB5/wCI/wCY/wCm/wC3/wDF/wDV/wDk/wD1/wD/+gD/7AD/3AD/zAD/vgD/rQD/nwD/jgD/gAD/cAD/YgD/UQD/QwD/MgD/JAD/FAD4Eg42qAedAAAAbUlEQVR4XgXAghEDsbxtlrZt27ax/w49ACAYQTGcICmaYTleECVZUTXdMC1Wm93hdLk9Xp8/EAyFI9FYPJFMpTPZXL5QLJUr1Vq90Wy1O91efzAcjSfT2XyxXK03293+cDydL9fb/fF8vT/f3x+LfRNXARMbCAAAAABJRU5ErkJggg==)}.colorpicker.colorpicker-horizontal .colorpicker-alpha{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAAAKCAQAAADoFTP1AAAB9ElEQVR4XoWTQW4VMRBEu9qWEimL7DhEMp8NF+ASnJJLcAQgE1bcgBUSkYKUuHCrZ9pjeqSU5Yn9LPu7umJQBIIv+k7vIOrtK66L4lmr3pVOrOv3otp619KZ0/KjdNI79L52Uo09FBQWrU0vfe5trezU+hLsoUKd3Repovte+0vbq/7Lj5XbaHECKasR9G4MPlbp+gzZxd6koPEJCkAYC5SjcOTAIIOK90Dja1IfIZ8Z+zAY9jm3b5Ia+MT5sFcqRJrR2AYYA8Kua5BzYRrFPNmD4PQMegGJMOffJJUsWiI3nCHZZjInNdffLWOufzbc3JaboCAVxwmnRHbhLSPwRJ4wU0BRSc6HkECYYVw95nMKgJOcylxrJttE5Ibzf9Xq9GPvP+WX3MiV/MGHfRu/SentRQrfG1GzsIrytdNXucSRKxQNIGHM9YhGFQJcdjNcBZvfJayuYe4Sia1CzwW+19mWOhe37HsxJWKwbu/jluEU15QzAQjAqCEbhMJc78GYV2E0kooHDubUImWkTOhGpgv8PoT8DJG/bzxna4BZ0eOFSOaLADGeSpFsg5AzeaDZIDQQXjZ4y/8ryfzUXBwdELRjTjCNvOeT0rNlrJz90vwy6N9pXXQEluX0inElpPWokSdiLCfiNJJjMKQ8Qsh8GEKQKMo/eiHrNbI9UksAAAAASUVORK5CYII=)}.colorpicker-right:before{left:auto;right:6px}.colorpicker-right:after{left:auto;right:7px}.colorpicker-no-arrow:before{border-right:0;border-left:0}.colorpicker-no-arrow:after{border-right:0;border-left:0}.colorpicker-alpha.colorpicker-visible,.colorpicker-hue.colorpicker-visible,.colorpicker-saturation.colorpicker-visible,.colorpicker-selectors.colorpicker-visible,.colorpicker.colorpicker-visible{display:block}.colorpicker-alpha.colorpicker-hidden,.colorpicker-hue.colorpicker-hidden,.colorpicker-saturation.colorpicker-hidden,.colorpicker-selectors.colorpicker-hidden,.colorpicker.colorpicker-hidden{display:none}.colorpicker-inline.colorpicker-visible{display:inline-block} -/*# sourceMappingURL=bootstrap-colorpicker.min.css.map */ \ No newline at end of file diff --git a/public/admin/view/javascript/lightshop/colorpicker/js/bootstrap-colorpicker.js b/public/admin/view/javascript/lightshop/colorpicker/js/bootstrap-colorpicker.js deleted file mode 100644 index f96e5ff..0000000 --- a/public/admin/view/javascript/lightshop/colorpicker/js/bootstrap-colorpicker.js +++ /dev/null @@ -1,1327 +0,0 @@ -/*! - * Bootstrap Colorpicker v2.5.2 - * https://itsjavi.com/bootstrap-colorpicker/ - * - * Originally written by (c) 2012 Stefan Petre - * Licensed under the Apache License v2.0 - * http://www.apache.org/licenses/LICENSE-2.0.txt - * - */ - -(function(root, factory) { - if (typeof define === 'function' && define.amd) { - // AMD. Register as an anonymous module unless amdModuleId is set - define(["jquery"], function(jq) { - return (factory(jq)); - }); - } else if (typeof exports === 'object') { - // Node. Does not work with strict CommonJS, but - // only CommonJS-like environments that support module.exports, - // like Node. - module.exports = factory(require("jquery")); - } else if (jQuery && !jQuery.fn.colorpicker) { - factory(jQuery); - } -}(this, function($) { - 'use strict'; - /** - * Color manipulation helper class - * - * @param {Object|String} [val] - * @param {Object} [predefinedColors] - * @param {String|null} [fallbackColor] - * @param {String|null} [fallbackFormat] - * @param {Boolean} [hexNumberSignPrefix] - * @constructor - */ - var Color = function( - val, predefinedColors, fallbackColor, fallbackFormat, hexNumberSignPrefix) { - this.fallbackValue = fallbackColor ? - ( - (typeof fallbackColor === 'string') ? - this.parse(fallbackColor) : - fallbackColor - ) : - null; - - this.fallbackFormat = fallbackFormat ? fallbackFormat : 'rgba'; - - this.hexNumberSignPrefix = hexNumberSignPrefix === true; - - this.value = this.fallbackValue; - - this.origFormat = null; // original string format - - this.predefinedColors = predefinedColors ? predefinedColors : {}; - - // We don't want to share aliases across instances so we extend new object - this.colors = $.extend({}, Color.webColors, this.predefinedColors); - - if (val) { - if (typeof val.h !== 'undefined') { - this.value = val; - } else { - this.setColor(String(val)); - } - } - - if (!this.value) { - // Initial value is always black if no arguments are passed or val is empty - this.value = { - h: 0, - s: 0, - b: 0, - a: 1 - }; - } - }; - - Color.webColors = { // 140 predefined colors from the HTML Colors spec - "aliceblue": "f0f8ff", - "antiquewhite": "faebd7", - "aqua": "00ffff", - "aquamarine": "7fffd4", - "azure": "f0ffff", - "beige": "f5f5dc", - "bisque": "ffe4c4", - "black": "000000", - "blanchedalmond": "ffebcd", - "blue": "0000ff", - "blueviolet": "8a2be2", - "brown": "a52a2a", - "burlywood": "deb887", - "cadetblue": "5f9ea0", - "chartreuse": "7fff00", - "chocolate": "d2691e", - "coral": "ff7f50", - "cornflowerblue": "6495ed", - "cornsilk": "fff8dc", - "crimson": "dc143c", - "cyan": "00ffff", - "darkblue": "00008b", - "darkcyan": "008b8b", - "darkgoldenrod": "b8860b", - "darkgray": "a9a9a9", - "darkgreen": "006400", - "darkkhaki": "bdb76b", - "darkmagenta": "8b008b", - "darkolivegreen": "556b2f", - "darkorange": "ff8c00", - "darkorchid": "9932cc", - "darkred": "8b0000", - "darksalmon": "e9967a", - "darkseagreen": "8fbc8f", - "darkslateblue": "483d8b", - "darkslategray": "2f4f4f", - "darkturquoise": "00ced1", - "darkviolet": "9400d3", - "deeppink": "ff1493", - "deepskyblue": "00bfff", - "dimgray": "696969", - "dodgerblue": "1e90ff", - "firebrick": "b22222", - "floralwhite": "fffaf0", - "forestgreen": "228b22", - "fuchsia": "ff00ff", - "gainsboro": "dcdcdc", - "ghostwhite": "f8f8ff", - "gold": "ffd700", - "goldenrod": "daa520", - "gray": "808080", - "green": "008000", - "greenyellow": "adff2f", - "honeydew": "f0fff0", - "hotpink": "ff69b4", - "indianred": "cd5c5c", - "indigo": "4b0082", - "ivory": "fffff0", - "khaki": "f0e68c", - "lavender": "e6e6fa", - "lavenderblush": "fff0f5", - "lawngreen": "7cfc00", - "lemonchiffon": "fffacd", - "lightblue": "add8e6", - "lightcoral": "f08080", - "lightcyan": "e0ffff", - "lightgoldenrodyellow": "fafad2", - "lightgrey": "d3d3d3", - "lightgreen": "90ee90", - "lightpink": "ffb6c1", - "lightsalmon": "ffa07a", - "lightseagreen": "20b2aa", - "lightskyblue": "87cefa", - "lightslategray": "778899", - "lightsteelblue": "b0c4de", - "lightyellow": "ffffe0", - "lime": "00ff00", - "limegreen": "32cd32", - "linen": "faf0e6", - "magenta": "ff00ff", - "maroon": "800000", - "mediumaquamarine": "66cdaa", - "mediumblue": "0000cd", - "mediumorchid": "ba55d3", - "mediumpurple": "9370d8", - "mediumseagreen": "3cb371", - "mediumslateblue": "7b68ee", - "mediumspringgreen": "00fa9a", - "mediumturquoise": "48d1cc", - "mediumvioletred": "c71585", - "midnightblue": "191970", - "mintcream": "f5fffa", - "mistyrose": "ffe4e1", - "moccasin": "ffe4b5", - "navajowhite": "ffdead", - "navy": "000080", - "oldlace": "fdf5e6", - "olive": "808000", - "olivedrab": "6b8e23", - "orange": "ffa500", - "orangered": "ff4500", - "orchid": "da70d6", - "palegoldenrod": "eee8aa", - "palegreen": "98fb98", - "paleturquoise": "afeeee", - "palevioletred": "d87093", - "papayawhip": "ffefd5", - "peachpuff": "ffdab9", - "peru": "cd853f", - "pink": "ffc0cb", - "plum": "dda0dd", - "powderblue": "b0e0e6", - "purple": "800080", - "red": "ff0000", - "rosybrown": "bc8f8f", - "royalblue": "4169e1", - "saddlebrown": "8b4513", - "salmon": "fa8072", - "sandybrown": "f4a460", - "seagreen": "2e8b57", - "seashell": "fff5ee", - "sienna": "a0522d", - "silver": "c0c0c0", - "skyblue": "87ceeb", - "slateblue": "6a5acd", - "slategray": "708090", - "snow": "fffafa", - "springgreen": "00ff7f", - "steelblue": "4682b4", - "tan": "d2b48c", - "teal": "008080", - "thistle": "d8bfd8", - "tomato": "ff6347", - "turquoise": "40e0d0", - "violet": "ee82ee", - "wheat": "f5deb3", - "white": "ffffff", - "whitesmoke": "f5f5f5", - "yellow": "ffff00", - "yellowgreen": "9acd32", - "transparent": "transparent" - }; - - Color.prototype = { - constructor: Color, - colors: {}, // merged web and predefined colors - predefinedColors: {}, - /** - * @return {Object} - */ - getValue: function() { - return this.value; - }, - /** - * @param {Object} val - */ - setValue: function(val) { - this.value = val; - }, - _sanitizeNumber: function(val) { - if (typeof val === 'number') { - return val; - } - if (isNaN(val) || (val === null) || (val === '') || (val === undefined)) { - return 1; - } - if (val === '') { - return 0; - } - if (typeof val.toLowerCase !== 'undefined') { - if (val.match(/^\./)) { - val = "0" + val; - } - return Math.ceil(parseFloat(val) * 100) / 100; - } - return 1; - }, - isTransparent: function(strVal) { - if (!strVal || !(typeof strVal === 'string' || strVal instanceof String)) { - return false; - } - strVal = strVal.toLowerCase().trim(); - return (strVal === 'transparent') || (strVal.match(/#?00000000/)) || (strVal.match(/(rgba|hsla)\(0,0,0,0?\.?0\)/)); - }, - rgbaIsTransparent: function(rgba) { - return ((rgba.r === 0) && (rgba.g === 0) && (rgba.b === 0) && (rgba.a === 0)); - }, - // parse a string to HSB - /** - * @protected - * @param {String} strVal - * @returns {boolean} Returns true if it could be parsed, false otherwise - */ - setColor: function(strVal) { - strVal = strVal.toLowerCase().trim(); - if (strVal) { - if (this.isTransparent(strVal)) { - this.value = { - h: 0, - s: 0, - b: 0, - a: 0 - }; - return true; - } else { - var parsedColor = this.parse(strVal); - if (parsedColor) { - this.value = this.value = { - h: parsedColor.h, - s: parsedColor.s, - b: parsedColor.b, - a: parsedColor.a - }; - if (!this.origFormat) { - this.origFormat = parsedColor.format; - } - } else if (this.fallbackValue) { - // if parser fails, defaults to fallbackValue if defined, otherwise the value won't be changed - this.value = this.fallbackValue; - } - } - } - return false; - }, - setHue: function(h) { - this.value.h = 1 - h; - }, - setSaturation: function(s) { - this.value.s = s; - }, - setBrightness: function(b) { - this.value.b = 1 - b; - }, - setAlpha: function(a) { - this.value.a = Math.round((parseInt((1 - a) * 100, 10) / 100) * 100) / 100; - }, - toRGB: function(h, s, b, a) { - if (arguments.length === 0) { - h = this.value.h; - s = this.value.s; - b = this.value.b; - a = this.value.a; - } - - h *= 360; - var R, G, B, X, C; - h = (h % 360) / 60; - C = b * s; - X = C * (1 - Math.abs(h % 2 - 1)); - R = G = B = b - C; - - h = ~~h; - R += [C, X, 0, 0, X, C][h]; - G += [X, C, C, X, 0, 0][h]; - B += [0, 0, X, C, C, X][h]; - - return { - r: Math.round(R * 255), - g: Math.round(G * 255), - b: Math.round(B * 255), - a: a - }; - }, - toHex: function(ignoreFormat, h, s, b, a) { - if (arguments.length <= 1) { - h = this.value.h; - s = this.value.s; - b = this.value.b; - a = this.value.a; - } - - var prefix = '#'; - var rgb = this.toRGB(h, s, b, a); - - if (this.rgbaIsTransparent(rgb)) { - return 'transparent'; - } - - if (!ignoreFormat) { - prefix = (this.hexNumberSignPrefix ? '#' : ''); - } - - var hexStr = prefix + ( - (1 << 24) + - (parseInt(rgb.r) << 16) + - (parseInt(rgb.g) << 8) + - parseInt(rgb.b)) - .toString(16) - .slice(1); - - return hexStr; - }, - toHSL: function(h, s, b, a) { - if (arguments.length === 0) { - h = this.value.h; - s = this.value.s; - b = this.value.b; - a = this.value.a; - } - - var H = h, - L = (2 - s) * b, - S = s * b; - if (L > 0 && L <= 1) { - S /= L; - } else { - S /= 2 - L; - } - L /= 2; - if (S > 1) { - S = 1; - } - return { - h: isNaN(H) ? 0 : H, - s: isNaN(S) ? 0 : S, - l: isNaN(L) ? 0 : L, - a: isNaN(a) ? 0 : a - }; - }, - toAlias: function(r, g, b, a) { - var c, rgb = (arguments.length === 0) ? this.toHex(true) : this.toHex(true, r, g, b, a); - - // support predef. colors in non-hex format too, as defined in the alias itself - var original = this.origFormat === 'alias' ? rgb : this.toString(false, this.origFormat); - - for (var alias in this.colors) { - c = this.colors[alias].toLowerCase().trim(); - if ((c === rgb) || (c === original)) { - return alias; - } - } - return false; - }, - RGBtoHSB: function(r, g, b, a) { - r /= 255; - g /= 255; - b /= 255; - - var H, S, V, C; - V = Math.max(r, g, b); - C = V - Math.min(r, g, b); - H = (C === 0 ? null : - V === r ? (g - b) / C : - V === g ? (b - r) / C + 2 : - (r - g) / C + 4 - ); - H = ((H + 360) % 6) * 60 / 360; - S = C === 0 ? 0 : C / V; - return { - h: this._sanitizeNumber(H), - s: S, - b: V, - a: this._sanitizeNumber(a) - }; - }, - HueToRGB: function(p, q, h) { - if (h < 0) { - h += 1; - } else if (h > 1) { - h -= 1; - } - if ((h * 6) < 1) { - return p + (q - p) * h * 6; - } else if ((h * 2) < 1) { - return q; - } else if ((h * 3) < 2) { - return p + (q - p) * ((2 / 3) - h) * 6; - } else { - return p; - } - }, - HSLtoRGB: function(h, s, l, a) { - if (s < 0) { - s = 0; - } - var q; - if (l <= 0.5) { - q = l * (1 + s); - } else { - q = l + s - (l * s); - } - - var p = 2 * l - q; - - var tr = h + (1 / 3); - var tg = h; - var tb = h - (1 / 3); - - var r = Math.round(this.HueToRGB(p, q, tr) * 255); - var g = Math.round(this.HueToRGB(p, q, tg) * 255); - var b = Math.round(this.HueToRGB(p, q, tb) * 255); - return [r, g, b, this._sanitizeNumber(a)]; - }, - /** - * @param {String} strVal - * @returns {Object} Object containing h,s,b,a,format properties or FALSE if failed to parse - */ - parse: function(strVal) { - if (typeof strVal !== 'string') { - return this.fallbackValue; - } - if (arguments.length === 0) { - return false; - } - - var that = this, - result = false, - isAlias = (typeof this.colors[strVal] !== 'undefined'), - values, format; - - if (isAlias) { - strVal = this.colors[strVal].toLowerCase().trim(); - } - - $.each(this.stringParsers, function(i, parser) { - var match = parser.re.exec(strVal); - values = match && parser.parse.apply(that, [match]); - if (values) { - result = {}; - format = (isAlias ? 'alias' : (parser.format ? parser.format : that.getValidFallbackFormat())); - if (format.match(/hsla?/)) { - result = that.RGBtoHSB.apply(that, that.HSLtoRGB.apply(that, values)); - } else { - result = that.RGBtoHSB.apply(that, values); - } - if (result instanceof Object) { - result.format = format; - } - return false; // stop iterating - } - return true; - }); - return result; - }, - getValidFallbackFormat: function() { - var formats = [ - 'rgba', 'rgb', 'hex', 'hsla', 'hsl' - ]; - if (this.origFormat && (formats.indexOf(this.origFormat) !== -1)) { - return this.origFormat; - } - if (this.fallbackFormat && (formats.indexOf(this.fallbackFormat) !== -1)) { - return this.fallbackFormat; - } - - return 'rgba'; // By default, return a format that will not lose the alpha info - }, - /** - * - * @param {string} [format] (default: rgba) - * @param {boolean} [translateAlias] Return real color for pre-defined (non-standard) aliases (default: false) - * @param {boolean} [forceRawValue] Forces hashtag prefix when getting hex color (default: false) - * @returns {String} - */ - toString: function(forceRawValue, format, translateAlias) { - format = format || this.origFormat || this.fallbackFormat; - translateAlias = translateAlias || false; - - var c = false; - - switch (format) { - case 'rgb': - { - c = this.toRGB(); - if (this.rgbaIsTransparent(c)) { - return 'transparent'; - } - return 'rgb(' + c.r + ',' + c.g + ',' + c.b + ')'; - } - break; - case 'rgba': - { - c = this.toRGB(); - return 'rgba(' + c.r + ',' + c.g + ',' + c.b + ',' + c.a + ')'; - } - break; - case 'hsl': - { - c = this.toHSL(); - return 'hsl(' + Math.round(c.h * 360) + ',' + Math.round(c.s * 100) + '%,' + Math.round(c.l * 100) + '%)'; - } - break; - case 'hsla': - { - c = this.toHSL(); - return 'hsla(' + Math.round(c.h * 360) + ',' + Math.round(c.s * 100) + '%,' + Math.round(c.l * 100) + '%,' + c.a + ')'; - } - break; - case 'hex': - { - return this.toHex(forceRawValue); - } - break; - case 'alias': - { - c = this.toAlias(); - - if (c === false) { - return this.toString(forceRawValue, this.getValidFallbackFormat()); - } - - if (translateAlias && !(c in Color.webColors) && (c in this.predefinedColors)) { - return this.predefinedColors[c]; - } - - return c; - } - default: - { - return c; - } - break; - } - }, - // a set of RE's that can match strings and generate color tuples. - // from John Resig color plugin - // https://github.com/jquery/jquery-color/ - stringParsers: [{ - re: /rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*?\)/, - format: 'rgb', - parse: function(execResult) { - return [ - execResult[1], - execResult[2], - execResult[3], - 1 - ]; - } - }, { - re: /rgb\(\s*(\d*(?:\.\d+)?)\%\s*,\s*(\d*(?:\.\d+)?)\%\s*,\s*(\d*(?:\.\d+)?)\%\s*?\)/, - format: 'rgb', - parse: function(execResult) { - return [ - 2.55 * execResult[1], - 2.55 * execResult[2], - 2.55 * execResult[3], - 1 - ]; - } - }, { - re: /rgba\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d*(?:\.\d+)?)\s*)?\)/, - format: 'rgba', - parse: function(execResult) { - return [ - execResult[1], - execResult[2], - execResult[3], - execResult[4] - ]; - } - }, { - re: /rgba\(\s*(\d*(?:\.\d+)?)\%\s*,\s*(\d*(?:\.\d+)?)\%\s*,\s*(\d*(?:\.\d+)?)\%\s*(?:,\s*(\d*(?:\.\d+)?)\s*)?\)/, - format: 'rgba', - parse: function(execResult) { - return [ - 2.55 * execResult[1], - 2.55 * execResult[2], - 2.55 * execResult[3], - execResult[4] - ]; - } - }, { - re: /hsl\(\s*(\d*(?:\.\d+)?)\s*,\s*(\d*(?:\.\d+)?)\%\s*,\s*(\d*(?:\.\d+)?)\%\s*?\)/, - format: 'hsl', - parse: function(execResult) { - return [ - execResult[1] / 360, - execResult[2] / 100, - execResult[3] / 100, - execResult[4] - ]; - } - }, { - re: /hsla\(\s*(\d*(?:\.\d+)?)\s*,\s*(\d*(?:\.\d+)?)\%\s*,\s*(\d*(?:\.\d+)?)\%\s*(?:,\s*(\d*(?:\.\d+)?)\s*)?\)/, - format: 'hsla', - parse: function(execResult) { - return [ - execResult[1] / 360, - execResult[2] / 100, - execResult[3] / 100, - execResult[4] - ]; - } - }, { - re: /#?([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/, - format: 'hex', - parse: function(execResult) { - return [ - parseInt(execResult[1], 16), - parseInt(execResult[2], 16), - parseInt(execResult[3], 16), - 1 - ]; - } - }, { - re: /#?([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/, - format: 'hex', - parse: function(execResult) { - return [ - parseInt(execResult[1] + execResult[1], 16), - parseInt(execResult[2] + execResult[2], 16), - parseInt(execResult[3] + execResult[3], 16), - 1 - ]; - } - }], - colorNameToHex: function(name) { - if (typeof this.colors[name.toLowerCase()] !== 'undefined') { - return this.colors[name.toLowerCase()]; - } - return false; - } - }; - - /* - * Default plugin options - */ - var defaults = { - horizontal: false, // horizontal mode layout ? - inline: false, //forces to show the colorpicker as an inline element - color: false, //forces a color - format: false, //forces a format - input: 'input', // children input selector - container: false, // container selector - component: '.add-on, .input-group-addon', // children component selector - fallbackColor: false, // fallback color value. null = keeps current color. - fallbackFormat: 'hex', // fallback color format - hexNumberSignPrefix: true, // put a '#' (number sign) before hex strings - sliders: { - saturation: { - maxLeft: 100, - maxTop: 100, - callLeft: 'setSaturation', - callTop: 'setBrightness' - }, - hue: { - maxLeft: 0, - maxTop: 100, - callLeft: false, - callTop: 'setHue' - }, - alpha: { - maxLeft: 0, - maxTop: 100, - callLeft: false, - callTop: 'setAlpha' - } - }, - slidersHorz: { - saturation: { - maxLeft: 100, - maxTop: 100, - callLeft: 'setSaturation', - callTop: 'setBrightness' - }, - hue: { - maxLeft: 100, - maxTop: 0, - callLeft: 'setHue', - callTop: false - }, - alpha: { - maxLeft: 100, - maxTop: 0, - callLeft: 'setAlpha', - callTop: false - } - }, - template: '