From 222f3be65cb513a9192673b342d67d7b248d8987 Mon Sep 17 00:00:00 2001 From: superod Date: Tue, 25 Jun 2024 15:47:07 +0800 Subject: [PATCH] =?UTF-8?q?chore:=20=E6=81=A2=E5=A4=8D=E5=8E=9F=E6=9C=89?= =?UTF-8?q?=E7=9A=84=20laravel-admin?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- admin-db.sql | 252 + app/Admin/Controllers/CommentController.php | 113 + app/Admin/Controllers/NoticeController.php | 52 + app/Admin/Controllers/PostController.php | 113 + app/Admin/Controllers/SystemController.php | 25 + app/Admin/Controllers/ThumbController.php | 85 + app/Admin/Controllers/UserController.php | 132 + .../Controllers/UserReportController.php | 99 + app/Admin/Forms/System/AboutForm.php | 58 + app/Admin/Forms/System/MarqueeForm.php | 61 + app/Admin/Forms/System/RegulationForm.php | 56 + .../WechatSubscribeNoticeConfigForm.php | 72 + app/Admin/routes.php | 10 +- .../simditor-2.3.28/scripts/dompurify.js | 1017 +++ .../simditor-2.3.28/scripts/hotkeys.js | 241 + .../simditor-2.3.28/scripts/module.js | 172 + .../simditor-2.3.28/scripts/simditor.js | 5698 +++++++++++++++++ .../simditor-2.3.28/scripts/uploader.js | 261 + .../simditor-2.3.28/styles/customized.css | 11 + .../simditor-2.3.28/styles/simditor.css | 749 +++ 20 files changed, 9276 insertions(+), 1 deletion(-) create mode 100644 admin-db.sql create mode 100644 app/Admin/Controllers/CommentController.php create mode 100644 app/Admin/Controllers/NoticeController.php create mode 100644 app/Admin/Controllers/PostController.php create mode 100644 app/Admin/Controllers/SystemController.php create mode 100644 app/Admin/Controllers/ThumbController.php create mode 100644 app/Admin/Controllers/UserController.php create mode 100644 app/Admin/Controllers/UserReportController.php create mode 100644 app/Admin/Forms/System/AboutForm.php create mode 100644 app/Admin/Forms/System/MarqueeForm.php create mode 100644 app/Admin/Forms/System/RegulationForm.php create mode 100644 app/Admin/Forms/System/WechatSubscribeNoticeConfigForm.php create mode 100644 public/vendor/laravel-admin-ext/simditor/simditor-2.3.28/scripts/dompurify.js create mode 100644 public/vendor/laravel-admin-ext/simditor/simditor-2.3.28/scripts/hotkeys.js create mode 100644 public/vendor/laravel-admin-ext/simditor/simditor-2.3.28/scripts/module.js create mode 100644 public/vendor/laravel-admin-ext/simditor/simditor-2.3.28/scripts/simditor.js create mode 100644 public/vendor/laravel-admin-ext/simditor/simditor-2.3.28/scripts/uploader.js create mode 100644 public/vendor/laravel-admin-ext/simditor/simditor-2.3.28/styles/customized.css create mode 100644 public/vendor/laravel-admin-ext/simditor/simditor-2.3.28/styles/simditor.css diff --git a/admin-db.sql b/admin-db.sql new file mode 100644 index 00000000..a9ecd170 --- /dev/null +++ b/admin-db.sql @@ -0,0 +1,252 @@ +-- MySQL dump 10.13 Distrib 8.0.23, for Linux (x86_64) +-- +-- Host: localhost Database: dev_heycommunity +-- ------------------------------------------------------ +-- Server version 8.0.23-0ubuntu0.20.04.1 + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!50503 SET NAMES utf8mb4 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +-- +-- Table structure for table `admin_menu` +-- + +DROP TABLE IF EXISTS `admin_menu`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `admin_menu` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `parent_id` int NOT NULL DEFAULT '0', + `order` int NOT NULL DEFAULT '0', + `title` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `icon` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `uri` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `permission` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `created_at` timestamp NULL DEFAULT NULL, + `updated_at` timestamp NULL DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=18 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `admin_menu` +-- + +LOCK TABLES `admin_menu` WRITE; +/*!40000 ALTER TABLE `admin_menu` DISABLE KEYS */; +INSERT INTO `admin_menu` VALUES (1,2,17,'Dashboard','fa-bar-chart','/',NULL,NULL,'2021-07-09 16:19:35'),(2,0,11,'Admin','fa-tasks','',NULL,NULL,'2021-07-09 16:19:35'),(3,2,12,'Users','fa-users','auth/users',NULL,NULL,'2021-07-09 16:19:35'),(4,2,13,'Roles','fa-user','auth/roles',NULL,NULL,'2021-07-09 16:19:35'),(5,2,14,'Permission','fa-ban','auth/permissions',NULL,NULL,'2021-07-09 16:19:35'),(6,2,15,'Menu','fa-bars','auth/menu',NULL,NULL,'2021-07-09 16:19:35'),(7,2,16,'Operation log','fa-history','auth/logs',NULL,NULL,'2021-07-09 16:19:35'),(8,0,1,'用户管理','fa-users','/users',NULL,'2021-04-15 06:48:03','2021-04-15 06:48:09'),(9,0,2,'动态管理','fa-rss','/posts',NULL,'2021-04-15 06:49:03','2021-04-15 06:49:09'),(10,0,7,'系统配置','fa-cog','/system',NULL,'2021-04-27 08:41:53','2021-07-09 16:19:35'),(11,15,10,'TeleScope','fa-bug','/telescope',NULL,'2021-05-10 04:54:37','2021-07-09 16:19:35'),(12,0,4,'评论管理','fa-comments','/comments',NULL,'2021-05-10 04:55:15','2021-07-09 16:16:51'),(13,0,5,'通知管理','fa-pied-piper-alt','/notices',NULL,'2021-05-10 04:58:14','2021-07-09 16:16:51'),(14,15,9,'Logs','fa-file-text-o','/logs',NULL,'2021-05-14 05:01:22','2021-07-09 16:19:35'),(15,0,8,'运维管理','fa-ship',NULL,NULL,'2021-05-14 06:09:03','2021-07-09 16:19:35'),(16,0,3,'点赞管理','fa-thumbs-up','thumbs',NULL,'2021-07-09 16:16:19','2021-07-09 16:16:51'),(17,0,6,'用户报告','fa-bug','user-reports',NULL,'2021-07-09 16:19:29','2021-07-09 16:19:35'); +/*!40000 ALTER TABLE `admin_menu` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `admin_users` +-- + +DROP TABLE IF EXISTS `admin_users`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `admin_users` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `username` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `password` varchar(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `avatar` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `remember_token` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `created_at` timestamp NULL DEFAULT NULL, + `updated_at` timestamp NULL DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `admin_users_username_unique` (`username`) +) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `admin_users` +-- + +LOCK TABLES `admin_users` WRITE; +/*!40000 ALTER TABLE `admin_users` DISABLE KEYS */; +INSERT INTO `admin_users` VALUES (1,'admin','$2y$10$y0VCGI4wh0OwmDgYfcQ3JO23vWmv4bSn66Xj23h//ftJKLPyXhn36','Administrator','','JYCAsugaZNgFWIG87YJEsVQOK7hvp1NZUuy6nkd2uhAPJiCBWpyqn5RJluqF','2021-04-15 06:47:26','2021-05-14 05:02:59'); +/*!40000 ALTER TABLE `admin_users` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `admin_permissions` +-- + +DROP TABLE IF EXISTS `admin_permissions`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `admin_permissions` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `slug` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `http_method` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `http_path` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `created_at` timestamp NULL DEFAULT NULL, + `updated_at` timestamp NULL DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `admin_permissions_name_unique` (`name`), + UNIQUE KEY `admin_permissions_slug_unique` (`slug`) +) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `admin_permissions` +-- + +LOCK TABLES `admin_permissions` WRITE; +/*!40000 ALTER TABLE `admin_permissions` DISABLE KEYS */; +INSERT INTO `admin_permissions` VALUES (1,'All permission','*','','*',NULL,NULL),(2,'Dashboard','dashboard','GET','/',NULL,NULL),(3,'Login','auth.login','','/auth/login\r\n/auth/logout',NULL,NULL),(4,'User setting','auth.setting','GET,PUT','/auth/setting',NULL,NULL),(5,'Auth management','auth.management','','/auth/roles\r\n/auth/permissions\r\n/auth/menu\r\n/auth/logs',NULL,NULL); +/*!40000 ALTER TABLE `admin_permissions` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `admin_roles` +-- + +DROP TABLE IF EXISTS `admin_roles`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `admin_roles` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `slug` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `created_at` timestamp NULL DEFAULT NULL, + `updated_at` timestamp NULL DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `admin_roles_name_unique` (`name`), + UNIQUE KEY `admin_roles_slug_unique` (`slug`) +) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `admin_roles` +-- + +LOCK TABLES `admin_roles` WRITE; +/*!40000 ALTER TABLE `admin_roles` DISABLE KEYS */; +INSERT INTO `admin_roles` VALUES (1,'Administrator','administrator','2021-04-15 06:47:26','2021-04-15 06:47:26'); +/*!40000 ALTER TABLE `admin_roles` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `admin_role_menu` +-- + +DROP TABLE IF EXISTS `admin_role_menu`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `admin_role_menu` ( + `role_id` int NOT NULL, + `menu_id` int NOT NULL, + `created_at` timestamp NULL DEFAULT NULL, + `updated_at` timestamp NULL DEFAULT NULL, + KEY `admin_role_menu_role_id_menu_id_index` (`role_id`,`menu_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `admin_role_menu` +-- + +LOCK TABLES `admin_role_menu` WRITE; +/*!40000 ALTER TABLE `admin_role_menu` DISABLE KEYS */; +INSERT INTO `admin_role_menu` VALUES (1,2,NULL,NULL); +/*!40000 ALTER TABLE `admin_role_menu` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `admin_role_permissions` +-- + +DROP TABLE IF EXISTS `admin_role_permissions`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `admin_role_permissions` ( + `role_id` int NOT NULL, + `permission_id` int NOT NULL, + `created_at` timestamp NULL DEFAULT NULL, + `updated_at` timestamp NULL DEFAULT NULL, + KEY `admin_role_permissions_role_id_permission_id_index` (`role_id`,`permission_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `admin_role_permissions` +-- + +LOCK TABLES `admin_role_permissions` WRITE; +/*!40000 ALTER TABLE `admin_role_permissions` DISABLE KEYS */; +INSERT INTO `admin_role_permissions` VALUES (1,1,NULL,NULL); +/*!40000 ALTER TABLE `admin_role_permissions` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `admin_role_users` +-- + +DROP TABLE IF EXISTS `admin_role_users`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `admin_role_users` ( + `role_id` int NOT NULL, + `user_id` int NOT NULL, + `created_at` timestamp NULL DEFAULT NULL, + `updated_at` timestamp NULL DEFAULT NULL, + KEY `admin_role_users_role_id_user_id_index` (`role_id`,`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `admin_role_users` +-- + +LOCK TABLES `admin_role_users` WRITE; +/*!40000 ALTER TABLE `admin_role_users` DISABLE KEYS */; +INSERT INTO `admin_role_users` VALUES (1,1,NULL,NULL); +/*!40000 ALTER TABLE `admin_role_users` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `admin_user_permissions` +-- + +DROP TABLE IF EXISTS `admin_user_permissions`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `admin_user_permissions` ( + `user_id` int NOT NULL, + `permission_id` int NOT NULL, + `created_at` timestamp NULL DEFAULT NULL, + `updated_at` timestamp NULL DEFAULT NULL, + KEY `admin_user_permissions_user_id_permission_id_index` (`user_id`,`permission_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `admin_user_permissions` +-- + +LOCK TABLES `admin_user_permissions` WRITE; +/*!40000 ALTER TABLE `admin_user_permissions` DISABLE KEYS */; +/*!40000 ALTER TABLE `admin_user_permissions` ENABLE KEYS */; +UNLOCK TABLES; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + +-- Dump completed on 2021-07-10 0:38:01 diff --git a/app/Admin/Controllers/CommentController.php b/app/Admin/Controllers/CommentController.php new file mode 100644 index 00000000..85c5a565 --- /dev/null +++ b/app/Admin/Controllers/CommentController.php @@ -0,0 +1,113 @@ +model()->latest(); + + $grid->column('id', 'ID'); + $grid->column('status', '状态')->select(Comment::$statuses); + $grid->column('user.nickname', '发布者'); + $grid->column('content', '内容'); + $grid->column('entity_text', '目标实体')->display(function () { + return $this->getEntityTextForAdmin(); + }); + + $grid->column('thumb_up_num', '点赞数'); + $grid->column('comment_num', '评论数'); + + $grid->column('created_at', '创建时间'); + + $grid->disableCreateButton(); + + $grid->actions(function ($actions) { + $actions->disableEdit(); + $actions->disableView(); + }); + + $grid->filter(function($filter){ + $filter->equal('status', '状态')->select(Comment::$statuses); + $filter->like('user.nickname', '作者'); + $filter->like('content', '内容'); + }); + + return $grid; + } + + /** + * Make a show builder. + * + * @param mixed $id + * @return Show + */ + protected function detail($id) + { + $show = new Show(Comment::findOrFail($id)); + + $show->field('id', 'Id'); + $show->field('root_id', 'Root id'); + $show->field('parent_id', 'Parent id'); + $show->field('floor_number', 'Floor number'); + $show->field('user_id', 'User id'); + $show->field('entity_class', 'Entity type'); + $show->field('entity_id', 'Entity id'); + $show->field('content', 'Content'); + $show->field('thumb_up_num', 'Thumb up num'); + $show->field('thumb_down_num', 'Thumb down num'); + $show->field('comment_num', 'Comment num'); + $show->field('status', 'Status'); + $show->field('created_at', 'Created at'); + $show->field('updated_at', 'Updated at'); + $show->field('deleted_at', 'Deleted at'); + + return $show; + } + + /** + * Make a form builder. + * + * @return Form + */ + protected function form() + { + $form = new Form(new Comment()); + + $form->number('root_id', 'Root id'); + $form->number('parent_id', 'Parent id'); + $form->number('floor_number', 'Floor number'); + $form->number('user_id', 'User id'); + $form->text('entity_class', 'Entity type'); + $form->number('entity_id', 'Entity id'); + $form->textarea('content', 'Content'); + $form->number('thumb_up_num', 'Thumb up num'); + $form->number('thumb_down_num', 'Thumb down num'); + $form->number('comment_num', 'Comment num'); + $form->switch('status', 'Status'); + + return $form; + } +} diff --git a/app/Admin/Controllers/NoticeController.php b/app/Admin/Controllers/NoticeController.php new file mode 100644 index 00000000..45461df3 --- /dev/null +++ b/app/Admin/Controllers/NoticeController.php @@ -0,0 +1,52 @@ +model()->latest(); + + $grid->column('id', 'ID'); + $grid->column('user.nickname', '接收者'); + $grid->column('sender.nickname', '发送者'); + $grid->column('type', '类型')->using(Notice::$types); + $grid->column('entity_text', '实体')->display(function () { + return $this->getEntityTextForAdmin(); + }); + + $grid->column('read_at', '阅读时间')->default('-'); + + $grid->column('created_at', '创建时间'); + + $grid->disableCreateButton(); + + $grid->actions(function ($actions) { + $actions->disableEdit(); + $actions->disableView(); + }); + + return $grid; + } +} diff --git a/app/Admin/Controllers/PostController.php b/app/Admin/Controllers/PostController.php new file mode 100644 index 00000000..e887a019 --- /dev/null +++ b/app/Admin/Controllers/PostController.php @@ -0,0 +1,113 @@ +model()->latest(); + + $grid->column('id', 'ID')->sortable(); + $grid->column('status', '状态')->select(Post::$statuses); + $grid->column('user.nickname', '作者'); + $grid->column('content', '内容')->display(function ($value) { + return Str::limit($value, 20 * 2); + }); + $grid->column('comment_num', '评论数')->expand(function ($model) { + $comments = $model->comments()->take(10)->latest()->get()->map(function ($comment) { + $data = $comment->only('id', 'content', 'created_at'); + array_splice($data, 1, 0, ['user' => $comment->user->nickname]); + return $data; + }); + + return new Table(['ID', '作者', '内容', '发布时间'], $comments->toArray()); + }); + $grid->column('thumb_up_num', '点赞数'); + $grid->column('created_at', '发布时间'); + + $grid->disableCreateButton(); + + $grid->actions(function ($actions) { + $actions->disableEdit(); + $actions->disableView(); + }); + + $grid->filter(function($filter){ + $filter->equal('status', '状态')->select(Post::$statuses); + $filter->like('user.nickname', '作者'); + $filter->like('content', '内容'); + }); + + return $grid; + } + + /** + * Make a show builder. + * + * @param mixed $id + * @return Show + */ + protected function detail($id) + { + $show = new Show(Post::findOrFail($id)); + + $show->field('id', 'Id'); + $show->field('user_id', 'User id'); + $show->field('content', 'Content'); + $show->field('read_num', 'Read num'); + $show->field('favorite_num', 'Favorite num'); + $show->field('comment_num', 'Comment num'); + $show->field('thumb_up_num', 'Thumb up num'); + $show->field('thumb_down_num', 'Thumb down num'); + $show->field('status', 'Status'); + $show->field('created_at', 'Created at'); + $show->field('updated_at', 'Updated at'); + $show->field('deleted_at', 'Deleted at'); + + return $show; + } + + /** + * Make a form builder. + * + * @return Form + */ + protected function form() + { + $form = new Form(new Post()); + + $form->number('user_id', 'User id'); + $form->textarea('content', 'Content'); + $form->number('read_num', 'Read num'); + $form->number('favorite_num', 'Favorite num'); + $form->number('comment_num', 'Comment num'); + $form->number('thumb_up_num', 'Thumb up num'); + $form->number('thumb_down_num', 'Thumb down num'); + $form->switch('status', 'Status'); + + return $form; + } +} diff --git a/app/Admin/Controllers/SystemController.php b/app/Admin/Controllers/SystemController.php new file mode 100644 index 00000000..aaf9fea8 --- /dev/null +++ b/app/Admin/Controllers/SystemController.php @@ -0,0 +1,25 @@ +title('系统配置')->description('System Configs') + ->body(Tab::forms([ + 'about' => AboutForm::class, + 'regulation' => RegulationForm::class, + 'marquee' => MarqueeForm::class, + 'wechat_subscribe_notice' => WechatSubscribeNoticeConfigForm::class, + ])); + } +} diff --git a/app/Admin/Controllers/ThumbController.php b/app/Admin/Controllers/ThumbController.php new file mode 100644 index 00000000..3d86d86a --- /dev/null +++ b/app/Admin/Controllers/ThumbController.php @@ -0,0 +1,85 @@ +model()->latest(); + + $grid->column('id', 'Id'); + $grid->column('user.nickname', '点赞人'); + $grid->column('entity_text', '目标实体')->display(function () { + return $this->getEntityTextForAdmin(); + }); + $grid->column('created_at', '时间'); + + $grid->disableCreateButton(); + $grid->actions(function ($actions) { + $actions->disableDelete(); + $actions->disableEdit(); + $actions->disableView(); + }); + + return $grid; + } + + /** + * Make a show builder. + * + * @param mixed $id + * @return Show + */ + protected function detail($id) + { + $show = new Show(Thumb::findOrFail($id)); + + $show->field('id', 'Id'); + $show->field('user_id', 'User id'); + $show->field('entity_class', 'Entity class'); + $show->field('entity_id', 'Entity id'); + $show->field('type', 'Type'); + $show->field('created_at', 'Created at'); + $show->field('updated_at', 'Updated at'); + $show->field('deleted_at', 'Deleted at'); + + return $show; + } + + /** + * Make a form builder. + * + * @return Form + */ + protected function form() + { + $form = new Form(new Thumb()); + + $form->number('user_id', 'User id'); + $form->text('entity_class', 'Entity class'); + $form->number('entity_id', 'Entity id'); + $form->text('type', 'Type'); + + return $form; + } +} diff --git a/app/Admin/Controllers/UserController.php b/app/Admin/Controllers/UserController.php new file mode 100644 index 00000000..3153ab3c --- /dev/null +++ b/app/Admin/Controllers/UserController.php @@ -0,0 +1,132 @@ +model()->latest(); + + $grid->column('id', 'ID')->sortable(); + $grid->column('avatar', '头像')->image(null, 20, 20); + $grid->column('nickname', '昵称'); + $grid->column('gender', '性别')->using(User::$genders); + $grid->column('province_city', '省市')->display(function () { + if ($this->wx_user_info) return $this->wx_user_info['province'] . $this->wx_user_info['city']; + })->default('-'); + $grid->column('bio', '一句话简介')->hide(); + $grid->column('post_num', '动态数')->expand(function ($model) { + $posts = $model->posts()->latest()->get()->map(function ($post) { + return $post->only('id', 'content', 'created_at'); + }); + return new Table(['ID', '内容', '创建时间'], $posts->toArray()); + }); + $grid->column('thumb_up_num', '点赞数'); + $grid->column('comment_num', '评论数')->expand(function ($model) { + $posts = $model->postComments()->latest()->get()->map(function ($post) { + return $post->only('id', 'content', 'created_at'); + }); + + return new Table(['ID', '内容', '创建时间'], $posts->toArray()); + }); + $grid->column('last_active_at', '最后活跃时间')->sortable(); + $grid->column('created_at', '注册时间')->sortable(); + + $grid->disableCreateButton(); + + $grid->actions(function ($actions) { + $actions->disableDelete(); + $actions->disableEdit(); + $actions->disableView(); + }); + + $grid->filter(function($filter){ + $filter->like('nickname', '昵称'); + + $filter->scope('has_wx_user_info', '有微信资料')->whereNotNull('wx_user_info'); + $filter->scope('today_active', '今日活跃')->whereDate('last_active_at', date('Y-m-d')); + + }); + + return $grid; + } + + /** + * Make a show builder. + * + * @param mixed $id + * @return Show + */ + protected function detail($id) + { + $show = new Show(User::findOrFail($id)); + + $show->field('id', 'Id'); + $show->field('wx_open_id', 'Wx open id'); + $show->field('wx_union_id', 'Wx union id'); + $show->field('nickname', 'Nickname'); + $show->field('realname', 'Realname'); + $show->field('gender', 'Gender'); + $show->field('bio', 'Bio'); + $show->field('avatar', 'Avatar'); + $show->field('cover', 'Cover'); + $show->field('phone', 'Phone'); + $show->field('email', 'Email'); + $show->field('password', 'Password'); + $show->field('is_admin', 'Is admin'); + $show->field('remember_token', 'Remember token'); + $show->field('created_at', 'Created at'); + $show->field('updated_at', 'Updated at'); + $show->field('deleted_at', 'Deleted at'); + + return $show; + } + + /** + * Make a form builder. + * + * @return Form + */ + protected function form() + { + $form = new Form(new User()); + + $form->text('wx_open_id', 'Wx open id'); + $form->text('wx_union_id', 'Wx union id'); + $form->text('nickname', 'Nickname'); + $form->text('realname', 'Realname'); + $form->text('gender', 'Gender'); + $form->text('bio', 'Bio'); + $form->image('avatar', 'Avatar')->default('images/users/default-avatar.jpg'); + $form->image('cover', 'Cover')->default('images/users/default-cover.jpg'); + $form->mobile('phone', 'Phone'); + $form->email('email', 'Email'); + $form->password('password', 'Password'); + $form->switch('is_admin', 'Is admin'); + $form->text('remember_token', 'Remember token'); + + return $form; + } +} diff --git a/app/Admin/Controllers/UserReportController.php b/app/Admin/Controllers/UserReportController.php new file mode 100644 index 00000000..149179b0 --- /dev/null +++ b/app/Admin/Controllers/UserReportController.php @@ -0,0 +1,99 @@ +model()->latest(); + + $grid->column('id', 'ID'); + $grid->column('reporter_user_nickname', '报告人')->display(function () { + return $this->user ? $this->user->nickname : ''; + }); + $grid->column('creator_user_nickname', '发布人')->display(function () { + return $this->entity->user->nickname; + }); + $grid->column('entity_text', '目标实体')->display(function () { + return $this->getEntityTextForAdmin(); + }); + $grid->column('entity_content', '内容')->display(function () { + return $this->entity_content; + }); + $grid->column('created_at', '报告时间'); + + $grid->disableCreateButton(); + $grid->actions(function ($actions) { + $actions->disableDelete(); + $actions->disableEdit(); + $actions->disableView(); + }); + + return $grid; + } + + /** + * Make a show builder. + * + * @param mixed $id + * @return Show + */ + protected function detail($id) + { + $show = new Show(UserReport::findOrFail($id)); + + $show->field('id', 'Id'); + $show->field('user_id', 'User id'); + $show->field('entity_class', 'Entity class'); + $show->field('entity_id', 'Entity id'); + $show->field('type_id', 'Type id'); + $show->field('content', 'Content'); + $show->field('status', 'Status'); + $show->field('created_at', 'Created at'); + $show->field('updated_at', 'Updated at'); + $show->field('deleted_at', 'Deleted at'); + + return $show; + } + + /** + * Make a form builder. + * + * @return Form + */ + protected function form() + { + $form = new Form(new UserReport()); + + $form->number('user_id', 'User id'); + $form->text('entity_class', 'Entity class'); + $form->number('entity_id', 'Entity id'); + $form->switch('type_id', 'Type id'); + $form->text('content', 'Content'); + $form->switch('status', 'Status'); + + return $form; + } +} diff --git a/app/Admin/Forms/System/AboutForm.php b/app/Admin/Forms/System/AboutForm.php new file mode 100644 index 00000000..78ee1019 --- /dev/null +++ b/app/Admin/Forms/System/AboutForm.php @@ -0,0 +1,58 @@ +all() as $key => $value) { + updateSettingColumn($key, $value); + } + + admin_success('操作成功'); + + return back(); + } + + /** + * Build a form here. + */ + public function form() + { + $this->text('wxapp_about_title', '标题')->rules('required|string'); + $this->text('wxapp_about_subtitle', '子标题')->rules('required|string'); + $this->simditor('wxapp_about_content', '内容')->rules('required|string'); + } + + /** + * The data of the form. + * + * @return array $data + */ + public function data() + { + return [ + 'wxapp_about_title' => getSettingValueByKey('wxapp_about_title', 'HEY社区'), + 'wxapp_about_subtitle' => getSettingValueByKey('wxapp_about_subtitle', 'HeyCommunity'), + 'wxapp_about_content' => getSettingValueByKey('wxapp_about_content', '欢迎使用HEY社区'), + ]; + } +} diff --git a/app/Admin/Forms/System/MarqueeForm.php b/app/Admin/Forms/System/MarqueeForm.php new file mode 100644 index 00000000..44c31adc --- /dev/null +++ b/app/Admin/Forms/System/MarqueeForm.php @@ -0,0 +1,61 @@ +all() as $key => $value) { + updateSettingColumn($key, $value); + } + + admin_success('操作成功'); + + return back(); + } + + /** + * Build a form here. + */ + public function form() + { + $this->select('wxapp_index_page_marquee_enable', '是否启用')->options([0 => '关闭', 1 => '开启']); + $this->text('wxapp_index_page_marquee_text', '显示内容') + ->rules('required_if:wxapp_index_page_marquee_enable,1', ['required_if' => '启用跑马灯时,此字段不能为空']); + $this->text('wxapp_index_page_marquee_url', '小程序页面链接') + ->rules('required_if:wxapp_index_page_marquee_enable,1', ['required_if' => '启用跑马灯时,此字段不能为空']); + } + + /** + * The data of the form. + * + * @return array $data + */ + public function data() + { + return [ + 'wxapp_index_page_marquee_enable' => getSettingValueByKey('wxapp_index_page_marquee_enable', 0), + 'wxapp_index_page_marquee_text' => getSettingValueByKey('wxapp_index_page_marquee_text', ''), + 'wxapp_index_page_marquee_url' => getSettingValueByKey('wxapp_index_page_marquee_url', ''), + ]; + } +} diff --git a/app/Admin/Forms/System/RegulationForm.php b/app/Admin/Forms/System/RegulationForm.php new file mode 100644 index 00000000..cd8b74ef --- /dev/null +++ b/app/Admin/Forms/System/RegulationForm.php @@ -0,0 +1,56 @@ +all() as $key => $value) { + updateSettingColumn($key, $value); + } + + admin_success('操作成功'); + + return back(); + } + + /** + * Build a form here. + */ + public function form() + { + $this->text('wxapp_regulation_title', '标题')->rules('required|string'); + $this->simditor('wxapp_regulation_content', '内容')->rules('required|string'); + } + + /** + * The data of the form. + * + * @return array $data + */ + public function data() + { + return [ + 'wxapp_regulation_title' => getSettingValueByKey('wxapp_regulation_title', '社区准则'), + 'wxapp_regulation_content' => getSettingValueByKey('wxapp_regulation_content', ''), + ]; + } +} diff --git a/app/Admin/Forms/System/WechatSubscribeNoticeConfigForm.php b/app/Admin/Forms/System/WechatSubscribeNoticeConfigForm.php new file mode 100644 index 00000000..ef525295 --- /dev/null +++ b/app/Admin/Forms/System/WechatSubscribeNoticeConfigForm.php @@ -0,0 +1,72 @@ +validate($request, [ + 'wxapp_subscribe_message_enable' => 'required|boolean', + 'wxapp_subscribe_message_thumb_up_temp_id' => 'nullable|string', + 'wxapp_subscribe_message_comment_temp_id' => 'nullable|string', + 'wxapp_subscribe_message_reply_temp_id' => 'nullable|string', + ]); + + systemUpdateEnvironmentValue([ + 'WXAPP_SUBSCRIBE_MESSAGE_ENABLE' => $request->get('wxapp_subscribe_message_enable') ? 'true' : 'false', + 'WXAPP_SUBSCRIBE_MESSAGE_THUMB_UP_TEMP_ID' => $request->get('wxapp_subscribe_message_thumb_up_temp_id'), + 'WXAPP_SUBSCRIBE_MESSAGE_COMMENT_TEMP_ID' => $request->get('wxapp_subscribe_message_comment_temp_id'), + 'WXAPP_SUBSCRIBE_MESSAGE_REPLY_TEMP_ID' => $request->get('wxapp_subscribe_message_reply_temp_id'), + ]); + + admin_success('操作成功'); + + return back(); + } + + /** + * Build a form here. + */ + public function form() + { + $this->select('wxapp_subscribe_message_enable', '微信订阅消息') + ->options([0 => '关闭', 1 => '开启'])->default(0) + ->help("如开启,系统中的点赞、评论、回复等通知,将通过微信小程序一次性订阅消息发送给用户。
开启后请配置下方模板 ID"); // TODO: 补充模板说明 + $this->text('wxapp_subscribe_message_thumb_up_temp_id', '点赞消息模板 ID'); + $this->text('wxapp_subscribe_message_comment_temp_id', '评论消息模板 ID'); + $this->text('wxapp_subscribe_message_reply_temp_id', '回复消息模板 ID'); + } + + /** + * The data of the form. + * + * @return array $data + */ + public function data() + { + return [ + 'wxapp_subscribe_message_enable' => config('system.wxapp.subscribe_message.enable'), + 'wxapp_subscribe_message_thumb_up_temp_id' => config('system.wxapp.subscribe_message.thumb_up_temp_id'), + 'wxapp_subscribe_message_comment_temp_id' => config('system.wxapp.subscribe_message.comment_temp_id'), + 'wxapp_subscribe_message_reply_temp_id' => config('system.wxapp.subscribe_message.reply_temp_id'), + ]; + } +} diff --git a/app/Admin/routes.php b/app/Admin/routes.php index 43d67b8e..6c2df9f4 100644 --- a/app/Admin/routes.php +++ b/app/Admin/routes.php @@ -10,8 +10,16 @@ 'middleware' => config('admin.route.middleware'), 'as' => config('admin.route.prefix') . '.', ], function (Router $router) { - $router->get('/', 'HomeController@index')->name('home'); + $router->resource('users', 'UserController'); + $router->resource('posts', 'PostController'); + $router->resource('comments', 'CommentController'); + $router->resource('thumbs', 'ThumbController'); + $router->resource('notices', 'NoticeController'); + $router->resource('user-reports', 'UserReportController'); + $router->resource('activities', 'ActivityController'); + + $router->get('system', 'SystemController@index')->name('admin.system'); }); diff --git a/public/vendor/laravel-admin-ext/simditor/simditor-2.3.28/scripts/dompurify.js b/public/vendor/laravel-admin-ext/simditor/simditor-2.3.28/scripts/dompurify.js new file mode 100644 index 00000000..aefaf03c --- /dev/null +++ b/public/vendor/laravel-admin-ext/simditor/simditor-2.3.28/scripts/dompurify.js @@ -0,0 +1,1017 @@ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global.DOMPurify = factory()); +}(this, (function () { 'use strict'; + +var html = ['a', 'abbr', 'acronym', 'address', 'area', 'article', 'aside', 'audio', 'b', 'bdi', 'bdo', 'big', 'blink', 'blockquote', 'body', 'br', 'button', 'canvas', 'caption', 'center', 'cite', 'code', 'col', 'colgroup', 'content', 'data', 'datalist', 'dd', 'decorator', 'del', 'details', 'dfn', 'dir', 'div', 'dl', 'dt', 'element', 'em', 'fieldset', 'figcaption', 'figure', 'font', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'header', 'hgroup', 'hr', 'html', 'i', 'img', 'input', 'ins', 'kbd', 'label', 'legend', 'li', 'main', 'map', 'mark', 'marquee', 'menu', 'menuitem', 'meter', 'nav', 'nobr', 'ol', 'optgroup', 'option', 'output', 'p', 'pre', 'progress', 'q', 'rp', 'rt', 'ruby', 's', 'samp', 'section', 'select', 'shadow', 'small', 'source', 'spacer', 'span', 'strike', 'strong', 'style', 'sub', 'summary', 'sup', 'table', 'tbody', 'td', 'template', 'textarea', 'tfoot', 'th', 'thead', 'time', 'tr', 'track', 'tt', 'u', 'ul', 'var', 'video', 'wbr']; + +// SVG +var svg = ['svg', 'a', 'altglyph', 'altglyphdef', 'altglyphitem', 'animatecolor', 'animatemotion', 'animatetransform', 'audio', 'canvas', 'circle', 'clippath', 'defs', 'desc', 'ellipse', 'filter', 'font', 'g', 'glyph', 'glyphref', 'hkern', 'image', 'line', 'lineargradient', 'marker', 'mask', 'metadata', 'mpath', 'path', 'pattern', 'polygon', 'polyline', 'radialgradient', 'rect', 'stop', 'style', 'switch', 'symbol', 'text', 'textpath', 'title', 'tref', 'tspan', 'video', 'view', 'vkern']; + +var svgFilters = ['feBlend', 'feColorMatrix', 'feComponentTransfer', 'feComposite', 'feConvolveMatrix', 'feDiffuseLighting', 'feDisplacementMap', 'feDistantLight', 'feFlood', 'feFuncA', 'feFuncB', 'feFuncG', 'feFuncR', 'feGaussianBlur', 'feMerge', 'feMergeNode', 'feMorphology', 'feOffset', 'fePointLight', 'feSpecularLighting', 'feSpotLight', 'feTile', 'feTurbulence']; + +var mathMl = ['math', 'menclose', 'merror', 'mfenced', 'mfrac', 'mglyph', 'mi', 'mlabeledtr', 'mmuliscripts', 'mn', 'mo', 'mover', 'mpadded', 'mphantom', 'mroot', 'mrow', 'ms', 'mpspace', 'msqrt', 'mystyle', 'msub', 'msup', 'msubsup', 'mtable', 'mtd', 'mtext', 'mtr', 'munder', 'munderover']; + +var text = ['#text']; + +var html$1 = ['accept', 'action', 'align', 'alt', 'autocomplete', 'background', 'bgcolor', 'border', 'cellpadding', 'cellspacing', 'checked', 'cite', 'class', 'clear', 'color', 'cols', 'colspan', 'coords', 'crossorigin', 'datetime', 'default', 'dir', 'disabled', 'download', 'enctype', 'face', 'for', 'headers', 'height', 'hidden', 'high', 'href', 'hreflang', 'id', 'integrity', 'ismap', 'label', 'lang', 'list', 'loop', 'low', 'max', 'maxlength', 'media', 'method', 'min', 'multiple', 'name', 'noshade', 'novalidate', 'nowrap', 'open', 'optimum', 'pattern', 'placeholder', 'poster', 'preload', 'pubdate', 'radiogroup', 'readonly', 'rel', 'required', 'rev', 'reversed', 'role', 'rows', 'rowspan', 'spellcheck', 'scope', 'selected', 'shape', 'size', 'sizes', 'span', 'srclang', 'start', 'src', 'srcset', 'step', 'style', 'summary', 'tabindex', 'title', 'type', 'usemap', 'valign', 'value', 'width', 'xmlns']; + +var svg$1 = ['accent-height', 'accumulate', 'additivive', 'alignment-baseline', 'ascent', 'attributename', 'attributetype', 'azimuth', 'basefrequency', 'baseline-shift', 'begin', 'bias', 'by', 'class', 'clip', 'clip-path', 'clip-rule', 'color', 'color-interpolation', 'color-interpolation-filters', 'color-profile', 'color-rendering', 'cx', 'cy', 'd', 'dx', 'dy', 'diffuseconstant', 'direction', 'display', 'divisor', 'dur', 'edgemode', 'elevation', 'end', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'flood-color', 'flood-opacity', 'font-family', 'font-size', 'font-size-adjust', 'font-stretch', 'font-style', 'font-variant', 'font-weight', 'fx', 'fy', 'g1', 'g2', 'glyph-name', 'glyphref', 'gradientunits', 'gradienttransform', 'height', 'href', 'id', 'image-rendering', 'in', 'in2', 'k', 'k1', 'k2', 'k3', 'k4', 'kerning', 'keypoints', 'keysplines', 'keytimes', 'lang', 'lengthadjust', 'letter-spacing', 'kernelmatrix', 'kernelunitlength', 'lighting-color', 'local', 'marker-end', 'marker-mid', 'marker-start', 'markerheight', 'markerunits', 'markerwidth', 'maskcontentunits', 'maskunits', 'max', 'mask', 'media', 'method', 'mode', 'min', 'name', 'numoctaves', 'offset', 'operator', 'opacity', 'order', 'orient', 'orientation', 'origin', 'overflow', 'paint-order', 'path', 'pathlength', 'patterncontentunits', 'patterntransform', 'patternunits', 'points', 'preservealpha', 'preserveaspectratio', 'r', 'rx', 'ry', 'radius', 'refx', 'refy', 'repeatcount', 'repeatdur', 'restart', 'result', 'rotate', 'scale', 'seed', 'shape-rendering', 'specularconstant', 'specularexponent', 'spreadmethod', 'stddeviation', 'stitchtiles', 'stop-color', 'stop-opacity', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke', 'stroke-width', 'style', 'surfacescale', 'tabindex', 'targetx', 'targety', 'transform', 'text-anchor', 'text-decoration', 'text-rendering', 'textlength', 'type', 'u1', 'u2', 'unicode', 'values', 'viewbox', 'visibility', 'vert-adv-y', 'vert-origin-x', 'vert-origin-y', 'width', 'word-spacing', 'wrap', 'writing-mode', 'xchannelselector', 'ychannelselector', 'x', 'x1', 'x2', 'xmlns', 'y', 'y1', 'y2', 'z', 'zoomandpan']; + +var mathMl$1 = ['accent', 'accentunder', 'align', 'bevelled', 'close', 'columnsalign', 'columnlines', 'columnspan', 'denomalign', 'depth', 'dir', 'display', 'displaystyle', 'fence', 'frame', 'height', 'href', 'id', 'largeop', 'length', 'linethickness', 'lspace', 'lquote', 'mathbackground', 'mathcolor', 'mathsize', 'mathvariant', 'maxsize', 'minsize', 'movablelimits', 'notation', 'numalign', 'open', 'rowalign', 'rowlines', 'rowspacing', 'rowspan', 'rspace', 'rquote', 'scriptlevel', 'scriptminsize', 'scriptsizemultiplier', 'selection', 'separator', 'separators', 'stretchy', 'subscriptshift', 'supscriptshift', 'symmetric', 'voffset', 'width', 'xmlns']; + +var xml = ['xlink:href', 'xml:id', 'xlink:title', 'xml:space', 'xmlns:xlink']; + +/* Add properties to a lookup table */ +function addToSet(set, array) { + var l = array.length; + while (l--) { + if (typeof array[l] === 'string') { + array[l] = array[l].toLowerCase(); + } + set[array[l]] = true; + } + return set; +} + +/* Shallow clone an object */ +function clone(object) { + var newObject = {}; + var property = void 0; + for (property in object) { + if (Object.prototype.hasOwnProperty.call(object, property)) { + newObject[property] = object[property]; + } + } + return newObject; +} + +var MUSTACHE_EXPR = /\{\{[\s\S]*|[\s\S]*\}\}/gm; // Specify template detection regex for SAFE_FOR_TEMPLATES mode +var ERB_EXPR = /<%[\s\S]*|[\s\S]*%>/gm; +var DATA_ATTR = /^data-[\-\w.\u00B7-\uFFFF]/; // eslint-disable-line no-useless-escape +var ARIA_ATTR = /^aria-[\-\w]+$/; // eslint-disable-line no-useless-escape +var IS_ALLOWED_URI = /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i; // eslint-disable-line no-useless-escape +var IS_SCRIPT_OR_DATA = /^(?:\w+script|data):/i; +var ATTR_WHITESPACE = /[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205f\u3000]/g; // eslint-disable-line no-control-regex + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } + +var getGlobal = function getGlobal() { + return typeof window === 'undefined' ? null : window; +}; + +function createDOMPurify() { + var window = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getGlobal(); + + var DOMPurify = function DOMPurify(root) { + return createDOMPurify(root); + }; + + /** + * Version label, exposed for easier checks + * if DOMPurify is up to date or not + */ + DOMPurify.version = '1.0.8'; + + /** + * Array of elements that DOMPurify removed during sanitation. + * Empty if nothing was removed. + */ + DOMPurify.removed = []; + + if (!window || !window.document || window.document.nodeType !== 9) { + // Not running in a browser, provide a factory function + // so that you can pass your own Window + DOMPurify.isSupported = false; + + return DOMPurify; + } + + var originalDocument = window.document; + var useDOMParser = false; // See comment below + var removeTitle = false; // See comment below + + var document = window.document; + var DocumentFragment = window.DocumentFragment, + HTMLTemplateElement = window.HTMLTemplateElement, + Node = window.Node, + NodeFilter = window.NodeFilter, + _window$NamedNodeMap = window.NamedNodeMap, + NamedNodeMap = _window$NamedNodeMap === undefined ? window.NamedNodeMap || window.MozNamedAttrMap : _window$NamedNodeMap, + Text = window.Text, + Comment = window.Comment, + DOMParser = window.DOMParser; + + // As per issue #47, the web-components registry is inherited by a + // new document created via createHTMLDocument. As per the spec + // (http://w3c.github.io/webcomponents/spec/custom/#creating-and-passing-registries) + // a new empty registry is used when creating a template contents owner + // document, so we use that as our parent document to ensure nothing + // is inherited. + + if (typeof HTMLTemplateElement === 'function') { + var template = document.createElement('template'); + if (template.content && template.content.ownerDocument) { + document = template.content.ownerDocument; + } + } + + var _document = document, + implementation = _document.implementation, + createNodeIterator = _document.createNodeIterator, + getElementsByTagName = _document.getElementsByTagName, + createDocumentFragment = _document.createDocumentFragment; + var importNode = originalDocument.importNode; + + + var hooks = {}; + + /** + * Expose whether this browser supports running the full DOMPurify. + */ + DOMPurify.isSupported = implementation && typeof implementation.createHTMLDocument !== 'undefined' && document.documentMode !== 9; + + var MUSTACHE_EXPR$$1 = MUSTACHE_EXPR, + ERB_EXPR$$1 = ERB_EXPR, + DATA_ATTR$$1 = DATA_ATTR, + ARIA_ATTR$$1 = ARIA_ATTR, + IS_SCRIPT_OR_DATA$$1 = IS_SCRIPT_OR_DATA, + ATTR_WHITESPACE$$1 = ATTR_WHITESPACE; + var IS_ALLOWED_URI$$1 = IS_ALLOWED_URI; + /** + * We consider the elements and attributes below to be safe. Ideally + * don't add any new ones but feel free to remove unwanted ones. + */ + + /* allowed element names */ + + var ALLOWED_TAGS = null; + var DEFAULT_ALLOWED_TAGS = addToSet({}, [].concat(_toConsumableArray(html), _toConsumableArray(svg), _toConsumableArray(svgFilters), _toConsumableArray(mathMl), _toConsumableArray(text))); + + /* Allowed attribute names */ + var ALLOWED_ATTR = null; + var DEFAULT_ALLOWED_ATTR = addToSet({}, [].concat(_toConsumableArray(html$1), _toConsumableArray(svg$1), _toConsumableArray(mathMl$1), _toConsumableArray(xml))); + + /* Explicitly forbidden tags (overrides ALLOWED_TAGS/ADD_TAGS) */ + var FORBID_TAGS = null; + + /* Explicitly forbidden attributes (overrides ALLOWED_ATTR/ADD_ATTR) */ + var FORBID_ATTR = null; + + /* Decide if ARIA attributes are okay */ + var ALLOW_ARIA_ATTR = true; + + /* Decide if custom data attributes are okay */ + var ALLOW_DATA_ATTR = true; + + /* Decide if unknown protocols are okay */ + var ALLOW_UNKNOWN_PROTOCOLS = false; + + /* Output should be safe for jQuery's $() factory? */ + var SAFE_FOR_JQUERY = false; + + /* Output should be safe for common template engines. + * This means, DOMPurify removes data attributes, mustaches and ERB + */ + var SAFE_FOR_TEMPLATES = false; + + /* Decide if document with ... should be returned */ + var WHOLE_DOCUMENT = false; + + /* Track whether config is already set on this instance of DOMPurify. */ + var SET_CONFIG = false; + + /* Decide if all elements (e.g. style, script) must be children of + * document.body. By default, browsers might move them to document.head */ + var FORCE_BODY = false; + + /* Decide if a DOM `HTMLBodyElement` should be returned, instead of a html string. + * If `WHOLE_DOCUMENT` is enabled a `HTMLHtmlElement` will be returned instead + */ + var RETURN_DOM = false; + + /* Decide if a DOM `DocumentFragment` should be returned, instead of a html string */ + var RETURN_DOM_FRAGMENT = false; + + /* If `RETURN_DOM` or `RETURN_DOM_FRAGMENT` is enabled, decide if the returned DOM + * `Node` is imported into the current `Document`. If this flag is not enabled the + * `Node` will belong (its ownerDocument) to a fresh `HTMLDocument`, created by + * DOMPurify. */ + var RETURN_DOM_IMPORT = false; + + /* Output should be free from DOM clobbering attacks? */ + var SANITIZE_DOM = true; + + /* Keep element content when removing element? */ + var KEEP_CONTENT = true; + + /* If a `Node` is passed to sanitize(), then performs sanitization in-place instead + * of importing it into a new Document and returning a sanitized copy */ + var IN_PLACE = false; + + /* Allow usage of profiles like html, svg and mathMl */ + var USE_PROFILES = {}; + + /* Tags to ignore content of when KEEP_CONTENT is true */ + var FORBID_CONTENTS = addToSet({}, ['audio', 'head', 'math', 'script', 'style', 'template', 'svg', 'video']); + + /* Tags that are safe for data: URIs */ + var DATA_URI_TAGS = addToSet({}, ['audio', 'video', 'img', 'source', 'image']); + + /* Attributes safe for values like "javascript:" */ + var URI_SAFE_ATTRIBUTES = addToSet({}, ['alt', 'class', 'for', 'id', 'label', 'name', 'pattern', 'placeholder', 'summary', 'title', 'value', 'style', 'xmlns']); + + /* Keep a reference to config to pass to hooks */ + var CONFIG = null; + + /* Ideally, do not touch anything below this line */ + /* ______________________________________________ */ + + var formElement = document.createElement('form'); + + /** + * _parseConfig + * + * @param {Object} cfg optional config literal + */ + // eslint-disable-next-line complexity + var _parseConfig = function _parseConfig(cfg) { + /* Shield configuration object from tampering */ + if ((typeof cfg === 'undefined' ? 'undefined' : _typeof(cfg)) !== 'object') { + cfg = {}; + } + /* Set configuration parameters */ + ALLOWED_TAGS = 'ALLOWED_TAGS' in cfg ? addToSet({}, cfg.ALLOWED_TAGS) : DEFAULT_ALLOWED_TAGS; + ALLOWED_ATTR = 'ALLOWED_ATTR' in cfg ? addToSet({}, cfg.ALLOWED_ATTR) : DEFAULT_ALLOWED_ATTR; + FORBID_TAGS = 'FORBID_TAGS' in cfg ? addToSet({}, cfg.FORBID_TAGS) : {}; + FORBID_ATTR = 'FORBID_ATTR' in cfg ? addToSet({}, cfg.FORBID_ATTR) : {}; + USE_PROFILES = 'USE_PROFILES' in cfg ? cfg.USE_PROFILES : false; + ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false; // Default true + ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false; // Default true + ALLOW_UNKNOWN_PROTOCOLS = cfg.ALLOW_UNKNOWN_PROTOCOLS || false; // Default false + SAFE_FOR_JQUERY = cfg.SAFE_FOR_JQUERY || false; // Default false + SAFE_FOR_TEMPLATES = cfg.SAFE_FOR_TEMPLATES || false; // Default false + WHOLE_DOCUMENT = cfg.WHOLE_DOCUMENT || false; // Default false + RETURN_DOM = cfg.RETURN_DOM || false; // Default false + RETURN_DOM_FRAGMENT = cfg.RETURN_DOM_FRAGMENT || false; // Default false + RETURN_DOM_IMPORT = cfg.RETURN_DOM_IMPORT || false; // Default false + FORCE_BODY = cfg.FORCE_BODY || false; // Default false + SANITIZE_DOM = cfg.SANITIZE_DOM !== false; // Default true + KEEP_CONTENT = cfg.KEEP_CONTENT !== false; // Default true + IN_PLACE = cfg.IN_PLACE || false; // Default false + + IS_ALLOWED_URI$$1 = cfg.ALLOWED_URI_REGEXP || IS_ALLOWED_URI$$1; + + if (SAFE_FOR_TEMPLATES) { + ALLOW_DATA_ATTR = false; + } + + if (RETURN_DOM_FRAGMENT) { + RETURN_DOM = true; + } + + /* Parse profile info */ + if (USE_PROFILES) { + ALLOWED_TAGS = addToSet({}, [].concat(_toConsumableArray(text))); + ALLOWED_ATTR = []; + if (USE_PROFILES.html === true) { + addToSet(ALLOWED_TAGS, html); + addToSet(ALLOWED_ATTR, html$1); + } + if (USE_PROFILES.svg === true) { + addToSet(ALLOWED_TAGS, svg); + addToSet(ALLOWED_ATTR, svg$1); + addToSet(ALLOWED_ATTR, xml); + } + if (USE_PROFILES.svgFilters === true) { + addToSet(ALLOWED_TAGS, svgFilters); + addToSet(ALLOWED_ATTR, svg$1); + addToSet(ALLOWED_ATTR, xml); + } + if (USE_PROFILES.mathMl === true) { + addToSet(ALLOWED_TAGS, mathMl); + addToSet(ALLOWED_ATTR, mathMl$1); + addToSet(ALLOWED_ATTR, xml); + } + } + + /* Merge configuration parameters */ + if (cfg.ADD_TAGS) { + if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) { + ALLOWED_TAGS = clone(ALLOWED_TAGS); + } + addToSet(ALLOWED_TAGS, cfg.ADD_TAGS); + } + if (cfg.ADD_ATTR) { + if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) { + ALLOWED_ATTR = clone(ALLOWED_ATTR); + } + addToSet(ALLOWED_ATTR, cfg.ADD_ATTR); + } + if (cfg.ADD_URI_SAFE_ATTR) { + addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR); + } + + /* Add #text in case KEEP_CONTENT is set to true */ + if (KEEP_CONTENT) { + ALLOWED_TAGS['#text'] = true; + } + + /* Add html, head and body to ALLOWED_TAGS in case WHOLE_DOCUMENT is true */ + if (WHOLE_DOCUMENT) { + addToSet(ALLOWED_TAGS, ['html', 'head', 'body']); + } + + /* Add tbody to ALLOWED_TAGS in case tables are permitted, see #286 */ + if (ALLOWED_TAGS.table) { + addToSet(ALLOWED_TAGS, ['tbody']); + } + + // Prevent further manipulation of configuration. + // Not available in IE8, Safari 5, etc. + if (Object && 'freeze' in Object) { + Object.freeze(cfg); + } + + CONFIG = cfg; + }; + + /** + * _forceRemove + * + * @param {Node} node a DOM node + */ + var _forceRemove = function _forceRemove(node) { + DOMPurify.removed.push({ element: node }); + try { + node.parentNode.removeChild(node); + } catch (err) { + node.outerHTML = ''; + } + }; + + /** + * _removeAttribute + * + * @param {String} name an Attribute name + * @param {Node} node a DOM node + */ + var _removeAttribute = function _removeAttribute(name, node) { + try { + DOMPurify.removed.push({ + attribute: node.getAttributeNode(name), + from: node + }); + } catch (err) { + DOMPurify.removed.push({ + attribute: null, + from: node + }); + } + node.removeAttribute(name); + }; + + /** + * _initDocument + * + * @param {String} dirty a string of dirty markup + * @return {Document} a DOM, filled with the dirty markup + */ + var _initDocument = function _initDocument(dirty) { + /* Create a HTML document */ + var doc = void 0; + + if (FORCE_BODY) { + dirty = '' + dirty; + } + + /* Use DOMParser to workaround Firefox bug (see comment below) */ + if (useDOMParser) { + try { + doc = new DOMParser().parseFromString(dirty, 'text/html'); + } catch (err) {} + } + + /* Remove title to fix an mXSS bug in older MS Edge */ + if (removeTitle) { + addToSet(FORBID_TAGS, ['title']); + } + + /* Otherwise use createHTMLDocument, because DOMParser is unsafe in + Safari (see comment below) */ + if (!doc || !doc.documentElement) { + doc = implementation.createHTMLDocument(''); + var _doc = doc, + body = _doc.body; + + body.parentNode.removeChild(body.parentNode.firstElementChild); + body.outerHTML = dirty; + } + + /* Work on whole document or just its body */ + return getElementsByTagName.call(doc, WHOLE_DOCUMENT ? 'html' : 'body')[0]; + }; + + // Firefox uses a different parser for innerHTML rather than + // DOMParser (see https://bugzilla.mozilla.org/show_bug.cgi?id=1205631) + // which means that you *must* use DOMParser, otherwise the output may + // not be safe if used in a document.write context later. + // + // So we feature detect the Firefox bug and use the DOMParser if necessary. + // + // MS Edge, in older versions, is affected by an mXSS behavior. The second + // check tests for the behavior and fixes it if necessary. + if (DOMPurify.isSupported) { + (function () { + try { + var doc = _initDocument('

'); + if (doc.querySelector('svg img')) { + useDOMParser = true; + } + } catch (err) {} + })(); + (function () { + try { + var doc = _initDocument('</title><img>'); + if (doc.querySelector('title').textContent.match(/<\/title/)) { + removeTitle = true; + } + } catch (err) {} + })(); + } + + /** + * _createIterator + * + * @param {Document} root document/fragment to create iterator for + * @return {Iterator} iterator instance + */ + var _createIterator = function _createIterator(root) { + return createNodeIterator.call(root.ownerDocument || root, root, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT, function () { + return NodeFilter.FILTER_ACCEPT; + }, false); + }; + + /** + * _isClobbered + * + * @param {Node} elm element to check for clobbering attacks + * @return {Boolean} true if clobbered, false if safe + */ + var _isClobbered = function _isClobbered(elm) { + if (elm instanceof Text || elm instanceof Comment) { + return false; + } + if (typeof elm.nodeName !== 'string' || typeof elm.textContent !== 'string' || typeof elm.removeChild !== 'function' || !(elm.attributes instanceof NamedNodeMap) || typeof elm.removeAttribute !== 'function' || typeof elm.setAttribute !== 'function') { + return true; + } + return false; + }; + + /** + * _isNode + * + * @param {Node} obj object to check whether it's a DOM node + * @return {Boolean} true is object is a DOM node + */ + var _isNode = function _isNode(obj) { + return (typeof Node === 'undefined' ? 'undefined' : _typeof(Node)) === 'object' ? obj instanceof Node : obj && (typeof obj === 'undefined' ? 'undefined' : _typeof(obj)) === 'object' && typeof obj.nodeType === 'number' && typeof obj.nodeName === 'string'; + }; + + /** + * _executeHook + * Execute user configurable hooks + * + * @param {String} entryPoint Name of the hook's entry point + * @param {Node} currentNode node to work on with the hook + * @param {Object} data additional hook parameters + */ + var _executeHook = function _executeHook(entryPoint, currentNode, data) { + if (!hooks[entryPoint]) { + return; + } + + hooks[entryPoint].forEach(function (hook) { + hook.call(DOMPurify, currentNode, data, CONFIG); + }); + }; + + /** + * _sanitizeElements + * + * @protect nodeName + * @protect textContent + * @protect removeChild + * + * @param {Node} currentNode to check for permission to exist + * @return {Boolean} true if node was killed, false if left alive + */ + var _sanitizeElements = function _sanitizeElements(currentNode) { + var content = void 0; + + /* Execute a hook if present */ + _executeHook('beforeSanitizeElements', currentNode, null); + + /* Check if element is clobbered or can clobber */ + if (_isClobbered(currentNode)) { + _forceRemove(currentNode); + return true; + } + + /* Now let's check the element's type and name */ + var tagName = currentNode.nodeName.toLowerCase(); + + /* Execute a hook if present */ + _executeHook('uponSanitizeElement', currentNode, { + tagName: tagName, + allowedTags: ALLOWED_TAGS + }); + + /* Remove element if anything forbids its presence */ + if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) { + /* Keep content except for black-listed elements */ + if (KEEP_CONTENT && !FORBID_CONTENTS[tagName] && typeof currentNode.insertAdjacentHTML === 'function') { + try { + currentNode.insertAdjacentHTML('AfterEnd', currentNode.innerHTML); + } catch (err) {} + } + _forceRemove(currentNode); + return true; + } + + /* Convert markup to cover jQuery behavior */ + if (SAFE_FOR_JQUERY && !currentNode.firstElementChild && (!currentNode.content || !currentNode.content.firstElementChild) && /</g.test(currentNode.textContent)) { + DOMPurify.removed.push({ element: currentNode.cloneNode() }); + if (currentNode.innerHTML) { + currentNode.innerHTML = currentNode.innerHTML.replace(/</g, '<'); + } else { + currentNode.innerHTML = currentNode.textContent.replace(/</g, '<'); + } + } + + /* Sanitize element content to be template-safe */ + if (SAFE_FOR_TEMPLATES && currentNode.nodeType === 3) { + /* Get the element's text content */ + content = currentNode.textContent; + content = content.replace(MUSTACHE_EXPR$$1, ' '); + content = content.replace(ERB_EXPR$$1, ' '); + if (currentNode.textContent !== content) { + DOMPurify.removed.push({ element: currentNode.cloneNode() }); + currentNode.textContent = content; + } + } + + /* Execute a hook if present */ + _executeHook('afterSanitizeElements', currentNode, null); + + return false; + }; + + /** + * _isValidAttribute + * + * @param {string} lcTag Lowercase tag name of containing element. + * @param {string} lcName Lowercase attribute name. + * @param {string} value Attribute value. + * @return {Boolean} Returns true if `value` is valid, otherwise false. + */ + var _isValidAttribute = function _isValidAttribute(lcTag, lcName, value) { + /* Make sure attribute cannot clobber */ + if (SANITIZE_DOM && (lcName === 'id' || lcName === 'name') && (value in document || value in formElement)) { + return false; + } + + /* Sanitize attribute content to be template-safe */ + if (SAFE_FOR_TEMPLATES) { + value = value.replace(MUSTACHE_EXPR$$1, ' '); + value = value.replace(ERB_EXPR$$1, ' '); + } + + /* Allow valid data-* attributes: At least one character after "-" + (https://html.spec.whatwg.org/multipage/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes) + XML-compatible (https://html.spec.whatwg.org/multipage/infrastructure.html#xml-compatible and http://www.w3.org/TR/xml/#d0e804) + We don't need to check the value; it's always URI safe. */ + if (ALLOW_DATA_ATTR && DATA_ATTR$$1.test(lcName)) { + // This attribute is safe + } else if (ALLOW_ARIA_ATTR && ARIA_ATTR$$1.test(lcName)) { + // This attribute is safe + /* Otherwise, check the name is permitted */ + } else if (!ALLOWED_ATTR[lcName] || FORBID_ATTR[lcName]) { + return false; + + /* Check value is safe. First, is attr inert? If so, is safe */ + } else if (URI_SAFE_ATTRIBUTES[lcName]) { + // This attribute is safe + /* Check no script, data or unknown possibly unsafe URI + unless we know URI values are safe for that attribute */ + } else if (IS_ALLOWED_URI$$1.test(value.replace(ATTR_WHITESPACE$$1, ''))) { + // This attribute is safe + /* Keep image data URIs alive if src/xlink:href is allowed */ + /* Further prevent gadget XSS for dynamically built script tags */ + } else if ((lcName === 'src' || lcName === 'xlink:href') && lcTag !== 'script' && value.indexOf('data:') === 0 && DATA_URI_TAGS[lcTag]) { + // This attribute is safe + /* Allow unknown protocols: This provides support for links that + are handled by protocol handlers which may be unknown ahead of + time, e.g. fb:, spotify: */ + } else if (ALLOW_UNKNOWN_PROTOCOLS && !IS_SCRIPT_OR_DATA$$1.test(value.replace(ATTR_WHITESPACE$$1, ''))) { + // This attribute is safe + /* Check for binary attributes */ + // eslint-disable-next-line no-negated-condition + } else if (!value) { + // Binary attributes are safe at this point + /* Anything else, presume unsafe, do not add it back */ + } else { + return false; + } + return true; + }; + + /** + * _sanitizeAttributes + * + * @protect attributes + * @protect nodeName + * @protect removeAttribute + * @protect setAttribute + * + * @param {Node} node to sanitize + */ + // eslint-disable-next-line complexity + var _sanitizeAttributes = function _sanitizeAttributes(currentNode) { + var attr = void 0; + var value = void 0; + var lcName = void 0; + var idAttr = void 0; + var l = void 0; + /* Execute a hook if present */ + _executeHook('beforeSanitizeAttributes', currentNode, null); + + var attributes = currentNode.attributes; + + /* Check if we have attributes; if not we might have a text node */ + + if (!attributes) { + return; + } + + var hookEvent = { + attrName: '', + attrValue: '', + keepAttr: true, + allowedAttributes: ALLOWED_ATTR + }; + l = attributes.length; + + /* Go backwards over all attributes; safely remove bad ones */ + while (l--) { + attr = attributes[l]; + var _attr = attr, + name = _attr.name, + namespaceURI = _attr.namespaceURI; + + value = attr.value.trim(); + lcName = name.toLowerCase(); + + /* Execute a hook if present */ + hookEvent.attrName = lcName; + hookEvent.attrValue = value; + hookEvent.keepAttr = true; + _executeHook('uponSanitizeAttribute', currentNode, hookEvent); + value = hookEvent.attrValue; + + /* Remove attribute */ + // Safari (iOS + Mac), last tested v8.0.5, crashes if you try to + // remove a "name" attribute from an <img> tag that has an "id" + // attribute at the time. + if (lcName === 'name' && currentNode.nodeName === 'IMG' && attributes.id) { + idAttr = attributes.id; + attributes = Array.prototype.slice.apply(attributes); + _removeAttribute('id', currentNode); + _removeAttribute(name, currentNode); + if (attributes.indexOf(idAttr) > l) { + currentNode.setAttribute('id', idAttr.value); + } + } else if ( + // This works around a bug in Safari, where input[type=file] + // cannot be dynamically set after type has been removed + currentNode.nodeName === 'INPUT' && lcName === 'type' && value === 'file' && (ALLOWED_ATTR[lcName] || !FORBID_ATTR[lcName])) { + continue; + } else { + // This avoids a crash in Safari v9.0 with double-ids. + // The trick is to first set the id to be empty and then to + // remove the attribute + if (name === 'id') { + currentNode.setAttribute(name, ''); + } + _removeAttribute(name, currentNode); + } + + /* Did the hooks approve of the attribute? */ + if (!hookEvent.keepAttr) { + continue; + } + + /* Is `value` valid for this attribute? */ + var lcTag = currentNode.nodeName.toLowerCase(); + if (!_isValidAttribute(lcTag, lcName, value)) { + continue; + } + + /* Handle invalid data-* attribute set by try-catching it */ + try { + if (namespaceURI) { + currentNode.setAttributeNS(namespaceURI, name, value); + } else { + /* Fallback to setAttribute() for browser-unrecognized namespaces e.g. "x-schema". */ + currentNode.setAttribute(name, value); + } + DOMPurify.removed.pop(); + } catch (err) {} + } + + /* Execute a hook if present */ + _executeHook('afterSanitizeAttributes', currentNode, null); + }; + + /** + * _sanitizeShadowDOM + * + * @param {DocumentFragment} fragment to iterate over recursively + */ + var _sanitizeShadowDOM = function _sanitizeShadowDOM(fragment) { + var shadowNode = void 0; + var shadowIterator = _createIterator(fragment); + + /* Execute a hook if present */ + _executeHook('beforeSanitizeShadowDOM', fragment, null); + + while (shadowNode = shadowIterator.nextNode()) { + /* Execute a hook if present */ + _executeHook('uponSanitizeShadowNode', shadowNode, null); + + /* Sanitize tags and elements */ + if (_sanitizeElements(shadowNode)) { + continue; + } + + /* Deep shadow DOM detected */ + if (shadowNode.content instanceof DocumentFragment) { + _sanitizeShadowDOM(shadowNode.content); + } + + /* Check attributes, sanitize if necessary */ + _sanitizeAttributes(shadowNode); + } + + /* Execute a hook if present */ + _executeHook('afterSanitizeShadowDOM', fragment, null); + }; + + /** + * Sanitize + * Public method providing core sanitation functionality + * + * @param {String|Node} dirty string or DOM node + * @param {Object} configuration object + */ + // eslint-disable-next-line complexity + DOMPurify.sanitize = function (dirty, cfg) { + var body = void 0; + var importedNode = void 0; + var currentNode = void 0; + var oldNode = void 0; + var returnNode = void 0; + /* Make sure we have a string to sanitize. + DO NOT return early, as this will return the wrong type if + the user has requested a DOM object rather than a string */ + if (!dirty) { + dirty = '<!-->'; + } + + /* Stringify, in case dirty is an object */ + if (typeof dirty !== 'string' && !_isNode(dirty)) { + // eslint-disable-next-line no-negated-condition + if (typeof dirty.toString !== 'function') { + throw new TypeError('toString is not a function'); + } else { + dirty = dirty.toString(); + if (typeof dirty !== 'string') { + throw new TypeError('dirty is not a string, aborting'); + } + } + } + + /* Check we can run. Otherwise fall back or ignore */ + if (!DOMPurify.isSupported) { + if (_typeof(window.toStaticHTML) === 'object' || typeof window.toStaticHTML === 'function') { + if (typeof dirty === 'string') { + return window.toStaticHTML(dirty); + } + if (_isNode(dirty)) { + return window.toStaticHTML(dirty.outerHTML); + } + } + return dirty; + } + + /* Assign config vars */ + if (!SET_CONFIG) { + _parseConfig(cfg); + } + + /* Clean up removed elements */ + DOMPurify.removed = []; + + if (IN_PLACE) { + /* No special handling necessary for in-place sanitization */ + } else if (dirty instanceof Node) { + /* If dirty is a DOM element, append to an empty document to avoid + elements being stripped by the parser */ + body = _initDocument('<!-->'); + importedNode = body.ownerDocument.importNode(dirty, true); + if (importedNode.nodeType === 1 && importedNode.nodeName === 'BODY') { + /* Node is already a body, use as is */ + body = importedNode; + } else { + body.appendChild(importedNode); + } + } else { + /* Exit directly if we have nothing to do */ + if (!RETURN_DOM && !WHOLE_DOCUMENT && dirty.indexOf('<') === -1) { + return dirty; + } + + /* Initialize the document to work on */ + body = _initDocument(dirty); + + /* Check we have a DOM node from the data */ + if (!body) { + return RETURN_DOM ? null : ''; + } + } + + /* Remove first element node (ours) if FORCE_BODY is set */ + if (body && FORCE_BODY) { + _forceRemove(body.firstChild); + } + + /* Get node iterator */ + var nodeIterator = _createIterator(IN_PLACE ? dirty : body); + + /* Now start iterating over the created document */ + while (currentNode = nodeIterator.nextNode()) { + /* Fix IE's strange behavior with manipulated textNodes #89 */ + if (currentNode.nodeType === 3 && currentNode === oldNode) { + continue; + } + + /* Sanitize tags and elements */ + if (_sanitizeElements(currentNode)) { + continue; + } + + /* Shadow DOM detected, sanitize it */ + if (currentNode.content instanceof DocumentFragment) { + _sanitizeShadowDOM(currentNode.content); + } + + /* Check attributes, sanitize if necessary */ + _sanitizeAttributes(currentNode); + + oldNode = currentNode; + } + + /* If we sanitized `dirty` in-place, return it. */ + if (IN_PLACE) { + return dirty; + } + + /* Return sanitized string or DOM */ + if (RETURN_DOM) { + if (RETURN_DOM_FRAGMENT) { + returnNode = createDocumentFragment.call(body.ownerDocument); + + while (body.firstChild) { + returnNode.appendChild(body.firstChild); + } + } else { + returnNode = body; + } + + if (RETURN_DOM_IMPORT) { + /* AdoptNode() is not used because internal state is not reset + (e.g. the past names map of a HTMLFormElement), this is safe + in theory but we would rather not risk another attack vector. + The state that is cloned by importNode() is explicitly defined + by the specs. */ + returnNode = importNode.call(originalDocument, returnNode, true); + } + + return returnNode; + } + + return WHOLE_DOCUMENT ? body.outerHTML : body.innerHTML; + }; + + /** + * Public method to set the configuration once + * setConfig + * + * @param {Object} cfg configuration object + */ + DOMPurify.setConfig = function (cfg) { + _parseConfig(cfg); + SET_CONFIG = true; + }; + + /** + * Public method to remove the configuration + * clearConfig + * + */ + DOMPurify.clearConfig = function () { + CONFIG = null; + SET_CONFIG = false; + }; + + /** + * Public method to check if an attribute value is valid. + * Uses last set config, if any. Otherwise, uses config defaults. + * isValidAttribute + * + * @param {string} tag Tag name of containing element. + * @param {string} attr Attribute name. + * @param {string} value Attribute value. + * @return {Boolean} Returns true if `value` is valid. Otherwise, returns false. + */ + DOMPurify.isValidAttribute = function (tag, attr, value) { + /* Initialize shared config vars if necessary. */ + if (!CONFIG) { + _parseConfig({}); + } + var lcTag = tag.toLowerCase(); + var lcName = attr.toLowerCase(); + return _isValidAttribute(lcTag, lcName, value); + }; + + /** + * AddHook + * Public method to add DOMPurify hooks + * + * @param {String} entryPoint entry point for the hook to add + * @param {Function} hookFunction function to execute + */ + DOMPurify.addHook = function (entryPoint, hookFunction) { + if (typeof hookFunction !== 'function') { + return; + } + hooks[entryPoint] = hooks[entryPoint] || []; + hooks[entryPoint].push(hookFunction); + }; + + /** + * RemoveHook + * Public method to remove a DOMPurify hook at a given entryPoint + * (pops it from the stack of hooks if more are present) + * + * @param {String} entryPoint entry point for the hook to remove + */ + DOMPurify.removeHook = function (entryPoint) { + if (hooks[entryPoint]) { + hooks[entryPoint].pop(); + } + }; + + /** + * RemoveHooks + * Public method to remove all DOMPurify hooks at a given entryPoint + * + * @param {String} entryPoint entry point for the hooks to remove + */ + DOMPurify.removeHooks = function (entryPoint) { + if (hooks[entryPoint]) { + hooks[entryPoint] = []; + } + }; + + /** + * RemoveAllHooks + * Public method to remove all DOMPurify hooks + * + */ + DOMPurify.removeAllHooks = function () { + hooks = {}; + }; + + return DOMPurify; +} + +var purify = createDOMPurify(); + +return purify; + +}))); +//# sourceMappingURL=purify.js.map diff --git a/public/vendor/laravel-admin-ext/simditor/simditor-2.3.28/scripts/hotkeys.js b/public/vendor/laravel-admin-ext/simditor/simditor-2.3.28/scripts/hotkeys.js new file mode 100644 index 00000000..de20b918 --- /dev/null +++ b/public/vendor/laravel-admin-ext/simditor/simditor-2.3.28/scripts/hotkeys.js @@ -0,0 +1,241 @@ +(function (root, factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module unless amdModuleId is set + define('simple-hotkeys', ["jquery","simple-module"], function ($, SimpleModule) { + return (root['hotkeys'] = factory($, SimpleModule)); + }); + } 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"),require("simple-module")); + } else { + root.simple = root.simple || {}; + root.simple['hotkeys'] = factory(jQuery,SimpleModule); + } +}(this, function ($, SimpleModule) { + +var Hotkeys, hotkeys, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + +Hotkeys = (function(superClass) { + extend(Hotkeys, superClass); + + function Hotkeys() { + return Hotkeys.__super__.constructor.apply(this, arguments); + } + + Hotkeys.count = 0; + + Hotkeys.keyNameMap = { + 8: "Backspace", + 9: "Tab", + 13: "Enter", + 16: "Shift", + 17: "Control", + 18: "Alt", + 19: "Pause", + 20: "CapsLock", + 27: "Esc", + 32: "Spacebar", + 33: "PageUp", + 34: "PageDown", + 35: "End", + 36: "Home", + 37: "Left", + 38: "Up", + 39: "Right", + 40: "Down", + 45: "Insert", + 46: "Del", + 91: "Meta", + 93: "Meta", + 48: "0", + 49: "1", + 50: "2", + 51: "3", + 52: "4", + 53: "5", + 54: "6", + 55: "7", + 56: "8", + 57: "9", + 65: "A", + 66: "B", + 67: "C", + 68: "D", + 69: "E", + 70: "F", + 71: "G", + 72: "H", + 73: "I", + 74: "J", + 75: "K", + 76: "L", + 77: "M", + 78: "N", + 79: "O", + 80: "P", + 81: "Q", + 82: "R", + 83: "S", + 84: "T", + 85: "U", + 86: "V", + 87: "W", + 88: "X", + 89: "Y", + 90: "Z", + 96: "0", + 97: "1", + 98: "2", + 99: "3", + 100: "4", + 101: "5", + 102: "6", + 103: "7", + 104: "8", + 105: "9", + 106: "Multiply", + 107: "Add", + 109: "Subtract", + 110: "Decimal", + 111: "Divide", + 112: "F1", + 113: "F2", + 114: "F3", + 115: "F4", + 116: "F5", + 117: "F6", + 118: "F7", + 119: "F8", + 120: "F9", + 121: "F10", + 122: "F11", + 123: "F12", + 124: "F13", + 125: "F14", + 126: "F15", + 127: "F16", + 128: "F17", + 129: "F18", + 130: "F19", + 131: "F20", + 132: "F21", + 133: "F22", + 134: "F23", + 135: "F24", + 59: ";", + 61: "=", + 186: ";", + 187: "=", + 188: ",", + 190: ".", + 191: "/", + 192: "`", + 219: "[", + 220: "\\", + 221: "]", + 222: "'" + }; + + Hotkeys.aliases = { + "escape": "esc", + "delete": "del", + "return": "enter", + "ctrl": "control", + "space": "spacebar", + "ins": "insert", + "cmd": "meta", + "command": "meta", + "wins": "meta", + "windows": "meta" + }; + + Hotkeys.normalize = function(shortcut) { + var i, j, key, keyname, keys, len; + keys = shortcut.toLowerCase().replace(/\s+/gi, "").split("+"); + for (i = j = 0, len = keys.length; j < len; i = ++j) { + key = keys[i]; + keys[i] = this.aliases[key] || key; + } + keyname = keys.pop(); + keys.sort().push(keyname); + return keys.join("_"); + }; + + Hotkeys.prototype.opts = { + el: document + }; + + Hotkeys.prototype._init = function() { + this.id = ++this.constructor.count; + this._map = {}; + this._delegate = typeof this.opts.el === "string" ? document : this.opts.el; + return $(this._delegate).on("keydown.simple-hotkeys-" + this.id, this.opts.el, (function(_this) { + return function(e) { + var ref; + return (ref = _this._getHander(e)) != null ? ref.call(_this, e) : void 0; + }; + })(this)); + }; + + Hotkeys.prototype._getHander = function(e) { + var keyname, shortcut; + if (!(keyname = this.constructor.keyNameMap[e.which])) { + return; + } + shortcut = ""; + if (e.altKey) { + shortcut += "alt_"; + } + if (e.ctrlKey) { + shortcut += "control_"; + } + if (e.metaKey) { + shortcut += "meta_"; + } + if (e.shiftKey) { + shortcut += "shift_"; + } + shortcut += keyname.toLowerCase(); + return this._map[shortcut]; + }; + + Hotkeys.prototype.respondTo = function(subject) { + if (typeof subject === 'string') { + return this._map[this.constructor.normalize(subject)] != null; + } else { + return this._getHander(subject) != null; + } + }; + + Hotkeys.prototype.add = function(shortcut, handler) { + this._map[this.constructor.normalize(shortcut)] = handler; + return this; + }; + + Hotkeys.prototype.remove = function(shortcut) { + delete this._map[this.constructor.normalize(shortcut)]; + return this; + }; + + Hotkeys.prototype.destroy = function() { + $(this._delegate).off(".simple-hotkeys-" + this.id); + this._map = {}; + return this; + }; + + return Hotkeys; + +})(SimpleModule); + +hotkeys = function(opts) { + return new Hotkeys(opts); +}; + +return hotkeys; + +})); + diff --git a/public/vendor/laravel-admin-ext/simditor/simditor-2.3.28/scripts/module.js b/public/vendor/laravel-admin-ext/simditor/simditor-2.3.28/scripts/module.js new file mode 100644 index 00000000..9f7dbbd7 --- /dev/null +++ b/public/vendor/laravel-admin-ext/simditor/simditor-2.3.28/scripts/module.js @@ -0,0 +1,172 @@ +(function (root, factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module unless amdModuleId is set + define('simple-module', ["jquery"], function (a0) { + return (root['Module'] = factory(a0)); + }); + } 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 { + root['SimpleModule'] = factory(jQuery); + } +}(this, function ($) { + +var Module, + slice = [].slice; + +Module = (function() { + Module.extend = function(obj) { + var key, ref, val; + if (!((obj != null) && typeof obj === 'object')) { + return; + } + for (key in obj) { + val = obj[key]; + if (key !== 'included' && key !== 'extended') { + this[key] = val; + } + } + return (ref = obj.extended) != null ? ref.call(this) : void 0; + }; + + Module.include = function(obj) { + var key, ref, val; + if (!((obj != null) && typeof obj === 'object')) { + return; + } + for (key in obj) { + val = obj[key]; + if (key !== 'included' && key !== 'extended') { + this.prototype[key] = val; + } + } + return (ref = obj.included) != null ? ref.call(this) : void 0; + }; + + Module.connect = function(cls) { + if (typeof cls !== 'function') { + return; + } + if (!cls.pluginName) { + throw new Error('Module.connect: cannot connect plugin without pluginName'); + return; + } + cls.prototype._connected = true; + if (!this._connectedClasses) { + this._connectedClasses = []; + } + this._connectedClasses.push(cls); + if (cls.pluginName) { + return this[cls.pluginName] = cls; + } + }; + + Module.prototype.opts = {}; + + function Module(opts) { + var base, cls, i, instance, instances, len, name; + this.opts = $.extend({}, this.opts, opts); + (base = this.constructor)._connectedClasses || (base._connectedClasses = []); + instances = (function() { + var i, len, ref, results; + ref = this.constructor._connectedClasses; + results = []; + for (i = 0, len = ref.length; i < len; i++) { + cls = ref[i]; + name = cls.pluginName.charAt(0).toLowerCase() + cls.pluginName.slice(1); + if (cls.prototype._connected) { + cls.prototype._module = this; + } + results.push(this[name] = new cls()); + } + return results; + }).call(this); + if (this._connected) { + this.opts = $.extend({}, this.opts, this._module.opts); + } else { + this._init(); + for (i = 0, len = instances.length; i < len; i++) { + instance = instances[i]; + if (typeof instance._init === "function") { + instance._init(); + } + } + } + this.trigger('initialized'); + } + + Module.prototype._init = function() {}; + + Module.prototype.on = function() { + var args, ref; + args = 1 <= arguments.length ? slice.call(arguments, 0) : []; + (ref = $(this)).on.apply(ref, args); + return this; + }; + + Module.prototype.one = function() { + var args, ref; + args = 1 <= arguments.length ? slice.call(arguments, 0) : []; + (ref = $(this)).one.apply(ref, args); + return this; + }; + + Module.prototype.off = function() { + var args, ref; + args = 1 <= arguments.length ? slice.call(arguments, 0) : []; + (ref = $(this)).off.apply(ref, args); + return this; + }; + + Module.prototype.trigger = function() { + var args, ref; + args = 1 <= arguments.length ? slice.call(arguments, 0) : []; + (ref = $(this)).trigger.apply(ref, args); + return this; + }; + + Module.prototype.triggerHandler = function() { + var args, ref; + args = 1 <= arguments.length ? slice.call(arguments, 0) : []; + return (ref = $(this)).triggerHandler.apply(ref, args); + }; + + Module.prototype._t = function() { + var args, ref; + args = 1 <= arguments.length ? slice.call(arguments, 0) : []; + return (ref = this.constructor)._t.apply(ref, args); + }; + + Module._t = function() { + var args, key, ref, result; + key = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : []; + result = ((ref = this.i18n[this.locale]) != null ? ref[key] : void 0) || ''; + if (!(args.length > 0)) { + return result; + } + result = result.replace(/([^%]|^)%(?:(\d+)\$)?s/g, function(p0, p, position) { + if (position) { + return p + args[parseInt(position) - 1]; + } else { + return p + args.shift(); + } + }); + return result.replace(/%%s/g, '%s'); + }; + + Module.i18n = { + 'zh-CN': {} + }; + + Module.locale = 'zh-CN'; + + return Module; + +})(); + +return Module; + +})); diff --git a/public/vendor/laravel-admin-ext/simditor/simditor-2.3.28/scripts/simditor.js b/public/vendor/laravel-admin-ext/simditor/simditor-2.3.28/scripts/simditor.js new file mode 100644 index 00000000..564ef062 --- /dev/null +++ b/public/vendor/laravel-admin-ext/simditor/simditor-2.3.28/scripts/simditor.js @@ -0,0 +1,5698 @@ +/*! +* Simditor v2.3.27 +* http://simditor.tower.im/ +* 2019-08-15 +*/ +(function (root, factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module unless amdModuleId is set + define('simditor', ["jquery","simple-module","simple-hotkeys","simple-uploader","dompurify"], function ($, SimpleModule, simpleHotkeys, simpleUploader, DOMPurify) { + return (root['Simditor'] = factory($, SimpleModule, simpleHotkeys, simpleUploader, DOMPurify)); + }); + } 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"),require("simple-module"),require("simple-hotkeys"),require("simple-uploader"),require("dompurify")); + } else { + root['Simditor'] = factory(jQuery,SimpleModule,simple.hotkeys,simple.uploader,window.DOMPurify); + } +}(this, function ($, SimpleModule, simpleHotkeys, simpleUploader, DOMPurify) { + +var AlignmentButton, BlockquoteButton, BoldButton, Button, Clipboard, CodeButton, CodePopover, ColorButton, FontScaleButton, Formatter, HrButton, ImageButton, ImagePopover, IndentButton, Indentation, InputManager, ItalicButton, Keystroke, LinkButton, LinkPopover, ListButton, OrderListButton, OutdentButton, Popover, Selection, Simditor, StrikethroughButton, TableButton, TitleButton, Toolbar, UnderlineButton, UndoManager, UnorderListButton, Util, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty, + indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }, + slice = [].slice; + +Selection = (function(superClass) { + extend(Selection, superClass); + + function Selection() { + return Selection.__super__.constructor.apply(this, arguments); + } + + Selection.pluginName = 'Selection'; + + Selection.prototype._range = null; + + Selection.prototype._startNodes = null; + + Selection.prototype._endNodes = null; + + Selection.prototype._containerNode = null; + + Selection.prototype._nodes = null; + + Selection.prototype._blockNodes = null; + + Selection.prototype._rootNodes = null; + + Selection.prototype._init = function() { + this.editor = this._module; + this._selection = document.getSelection(); + this.editor.on('selectionchanged', (function(_this) { + return function(e) { + _this.reset(); + return _this._range = _this._selection.getRangeAt(0); + }; + })(this)); + this.editor.on('blur', (function(_this) { + return function(e) { + return _this.reset(); + }; + })(this)); + return this.editor.on('focus', (function(_this) { + return function(e) { + _this.reset(); + return _this._range = _this._selection.getRangeAt(0); + }; + })(this)); + }; + + Selection.prototype.reset = function() { + this._range = null; + this._startNodes = null; + this._endNodes = null; + this._containerNode = null; + this._nodes = null; + this._blockNodes = null; + return this._rootNodes = null; + }; + + Selection.prototype.clear = function() { + var e; + try { + this._selection.removeAllRanges(); + } catch (_error) { + e = _error; + } + return this.reset(); + }; + + Selection.prototype.range = function(range) { + var ffOrIE; + if (range) { + this.clear(); + this._selection.addRange(range); + this._range = range; + ffOrIE = this.editor.util.browser.firefox || this.editor.util.browser.msie; + if (!this.editor.inputManager.focused && ffOrIE) { + this.editor.body.focus(); + } + } else if (!this._range && this.editor.inputManager.focused && this._selection.rangeCount) { + this._range = this._selection.getRangeAt(0); + } + return this._range; + }; + + Selection.prototype.startNodes = function() { + if (this._range) { + this._startNodes || (this._startNodes = (function(_this) { + return function() { + var startNodes; + startNodes = $(_this._range.startContainer).parentsUntil(_this.editor.body).get(); + startNodes.unshift(_this._range.startContainer); + return $(startNodes); + }; + })(this)()); + } + return this._startNodes; + }; + + Selection.prototype.endNodes = function() { + var endNodes; + if (this._range) { + this._endNodes || (this._endNodes = this._range.collapsed ? this.startNodes() : (endNodes = $(this._range.endContainer).parentsUntil(this.editor.body).get(), endNodes.unshift(this._range.endContainer), $(endNodes))); + } + return this._endNodes; + }; + + Selection.prototype.containerNode = function() { + if (this._range) { + this._containerNode || (this._containerNode = $(this._range.commonAncestorContainer)); + } + return this._containerNode; + }; + + Selection.prototype.nodes = function() { + if (this._range) { + this._nodes || (this._nodes = (function(_this) { + return function() { + var nodes; + nodes = []; + if (_this.startNodes().first().is(_this.endNodes().first())) { + nodes = _this.startNodes().get(); + } else { + _this.startNodes().each(function(i, node) { + var $endNode, $node, $nodes, endIndex, index, sharedIndex, startIndex; + $node = $(node); + if (_this.endNodes().index($node) > -1) { + return nodes.push(node); + } else if ($node.parent().is(_this.editor.body) || (sharedIndex = _this.endNodes().index($node.parent())) > -1) { + if (sharedIndex && sharedIndex > -1) { + $endNode = _this.endNodes().eq(sharedIndex - 1); + } else { + $endNode = _this.endNodes().last(); + } + $nodes = $node.parent().contents(); + startIndex = $nodes.index($node); + endIndex = $nodes.index($endNode); + return $.merge(nodes, $nodes.slice(startIndex, endIndex).get()); + } else { + $nodes = $node.parent().contents(); + index = $nodes.index($node); + return $.merge(nodes, $nodes.slice(index).get()); + } + }); + _this.endNodes().each(function(i, node) { + var $node, $nodes, index; + $node = $(node); + if ($node.parent().is(_this.editor.body) || _this.startNodes().index($node.parent()) > -1) { + nodes.push(node); + return false; + } else { + $nodes = $node.parent().contents(); + index = $nodes.index($node); + return $.merge(nodes, $nodes.slice(0, index + 1)); + } + }); + } + return $($.unique(nodes)); + }; + })(this)()); + } + return this._nodes; + }; + + Selection.prototype.blockNodes = function() { + if (!this._range) { + return; + } + this._blockNodes || (this._blockNodes = (function(_this) { + return function() { + return _this.nodes().filter(function(i, node) { + return _this.editor.util.isBlockNode(node); + }); + }; + })(this)()); + return this._blockNodes; + }; + + Selection.prototype.rootNodes = function() { + if (!this._range) { + return; + } + this._rootNodes || (this._rootNodes = (function(_this) { + return function() { + return _this.nodes().filter(function(i, node) { + var $parent; + $parent = $(node).parent(); + return $parent.is(_this.editor.body) || $parent.is('blockquote'); + }); + }; + })(this)()); + return this._rootNodes; + }; + + Selection.prototype.rangeAtEndOf = function(node, range) { + var afterLastNode, beforeLastNode, endNode, endNodeLength, lastNodeIsBr, result; + if (range == null) { + range = this.range(); + } + if (!(range && range.collapsed)) { + return; + } + node = $(node)[0]; + endNode = range.endContainer; + endNodeLength = this.editor.util.getNodeLength(endNode); + beforeLastNode = range.endOffset === endNodeLength - 1; + lastNodeIsBr = $(endNode).contents().last().is('br'); + afterLastNode = range.endOffset === endNodeLength; + if (!((beforeLastNode && lastNodeIsBr) || afterLastNode)) { + return false; + } + if (node === endNode) { + return true; + } else if (!$.contains(node, endNode)) { + return false; + } + result = true; + $(endNode).parentsUntil(node).addBack().each(function(i, n) { + var $lastChild, beforeLastbr, isLastNode, nodes; + nodes = $(n).parent().contents().filter(function() { + return !(this !== n && this.nodeType === 3 && !this.nodeValue); + }); + $lastChild = nodes.last(); + isLastNode = $lastChild.get(0) === n; + beforeLastbr = $lastChild.is('br') && $lastChild.prev().get(0) === n; + if (!(isLastNode || beforeLastbr)) { + result = false; + return false; + } + }); + return result; + }; + + Selection.prototype.rangeAtStartOf = function(node, range) { + var result, startNode; + if (range == null) { + range = this.range(); + } + if (!(range && range.collapsed)) { + return; + } + node = $(node)[0]; + startNode = range.startContainer; + if (range.startOffset !== 0) { + return false; + } + if (node === startNode) { + return true; + } else if (!$.contains(node, startNode)) { + return false; + } + result = true; + $(startNode).parentsUntil(node).addBack().each(function(i, n) { + var nodes; + nodes = $(n).parent().contents().filter(function() { + return !(this !== n && this.nodeType === 3 && !this.nodeValue); + }); + if (nodes.first().get(0) !== n) { + return result = false; + } + }); + return result; + }; + + Selection.prototype.insertNode = function(node, range) { + if (range == null) { + range = this.range(); + } + if (!range) { + return; + } + node = $(node)[0]; + range.insertNode(node); + return this.setRangeAfter(node, range); + }; + + Selection.prototype.setRangeAfter = function(node, range) { + if (range == null) { + range = this.range(); + } + if (range == null) { + return; + } + node = $(node)[0]; + range.setEndAfter(node); + range.collapse(false); + return this.range(range); + }; + + Selection.prototype.setRangeBefore = function(node, range) { + if (range == null) { + range = this.range(); + } + if (range == null) { + return; + } + node = $(node)[0]; + range.setEndBefore(node); + range.collapse(false); + return this.range(range); + }; + + Selection.prototype.setRangeAtStartOf = function(node, range) { + if (range == null) { + range = this.range(); + } + node = $(node).get(0); + range.setEnd(node, 0); + range.collapse(false); + return this.range(range); + }; + + Selection.prototype.setRangeAtEndOf = function(node, range) { + var $lastNode, $node, contents, lastChild, lastChildLength, lastText, nodeLength; + if (range == null) { + range = this.range(); + } + $node = $(node); + node = $node[0]; + if (!node) { + return; + } + if ($node.is('pre')) { + contents = $node.contents(); + if (contents.length > 0) { + lastChild = contents.last(); + lastText = lastChild.text(); + lastChildLength = this.editor.util.getNodeLength(lastChild[0]); + if (lastText.charAt(lastText.length - 1) === '\n') { + range.setEnd(lastChild[0], lastChildLength - 1); + } else { + range.setEnd(lastChild[0], lastChildLength); + } + } else { + range.setEnd(node, 0); + } + } else { + nodeLength = this.editor.util.getNodeLength(node); + if (node.nodeType !== 3 && nodeLength > 0) { + $lastNode = $(node).contents().last(); + if ($lastNode.is('br')) { + nodeLength -= 1; + } else if ($lastNode[0].nodeType !== 3 && this.editor.util.isEmptyNode($lastNode)) { + $lastNode.append(this.editor.util.phBr); + node = $lastNode[0]; + nodeLength = 0; + } + } + range.setEnd(node, nodeLength); + } + range.collapse(false); + return this.range(range); + }; + + Selection.prototype.deleteRangeContents = function(range) { + var atEndOfBody, atStartOfBody, endRange, startRange; + if (range == null) { + range = this.range(); + } + startRange = range.cloneRange(); + endRange = range.cloneRange(); + startRange.collapse(true); + endRange.collapse(false); + atStartOfBody = this.rangeAtStartOf(this.editor.body, startRange); + atEndOfBody = this.rangeAtEndOf(this.editor.body, endRange); + if (!range.collapsed && atStartOfBody && atEndOfBody) { + this.editor.body.empty(); + range.setStart(this.editor.body[0], 0); + range.collapse(true); + this.range(range); + } else { + range.deleteContents(); + } + return range; + }; + + Selection.prototype.breakBlockEl = function(el, range) { + var $el; + if (range == null) { + range = this.range(); + } + $el = $(el); + if (!range.collapsed) { + return $el; + } + range.setStartBefore($el.get(0)); + if (range.collapsed) { + return $el; + } + return $el.before(range.extractContents()); + }; + + Selection.prototype.save = function(range) { + var endCaret, endRange, startCaret; + if (range == null) { + range = this.range(); + } + if (this._selectionSaved) { + return; + } + endRange = range.cloneRange(); + endRange.collapse(false); + startCaret = $('<span/>').addClass('simditor-caret-start'); + endCaret = $('<span/>').addClass('simditor-caret-end'); + endRange.insertNode(endCaret[0]); + range.insertNode(startCaret[0]); + this.clear(); + return this._selectionSaved = true; + }; + + Selection.prototype.restore = function() { + var endCaret, endContainer, endOffset, range, startCaret, startContainer, startOffset; + if (!this._selectionSaved) { + return false; + } + startCaret = this.editor.body.find('.simditor-caret-start'); + endCaret = this.editor.body.find('.simditor-caret-end'); + if (startCaret.length && endCaret.length) { + startContainer = startCaret.parent(); + startOffset = startContainer.contents().index(startCaret); + endContainer = endCaret.parent(); + endOffset = endContainer.contents().index(endCaret); + if (startContainer[0] === endContainer[0]) { + endOffset -= 1; + } + range = document.createRange(); + range.setStart(startContainer.get(0), startOffset); + range.setEnd(endContainer.get(0), endOffset); + startCaret.remove(); + endCaret.remove(); + this.range(range); + } else { + startCaret.remove(); + endCaret.remove(); + } + this._selectionSaved = false; + return range; + }; + + return Selection; + +})(SimpleModule); + +Formatter = (function(superClass) { + extend(Formatter, superClass); + + function Formatter() { + return Formatter.__super__.constructor.apply(this, arguments); + } + + Formatter.pluginName = 'Formatter'; + + Formatter.prototype.opts = { + allowedTags: [], + allowedAttributes: {}, + allowedStyles: {} + }; + + Formatter.prototype._init = function() { + this.editor = this._module; + this._allowedTags = $.merge(['br', 'span', 'a', 'img', 'b', 'strong', 'i', 'strike', 'u', 'font', 'p', 'ul', 'ol', 'li', 'blockquote', 'pre', 'code', 'h1', 'h2', 'h3', 'h4', 'hr'], this.opts.allowedTags); + this._allowedAttributes = $.extend({ + img: ['src', 'alt', 'width', 'height', 'data-non-image'], + a: ['href', 'target'], + font: ['color'], + code: ['class'] + }, this.opts.allowedAttributes); + this._allowedStyles = $.extend({ + span: ['color', 'font-size'], + b: ['color', 'font-size'], + i: ['color', 'font-size'], + strong: ['color', 'font-size'], + strike: ['color', 'font-size'], + u: ['color', 'font-size'], + p: ['margin-left', 'text-align'], + h1: ['margin-left', 'text-align'], + h2: ['margin-left', 'text-align'], + h3: ['margin-left', 'text-align'], + h4: ['margin-left', 'text-align'] + }, this.opts.allowedStyles); + return this.editor.body.on('click', 'a', function(e) { + return false; + }); + }; + + Formatter.prototype.decorate = function($el) { + if ($el == null) { + $el = this.editor.body; + } + this.editor.trigger('decorate', [$el]); + return $el; + }; + + Formatter.prototype.undecorate = function($el) { + if ($el == null) { + $el = this.editor.body.clone(); + } + this.editor.trigger('undecorate', [$el]); + return $el; + }; + + Formatter.prototype.autolink = function($el) { + var $link, $node, findLinkNode, k, lastIndex, len, linkNodes, match, re, replaceEls, subStr, text, uri; + if ($el == null) { + $el = this.editor.body; + } + linkNodes = []; + findLinkNode = function($parentNode) { + return $parentNode.contents().each(function(i, node) { + var $node, text; + $node = $(node); + if ($node.is('a') || $node.closest('a, pre', $el).length) { + return; + } + if (!$node.is('iframe') && $node.contents().length) { + return findLinkNode($node); + } else if ((text = $node.text()) && /https?:\/\/|www\./ig.test(text)) { + return linkNodes.push($node); + } + }); + }; + findLinkNode($el); + re = /(https?:\/\/|www\.)[\w\-\.\?&=\/#%:,@\!\+]+/ig; + for (k = 0, len = linkNodes.length; k < len; k++) { + $node = linkNodes[k]; + text = $node.text(); + replaceEls = []; + match = null; + lastIndex = 0; + while ((match = re.exec(text)) !== null) { + subStr = text.substring(lastIndex, match.index); + replaceEls.push(document.createTextNode(subStr)); + lastIndex = re.lastIndex; + uri = /^(http(s)?:\/\/|\/)/.test(match[0]) ? match[0] : 'http://' + match[0]; + $link = $("<a href=\"" + uri + "\" rel=\"nofollow\"></a>").text(match[0]); + replaceEls.push($link[0]); + } + replaceEls.push(document.createTextNode(text.substring(lastIndex))); + $node.replaceWith($(replaceEls)); + } + return $el; + }; + + Formatter.prototype.format = function($el) { + var $node, blockNode, k, l, len, len1, n, node, ref, ref1; + if ($el == null) { + $el = this.editor.body; + } + if ($el.is(':empty')) { + $el.append('<p>' + this.editor.util.phBr + '</p>'); + return $el; + } + ref = $el.contents(); + for (k = 0, len = ref.length; k < len; k++) { + n = ref[k]; + this.cleanNode(n, true); + } + ref1 = $el.contents(); + for (l = 0, len1 = ref1.length; l < len1; l++) { + node = ref1[l]; + $node = $(node); + if ($node.is('br')) { + if (typeof blockNode !== "undefined" && blockNode !== null) { + blockNode = null; + } + $node.remove(); + } else if (this.editor.util.isBlockNode(node)) { + if ($node.is('li')) { + if (blockNode && blockNode.is('ul, ol')) { + blockNode.append(node); + } else { + blockNode = $('<ul/>').insertBefore(node); + blockNode.append(node); + } + } else { + blockNode = null; + } + } else { + if (!blockNode || blockNode.is('ul, ol')) { + blockNode = $('<p/>').insertBefore(node); + } + blockNode.append(node); + if (this.editor.util.isEmptyNode(blockNode)) { + blockNode.append(this.editor.util.phBr); + } + } + } + return $el; + }; + + Formatter.prototype.cleanNode = function(node, recursive) { + var $blockEls, $childImg, $node, $p, $td, allowedAttributes, attr, contents, isDecoration, k, l, len, len1, n, ref, ref1, text, textNode; + $node = $(node); + if (!($node.length > 0)) { + return; + } + if ($node[0].nodeType === 3) { + text = $node.text().replace(/(\r\n|\n|\r)/gm, ''); + if (text) { + textNode = document.createTextNode(text); + $node.replaceWith(textNode); + } else { + $node.remove(); + } + return; + } + contents = $node.is('iframe') ? null : $node.contents(); + isDecoration = this.editor.util.isDecoratedNode($node); + if ($node.is(this._allowedTags.join(',')) || isDecoration) { + if ($node.is('a') && ($childImg = $node.find('img')).length > 0) { + $node.replaceWith($childImg); + $node = $childImg; + contents = null; + } + if ($node.is('td') && ($blockEls = $node.find(this.editor.util.blockNodes.join(','))).length > 0) { + $blockEls.each((function(_this) { + return function(i, blockEl) { + return $(blockEl).contents().unwrap(); + }; + })(this)); + contents = $node.contents(); + } + if ($node.is('img') && $node.hasClass('uploading')) { + $node.remove(); + } + if (!isDecoration) { + allowedAttributes = this._allowedAttributes[$node[0].tagName.toLowerCase()]; + ref = $.makeArray($node[0].attributes); + for (k = 0, len = ref.length; k < len; k++) { + attr = ref[k]; + if (attr.name === 'style') { + continue; + } + if (!((allowedAttributes != null) && (ref1 = attr.name, indexOf.call(allowedAttributes, ref1) >= 0))) { + $node.removeAttr(attr.name); + } + } + this._cleanNodeStyles($node); + if ($node.is('span')) { + if ($node[0].attributes.length === 0) { + $node.contents().first().unwrap(); + } + if ($node[0].style.length === 2 && $node[0].style.color === 'rgb(51, 51, 51)' && $node[0].style.fontSize === '16px') { + $node.contents().unwrap(); + } + } + } + } else if ($node[0].nodeType === 1 && !$node.is(':empty')) { + if ($node.is('div, article, dl, header, footer, tr')) { + $node.append('<br/>'); + contents.first().unwrap(); + } else if ($node.is('table')) { + $p = $('<p/>'); + $node.find('tr').each(function(i, tr) { + return $p.append($(tr).text() + '<br/>'); + }); + $node.replaceWith($p); + contents = null; + } else if ($node.is('thead, tfoot')) { + $node.remove(); + contents = null; + } else if ($node.is('th')) { + $td = $('<td/>').append($node.contents()); + $node.replaceWith($td); + } else { + contents.first().unwrap(); + } + } else { + $node.remove(); + contents = null; + } + if (recursive && (contents != null) && !$node.is('pre')) { + for (l = 0, len1 = contents.length; l < len1; l++) { + n = contents[l]; + this.cleanNode(n, true); + } + } + return null; + }; + + Formatter.prototype._cleanNodeStyles = function($node) { + var allowedStyles, k, len, pair, ref, ref1, style, styleStr, styles; + styleStr = $node.attr('style'); + if (!styleStr) { + return; + } + $node.removeAttr('style'); + allowedStyles = this._allowedStyles[$node[0].tagName.toLowerCase()]; + if (!(allowedStyles && allowedStyles.length > 0)) { + return $node; + } + styles = {}; + ref = styleStr.split(';'); + for (k = 0, len = ref.length; k < len; k++) { + style = ref[k]; + style = $.trim(style); + pair = style.split(':'); + if (pair.length !== 2) { + continue; + } + if (pair[0] === 'font-size' && pair[1].indexOf('px') > 0) { + if (parseInt(pair[1], 10) < 12) { + continue; + } + } + if (ref1 = pair[0], indexOf.call(allowedStyles, ref1) >= 0) { + styles[$.trim(pair[0])] = $.trim(pair[1]); + } + } + if (Object.keys(styles).length > 0) { + $node.css(styles); + } + return $node; + }; + + Formatter.prototype.clearHtml = function(html, lineBreak) { + var container, contents, result; + if (lineBreak == null) { + lineBreak = true; + } + container = $('<div/>').append(html); + contents = container.contents(); + result = ''; + contents.each((function(_this) { + return function(i, node) { + var $node, children; + if (node.nodeType === 3) { + return result += node.nodeValue; + } else if (node.nodeType === 1) { + $node = $(node); + children = $node.is('iframe') ? null : $node.contents(); + if (children && children.length > 0) { + result += _this.clearHtml(children); + } + if (lineBreak && i < contents.length - 1 && $node.is('br, p, div, li,tr, pre, address, artticle, aside, dl, figcaption, footer, h1, h2,h3, h4, header')) { + return result += '\n'; + } + } + }; + })(this)); + return result; + }; + + Formatter.prototype.beautify = function($contents) { + var uselessP; + uselessP = function($el) { + return !!($el.is('p') && !$el.text() && $el.children(':not(br)').length < 1); + }; + return $contents.each(function(i, el) { + var $el, invalid; + $el = $(el); + invalid = $el.is(':not(img, br, col, td, hr, [class^="simditor-"]):empty'); + if (invalid || uselessP($el)) { + $el.remove(); + } + return $el.find(':not(img, br, col, td, hr, [class^="simditor-"]):empty').remove(); + }); + }; + + return Formatter; + +})(SimpleModule); + +InputManager = (function(superClass) { + extend(InputManager, superClass); + + function InputManager() { + return InputManager.__super__.constructor.apply(this, arguments); + } + + InputManager.pluginName = 'InputManager'; + + InputManager.prototype._modifierKeys = [16, 17, 18, 91, 93, 224]; + + InputManager.prototype._arrowKeys = [37, 38, 39, 40]; + + InputManager.prototype._init = function() { + var selectAllKey, submitKey; + this.editor = this._module; + this.throttledValueChanged = this.editor.util.throttle((function(_this) { + return function(params) { + return setTimeout(function() { + return _this.editor.trigger('valuechanged', params); + }, 10); + }; + })(this), 300); + this.throttledSelectionChanged = this.editor.util.throttle((function(_this) { + return function() { + return _this.editor.trigger('selectionchanged'); + }; + })(this), 50); + $(document).on('selectionchange.simditor' + this.editor.id, (function(_this) { + return function(e) { + var triggerEvent; + if (!(_this.focused && !_this.editor.clipboard.pasting)) { + return; + } + triggerEvent = function() { + if (_this._selectionTimer) { + clearTimeout(_this._selectionTimer); + _this._selectionTimer = null; + } + if (_this.editor.selection._selection.rangeCount > 0) { + return _this.throttledSelectionChanged(); + } else { + return _this._selectionTimer = setTimeout(function() { + _this._selectionTimer = null; + if (_this.focused) { + return triggerEvent(); + } + }, 10); + } + }; + return triggerEvent(); + }; + })(this)); + this.editor.on('valuechanged', (function(_this) { + return function() { + var $rootBlocks; + _this.lastCaretPosition = null; + $rootBlocks = _this.editor.body.children().filter(function(i, node) { + return _this.editor.util.isBlockNode(node); + }); + if (_this.focused && $rootBlocks.length === 0) { + _this.editor.selection.save(); + _this.editor.formatter.format(); + _this.editor.selection.restore(); + } + _this.editor.body.find('hr, pre, .simditor-table').each(function(i, el) { + var $el, formatted; + $el = $(el); + if ($el.parent().is('blockquote') || $el.parent()[0] === _this.editor.body[0]) { + formatted = false; + if ($el.next().length === 0) { + $('<p/>').append(_this.editor.util.phBr).insertAfter($el); + formatted = true; + } + if ($el.prev().length === 0) { + $('<p/>').append(_this.editor.util.phBr).insertBefore($el); + formatted = true; + } + if (formatted) { + return _this.throttledValueChanged(); + } + } + }); + _this.editor.body.find('pre:empty').append(_this.editor.util.phBr); + if (!_this.editor.util.support.onselectionchange && _this.focused) { + return _this.throttledSelectionChanged(); + } + }; + })(this)); + this.editor.body.on('keydown', $.proxy(this._onKeyDown, this)).on('keypress', $.proxy(this._onKeyPress, this)).on('keyup', $.proxy(this._onKeyUp, this)).on('mouseup', $.proxy(this._onMouseUp, this)).on('focus', $.proxy(this._onFocus, this)).on('blur', $.proxy(this._onBlur, this)).on('drop', $.proxy(this._onDrop, this)).on('input', $.proxy(this._onInput, this)); + if (this.editor.util.browser.firefox) { + this.editor.hotkeys.add('cmd+left', (function(_this) { + return function(e) { + e.preventDefault(); + _this.editor.selection._selection.modify('move', 'backward', 'lineboundary'); + return false; + }; + })(this)); + this.editor.hotkeys.add('cmd+right', (function(_this) { + return function(e) { + e.preventDefault(); + _this.editor.selection._selection.modify('move', 'forward', 'lineboundary'); + return false; + }; + })(this)); + selectAllKey = this.editor.util.os.mac ? 'cmd+a' : 'ctrl+a'; + this.editor.hotkeys.add(selectAllKey, (function(_this) { + return function(e) { + var $children, firstBlock, lastBlock, range; + $children = _this.editor.body.children(); + if (!($children.length > 0)) { + return; + } + firstBlock = $children.first().get(0); + lastBlock = $children.last().get(0); + range = document.createRange(); + range.setStart(firstBlock, 0); + range.setEnd(lastBlock, _this.editor.util.getNodeLength(lastBlock)); + _this.editor.selection.range(range); + return false; + }; + })(this)); + } + submitKey = this.editor.util.os.mac ? 'cmd+enter' : 'ctrl+enter'; + return this.editor.hotkeys.add(submitKey, (function(_this) { + return function(e) { + _this.editor.sync(); + _this.editor.el.closest('form').find('button:submit').click(); + return false; + }; + })(this)); + }; + + InputManager.prototype._onFocus = function(e) { + if (this.editor.clipboard.pasting) { + return; + } + this.editor.el.addClass('focus').removeClass('error'); + this.focused = true; + return setTimeout((function(_this) { + return function() { + var $blockEl, range; + range = _this.editor.selection._selection.getRangeAt(0); + if (range.startContainer === _this.editor.body[0]) { + if (_this.lastCaretPosition) { + _this.editor.undoManager.caretPosition(_this.lastCaretPosition); + } else { + $blockEl = _this.editor.body.children().first(); + range = document.createRange(); + _this.editor.selection.setRangeAtStartOf($blockEl, range); + } + } + _this.lastCaretPosition = null; + _this.editor.triggerHandler('focus'); + if (!_this.editor.util.support.onselectionchange) { + return _this.throttledSelectionChanged(); + } + }; + })(this), 0); + }; + + InputManager.prototype._onBlur = function(e) { + var ref; + if (this.editor.clipboard.pasting) { + return; + } + this.editor.el.removeClass('focus'); + this.editor.sync(); + this.focused = false; + this.lastCaretPosition = (ref = this.editor.undoManager.currentState()) != null ? ref.caret : void 0; + return this.editor.triggerHandler('blur'); + }; + + InputManager.prototype._onMouseUp = function(e) { + if (!this.editor.util.support.onselectionchange) { + return this.throttledSelectionChanged(); + } + }; + + InputManager.prototype._onKeyDown = function(e) { + var ref, ref1; + if (this.editor.triggerHandler(e) === false) { + return false; + } + if (this.editor.hotkeys.respondTo(e)) { + return; + } + if (this.editor.keystroke.respondTo(e)) { + this.throttledValueChanged(); + return false; + } + if ((ref = e.which, indexOf.call(this._modifierKeys, ref) >= 0) || (ref1 = e.which, indexOf.call(this._arrowKeys, ref1) >= 0)) { + return; + } + if (this.editor.util.metaKey(e) && e.which === 86) { + return; + } + if (!this.editor.util.support.oninput) { + this.throttledValueChanged(['typing']); + } + return null; + }; + + InputManager.prototype._onKeyPress = function(e) { + if (this.editor.triggerHandler(e) === false) { + return false; + } + }; + + InputManager.prototype._onKeyUp = function(e) { + var p, ref; + if (this.editor.triggerHandler(e) === false) { + return false; + } + if (!this.editor.util.support.onselectionchange && (ref = e.which, indexOf.call(this._arrowKeys, ref) >= 0)) { + this.throttledValueChanged(); + return; + } + if ((e.which === 8 || e.which === 46) && this.editor.util.isEmptyNode(this.editor.body)) { + this.editor.body.empty(); + p = $('<p/>').append(this.editor.util.phBr).appendTo(this.editor.body); + this.editor.selection.setRangeAtStartOf(p); + } + }; + + InputManager.prototype._onDrop = function(e) { + if (this.editor.triggerHandler(e) === false) { + return false; + } + return this.throttledValueChanged(); + }; + + InputManager.prototype._onInput = function(e) { + return this.throttledValueChanged(['oninput']); + }; + + return InputManager; + +})(SimpleModule); + +Keystroke = (function(superClass) { + extend(Keystroke, superClass); + + function Keystroke() { + return Keystroke.__super__.constructor.apply(this, arguments); + } + + Keystroke.pluginName = 'Keystroke'; + + Keystroke.prototype._init = function() { + this.editor = this._module; + this._keystrokeHandlers = {}; + return this._initKeystrokeHandlers(); + }; + + Keystroke.prototype.add = function(key, node, handler) { + key = key.toLowerCase(); + key = this.editor.hotkeys.constructor.aliases[key] || key; + if (!this._keystrokeHandlers[key]) { + this._keystrokeHandlers[key] = {}; + } + return this._keystrokeHandlers[key][node] = handler; + }; + + Keystroke.prototype.respondTo = function(e) { + var base, key, ref, result; + key = (ref = this.editor.hotkeys.constructor.keyNameMap[e.which]) != null ? ref.toLowerCase() : void 0; + if (!key) { + return; + } + if (key in this._keystrokeHandlers) { + result = typeof (base = this._keystrokeHandlers[key])['*'] === "function" ? base['*'](e) : void 0; + if (!result) { + this.editor.selection.startNodes().each((function(_this) { + return function(i, node) { + var handler, ref1; + if (node.nodeType !== Node.ELEMENT_NODE) { + return; + } + handler = (ref1 = _this._keystrokeHandlers[key]) != null ? ref1[node.tagName.toLowerCase()] : void 0; + result = typeof handler === "function" ? handler(e, $(node)) : void 0; + if (result === true || result === false) { + return false; + } + }; + })(this)); + } + if (result) { + return true; + } + } + }; + + Keystroke.prototype._initKeystrokeHandlers = function() { + var titleEnterHandler; + if (this.editor.util.browser.safari) { + this.add('enter', '*', (function(_this) { + return function(e) { + var $blockEl, $br; + if (!e.shiftKey) { + return; + } + $blockEl = _this.editor.selection.blockNodes().last(); + if ($blockEl.is('pre')) { + return; + } + $br = $('<br/>'); + if (_this.editor.selection.rangeAtEndOf($blockEl)) { + _this.editor.selection.insertNode($br); + _this.editor.selection.insertNode($('<br/>')); + _this.editor.selection.setRangeBefore($br); + } else { + _this.editor.selection.insertNode($br); + } + return true; + }; + })(this)); + } + if (this.editor.util.browser.webkit || this.editor.util.browser.msie) { + titleEnterHandler = (function(_this) { + return function(e, $node) { + var $p; + if (!_this.editor.selection.rangeAtEndOf($node)) { + return; + } + $p = $('<p/>').append(_this.editor.util.phBr).insertAfter($node); + _this.editor.selection.setRangeAtStartOf($p); + return true; + }; + })(this); + this.add('enter', 'h1', titleEnterHandler); + this.add('enter', 'h2', titleEnterHandler); + this.add('enter', 'h3', titleEnterHandler); + this.add('enter', 'h4', titleEnterHandler); + this.add('enter', 'h5', titleEnterHandler); + this.add('enter', 'h6', titleEnterHandler); + } + this.add('backspace', '*', (function(_this) { + return function(e) { + var $blockEl, $prevBlockEl, $rootBlock, isWebkit; + $rootBlock = _this.editor.selection.rootNodes().first(); + $prevBlockEl = $rootBlock.prev(); + if ($prevBlockEl.is('hr') && _this.editor.selection.rangeAtStartOf($rootBlock)) { + _this.editor.selection.save(); + $prevBlockEl.remove(); + _this.editor.selection.restore(); + return true; + } + $blockEl = _this.editor.selection.blockNodes().last(); + if ($blockEl.is('.simditor-resize-handle') && $rootBlock.is('.simditor-table')) { + e.preventDefault(); + $rootBlock.remove(); + _this.editor.selection.setRangeAtEndOf($prevBlockEl); + } + if ($prevBlockEl.is('.simditor-table') && !$blockEl.is('table') && _this.editor.util.isEmptyNode($blockEl)) { + e.preventDefault(); + $blockEl.remove(); + _this.editor.selection.setRangeAtEndOf($prevBlockEl); + } + isWebkit = _this.editor.util.browser.webkit; + if (isWebkit && _this.editor.selection.rangeAtStartOf($blockEl)) { + _this.editor.selection.save(); + _this.editor.formatter.cleanNode($blockEl, true); + _this.editor.selection.restore(); + return null; + } + }; + })(this)); + this.add('enter', 'div', (function(_this) { + return function(e, $node) { + var $blockEl, $p; + if ($node.is('.simditor-table')) { + $blockEl = _this.editor.selection.blockNodes().last(); + if ($blockEl.is('.simditor-resize-handle')) { + e.preventDefault(); + $p = $('<p/>').append(_this.editor.util.phBr).insertAfter($node); + return _this.editor.selection.setRangeAtStartOf($p); + } + } + }; + })(this)); + this.add('enter', 'li', (function(_this) { + return function(e, $node) { + var $cloneNode, listEl, newBlockEl, newListEl; + $cloneNode = $node.clone(); + $cloneNode.find('ul, ol').remove(); + if (!(_this.editor.util.isEmptyNode($cloneNode) && $node.is(_this.editor.selection.blockNodes().last()))) { + return; + } + listEl = $node.parent(); + if ($node.next('li').length > 0) { + if (!_this.editor.util.isEmptyNode($node)) { + return; + } + if (listEl.parent('li').length > 0) { + newBlockEl = $('<li/>').append(_this.editor.util.phBr).insertAfter(listEl.parent('li')); + newListEl = $('<' + listEl[0].tagName + '/>').append($node.nextAll('li')); + newBlockEl.append(newListEl); + } else { + newBlockEl = $('<p/>').append(_this.editor.util.phBr).insertAfter(listEl); + newListEl = $('<' + listEl[0].tagName + '/>').append($node.nextAll('li')); + newBlockEl.after(newListEl); + } + } else { + if (listEl.parent('li').length > 0) { + newBlockEl = $('<li/>').insertAfter(listEl.parent('li')); + if ($node.contents().length > 0) { + newBlockEl.append($node.contents()); + } else { + newBlockEl.append(_this.editor.util.phBr); + } + } else { + newBlockEl = $('<p/>').append(_this.editor.util.phBr).insertAfter(listEl); + if ($node.children('ul, ol').length > 0) { + newBlockEl.after($node.children('ul, ol')); + } + } + } + if ($node.prev('li').length) { + $node.remove(); + } else { + if ($node.prev('ul').length || $node.prev('ol').length) { + $node.remove(); + } else { + listEl.remove(); + } + } + _this.editor.selection.setRangeAtStartOf(newBlockEl); + return true; + }; + })(this)); + this.add('enter', 'pre', (function(_this) { + return function(e, $node) { + var $p, breakNode, range; + e.preventDefault(); + if (e.shiftKey) { + $p = $('<p/>').append(_this.editor.util.phBr).insertAfter($node); + _this.editor.selection.setRangeAtStartOf($p); + return true; + } + range = _this.editor.selection.range(); + breakNode = null; + range.deleteContents(); + if (!_this.editor.util.browser.msie && _this.editor.selection.rangeAtEndOf($node)) { + breakNode = document.createTextNode('\n\n'); + } else { + breakNode = document.createTextNode('\n'); + } + range.insertNode(breakNode); + range.setEnd(breakNode, 1); + range.collapse(false); + _this.editor.selection.range(range); + return true; + }; + })(this)); + this.add('enter', 'blockquote', (function(_this) { + return function(e, $node) { + var $closestBlock, range; + $closestBlock = _this.editor.selection.blockNodes().last(); + if (!($closestBlock.is('p') && !$closestBlock.next().length && _this.editor.util.isEmptyNode($closestBlock))) { + return; + } + $node.after($closestBlock); + range = document.createRange(); + _this.editor.selection.setRangeAtStartOf($closestBlock, range); + return true; + }; + })(this)); + this.add('backspace', 'li', (function(_this) { + return function(e, $node) { + var $br, $childList, $newLi, $prevChildList, $prevNode, $textNode, isFF, range, text; + $childList = $node.children('ul, ol'); + $prevNode = $node.prev('li'); + if (!($childList.length > 0 && $prevNode.length > 0)) { + return false; + } + text = ''; + $textNode = null; + $node.contents().each(function(i, n) { + if (n.nodeType === 1 && /UL|OL/.test(n.nodeName)) { + return false; + } + if (n.nodeType === 1 && /BR/.test(n.nodeName)) { + return; + } + if (n.nodeType === 3 && n.nodeValue) { + text += n.nodeValue; + } else if (n.nodeType === 1) { + text += $(n).text(); + } + return $textNode = $(n); + }); + isFF = _this.editor.util.browser.firefox && !$textNode.next('br').length; + if ($textNode && text.length === 1 && isFF) { + $br = $(_this.editor.util.phBr).insertAfter($textNode); + $textNode.remove(); + _this.editor.selection.setRangeBefore($br); + return true; + } else if (text.length > 0) { + return false; + } + range = document.createRange(); + $prevChildList = $prevNode.children('ul, ol'); + if ($prevChildList.length > 0) { + $newLi = $('<li/>').append(_this.editor.util.phBr).appendTo($prevChildList); + $prevChildList.append($childList.children('li')); + $node.remove(); + _this.editor.selection.setRangeAtEndOf($newLi, range); + } else { + _this.editor.selection.setRangeAtEndOf($prevNode, range); + $prevNode.append($childList); + $node.remove(); + _this.editor.selection.range(range); + } + return true; + }; + })(this)); + this.add('backspace', 'pre', (function(_this) { + return function(e, $node) { + var $newNode, codeStr, range; + if (!_this.editor.selection.rangeAtStartOf($node)) { + return; + } + codeStr = $node.html().replace('\n', '<br/>') || _this.editor.util.phBr; + $newNode = $('<p/>').append(codeStr).insertAfter($node); + $node.remove(); + range = document.createRange(); + _this.editor.selection.setRangeAtStartOf($newNode, range); + return true; + }; + })(this)); + return this.add('backspace', 'blockquote', (function(_this) { + return function(e, $node) { + var $firstChild, range; + if (!_this.editor.selection.rangeAtStartOf($node)) { + return; + } + $firstChild = $node.children().first().unwrap(); + range = document.createRange(); + _this.editor.selection.setRangeAtStartOf($firstChild, range); + return true; + }; + })(this)); + }; + + return Keystroke; + +})(SimpleModule); + +UndoManager = (function(superClass) { + extend(UndoManager, superClass); + + function UndoManager() { + return UndoManager.__super__.constructor.apply(this, arguments); + } + + UndoManager.pluginName = 'UndoManager'; + + UndoManager.prototype._index = -1; + + UndoManager.prototype._capacity = 20; + + UndoManager.prototype._startPosition = null; + + UndoManager.prototype._endPosition = null; + + UndoManager.prototype._init = function() { + var redoShortcut, undoShortcut; + this.editor = this._module; + this._stack = []; + if (this.editor.util.os.mac) { + undoShortcut = 'cmd+z'; + redoShortcut = 'shift+cmd+z'; + } else if (this.editor.util.os.win) { + undoShortcut = 'ctrl+z'; + redoShortcut = 'ctrl+y'; + } else { + undoShortcut = 'ctrl+z'; + redoShortcut = 'shift+ctrl+z'; + } + this.editor.hotkeys.add(undoShortcut, (function(_this) { + return function(e) { + e.preventDefault(); + _this.undo(); + return false; + }; + })(this)); + this.editor.hotkeys.add(redoShortcut, (function(_this) { + return function(e) { + e.preventDefault(); + _this.redo(); + return false; + }; + })(this)); + this.throttledPushState = this.editor.util.throttle((function(_this) { + return function() { + return _this._pushUndoState(); + }; + })(this), 2000); + this.editor.on('valuechanged', (function(_this) { + return function(e, src) { + if (src === 'undo' || src === 'redo') { + return; + } + return _this.throttledPushState(); + }; + })(this)); + this.editor.on('selectionchanged', (function(_this) { + return function(e) { + _this.resetCaretPosition(); + return _this.update(); + }; + })(this)); + this.editor.on('focus', (function(_this) { + return function(e) { + if (_this._stack.length === 0) { + return _this._pushUndoState(); + } + }; + })(this)); + return this.editor.on('blur', (function(_this) { + return function(e) { + return _this.resetCaretPosition(); + }; + })(this)); + }; + + UndoManager.prototype.resetCaretPosition = function() { + this._startPosition = null; + return this._endPosition = null; + }; + + UndoManager.prototype.startPosition = function() { + if (this.editor.selection._range) { + this._startPosition || (this._startPosition = this._getPosition('start')); + } + return this._startPosition; + }; + + UndoManager.prototype.endPosition = function() { + if (this.editor.selection._range) { + this._endPosition || (this._endPosition = (function(_this) { + return function() { + var range; + range = _this.editor.selection.range(); + if (range.collapsed) { + return _this._startPosition; + } + return _this._getPosition('end'); + }; + })(this)()); + } + return this._endPosition; + }; + + UndoManager.prototype._pushUndoState = function() { + var caret; + if (this.editor.triggerHandler('pushundostate') === false) { + return; + } + caret = this.caretPosition(); + if (!caret.start) { + return; + } + this._index += 1; + this._stack.length = this._index; + this._stack.push({ + html: this.editor.body.html(), + caret: this.caretPosition() + }); + if (this._stack.length > this._capacity) { + this._stack.shift(); + return this._index -= 1; + } + }; + + UndoManager.prototype.currentState = function() { + if (this._stack.length && this._index > -1) { + return this._stack[this._index]; + } else { + return null; + } + }; + + UndoManager.prototype.undo = function() { + var state; + if (this._index < 1 || this._stack.length < 2) { + return; + } + this.editor.hidePopover(); + this._index -= 1; + state = this._stack[this._index]; + this.editor.body.get(0).innerHTML = state.html; + this.caretPosition(state.caret); + this.editor.body.find('.selected').removeClass('selected'); + this.editor.sync(); + return this.editor.trigger('valuechanged', ['undo']); + }; + + UndoManager.prototype.redo = function() { + var state; + if (this._index < 0 || this._stack.length < this._index + 2) { + return; + } + this.editor.hidePopover(); + this._index += 1; + state = this._stack[this._index]; + this.editor.body.get(0).innerHTML = state.html; + this.caretPosition(state.caret); + this.editor.body.find('.selected').removeClass('selected'); + this.editor.sync(); + return this.editor.trigger('valuechanged', ['redo']); + }; + + UndoManager.prototype.update = function() { + var currentState; + currentState = this.currentState(); + if (!currentState) { + return; + } + currentState.html = this.editor.body.html(); + return currentState.caret = this.caretPosition(); + }; + + UndoManager.prototype._getNodeOffset = function(node, index) { + var $parent, merging, offset; + if ($.isNumeric(index)) { + $parent = $(node); + } else { + $parent = $(node).parent(); + } + offset = 0; + merging = false; + $parent.contents().each(function(i, child) { + if (node === child || (index === i && i === 0)) { + return false; + } + if (child.nodeType === Node.TEXT_NODE) { + if (!merging && child.nodeValue.length > 0) { + offset += 1; + merging = true; + } + } else { + offset += 1; + merging = false; + } + if (index - 1 === i) { + return false; + } + return null; + }); + return offset; + }; + + UndoManager.prototype._getPosition = function(type) { + var $nodes, node, nodes, offset, position, prevNode, range; + if (type == null) { + type = 'start'; + } + range = this.editor.selection.range(); + offset = range[type + "Offset"]; + $nodes = this.editor.selection[type + "Nodes"](); + node = $nodes.first()[0]; + if (node.nodeType === Node.TEXT_NODE) { + prevNode = node.previousSibling; + while (prevNode && prevNode.nodeType === Node.TEXT_NODE) { + node = prevNode; + offset += this.editor.util.getNodeLength(prevNode); + prevNode = prevNode.previousSibling; + } + nodes = $nodes.get(); + nodes[0] = node; + $nodes = $(nodes); + } else { + offset = this._getNodeOffset(node, offset); + } + position = [offset]; + $nodes.each((function(_this) { + return function(i, node) { + return position.unshift(_this._getNodeOffset(node)); + }; + })(this)); + return position; + }; + + UndoManager.prototype._getNodeByPosition = function(position) { + var child, childNodes, i, k, len, node, offset, ref; + node = this.editor.body[0]; + ref = position.slice(0, position.length - 1); + for (i = k = 0, len = ref.length; k < len; i = ++k) { + offset = ref[i]; + childNodes = node.childNodes; + if (offset > childNodes.length - 1) { + if (i === position.length - 2 && $(node).is(':empty')) { + child = document.createTextNode(''); + node.appendChild(child); + childNodes = node.childNodes; + } else { + node = null; + break; + } + } + node = childNodes[offset]; + } + return node; + }; + + UndoManager.prototype.caretPosition = function(caret) { + var endContainer, endOffset, range, startContainer, startOffset; + if (!caret) { + range = this.editor.selection.range(); + caret = this.editor.inputManager.focused && (range != null) ? { + start: this.startPosition(), + end: this.endPosition(), + collapsed: range.collapsed + } : {}; + return caret; + } else { + if (!caret.start) { + return; + } + startContainer = this._getNodeByPosition(caret.start); + startOffset = caret.start[caret.start.length - 1]; + if (caret.collapsed) { + endContainer = startContainer; + endOffset = startOffset; + } else { + endContainer = this._getNodeByPosition(caret.end); + endOffset = caret.start[caret.start.length - 1]; + } + if (!startContainer || !endContainer) { + if (typeof console !== "undefined" && console !== null) { + if (typeof console.info === "function") { + console.info('simditor: invalid caret state'); + } + } + return; + } + range = document.createRange(); + range.setStart(startContainer, startOffset); + range.setEnd(endContainer, endOffset); + return this.editor.selection.range(range); + } + }; + + return UndoManager; + +})(SimpleModule); + +Util = (function(superClass) { + extend(Util, superClass); + + function Util() { + return Util.__super__.constructor.apply(this, arguments); + } + + Util.pluginName = 'Util'; + + Util.prototype._init = function() { + this.editor = this._module; + if (this.browser.msie && this.browser.version < 11) { + return this.phBr = ''; + } + }; + + Util.prototype.phBr = '<br/>'; + + Util.prototype.os = (function() { + var os; + os = {}; + if (/Mac/.test(navigator.appVersion)) { + os.mac = true; + } else if (/Linux/.test(navigator.appVersion)) { + os.linux = true; + } else if (/Win/.test(navigator.appVersion)) { + os.win = true; + } else if (/X11/.test(navigator.appVersion)) { + os.unix = true; + } + if (/Mobi/.test(navigator.appVersion)) { + os.mobile = true; + } + return os; + })(); + + Util.prototype.browser = (function() { + var chrome, edge, firefox, ie, ref, ref1, ref2, ref3, ref4, safari, ua; + ua = navigator.userAgent; + ie = /(msie|trident)/i.test(ua); + chrome = /chrome|crios/i.test(ua); + safari = /safari/i.test(ua) && !chrome; + firefox = /firefox/i.test(ua); + edge = /edge/i.test(ua); + if (ie) { + return { + msie: true, + version: ((ref = ua.match(/(msie |rv:)(\d+(\.\d+)?)/i)) != null ? ref[2] : void 0) * 1 + }; + } else if (edge) { + return { + edge: true, + webkit: true, + version: ((ref1 = ua.match(/edge\/(\d+(\.\d+)?)/i)) != null ? ref1[1] : void 0) * 1 + }; + } else if (chrome) { + return { + webkit: true, + chrome: true, + version: ((ref2 = ua.match(/(?:chrome|crios)\/(\d+(\.\d+)?)/i)) != null ? ref2[1] : void 0) * 1 + }; + } else if (safari) { + return { + webkit: true, + safari: true, + version: ((ref3 = ua.match(/version\/(\d+(\.\d+)?)/i)) != null ? ref3[1] : void 0) * 1 + }; + } else if (firefox) { + return { + mozilla: true, + firefox: true, + version: ((ref4 = ua.match(/firefox\/(\d+(\.\d+)?)/i)) != null ? ref4[1] : void 0) * 1 + }; + } else { + return {}; + } + })(); + + Util.prototype.support = (function() { + return { + onselectionchange: (function() { + var e, onselectionchange; + onselectionchange = document.onselectionchange; + if (onselectionchange !== void 0) { + try { + document.onselectionchange = 0; + return document.onselectionchange === null; + } catch (_error) { + e = _error; + } finally { + document.onselectionchange = onselectionchange; + } + } + return false; + })(), + oninput: (function() { + return !/(msie|trident)/i.test(navigator.userAgent); + })() + }; + })(); + + Util.prototype.reflow = function(el) { + if (el == null) { + el = document; + } + return $(el)[0].offsetHeight; + }; + + Util.prototype.metaKey = function(e) { + var isMac; + isMac = /Mac/.test(navigator.userAgent); + if (isMac) { + return e.metaKey; + } else { + return e.ctrlKey; + } + }; + + Util.prototype.isEmptyNode = function(node) { + var $node; + $node = $(node); + return $node.is(':empty') || (!$node.text() && !$node.find(':not(br, span, div, b, a, strong, i, strike, font, u)').length); + }; + + Util.prototype.isDecoratedNode = function(node) { + return $(node).is('[class^="simditor-"]'); + }; + + Util.prototype.blockNodes = ["div", "p", "ul", "ol", "li", "blockquote", "hr", "pre", "h1", "h2", "h3", "h4", "h5", "table"]; + + Util.prototype.isBlockNode = function(node) { + node = $(node)[0]; + if (!node || node.nodeType === 3) { + return false; + } + return new RegExp("^(" + (this.blockNodes.join('|')) + ")$").test(node.nodeName.toLowerCase()); + }; + + Util.prototype.getNodeLength = function(node) { + node = $(node)[0]; + switch (node.nodeType) { + case 7: + case 10: + return 0; + case 3: + case 8: + return node.length; + default: + return node.childNodes.length; + } + }; + + Util.prototype.dataURLtoBlob = function(dataURL) { + var BlobBuilder, arrayBuffer, bb, blobArray, byteString, hasArrayBufferViewSupport, hasBlobConstructor, i, intArray, k, mimeString, ref, supportBlob; + hasBlobConstructor = window.Blob && (function() { + var e; + try { + return Boolean(new Blob()); + } catch (_error) { + e = _error; + return false; + } + })(); + hasArrayBufferViewSupport = hasBlobConstructor && window.Uint8Array && (function() { + var e; + try { + return new Blob([new Uint8Array(100)]).size === 100; + } catch (_error) { + e = _error; + return false; + } + })(); + BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder; + supportBlob = hasBlobConstructor || BlobBuilder; + if (!(supportBlob && window.atob && window.ArrayBuffer && window.Uint8Array)) { + return false; + } + if (dataURL.split(',')[0].indexOf('base64') >= 0) { + byteString = atob(dataURL.split(',')[1]); + } else { + byteString = decodeURIComponent(dataURL.split(',')[1]); + } + arrayBuffer = new ArrayBuffer(byteString.length); + intArray = new Uint8Array(arrayBuffer); + for (i = k = 0, ref = byteString.length; 0 <= ref ? k <= ref : k >= ref; i = 0 <= ref ? ++k : --k) { + intArray[i] = byteString.charCodeAt(i); + } + mimeString = dataURL.split(',')[0].split(':')[1].split(';')[0]; + if (hasBlobConstructor) { + blobArray = hasArrayBufferViewSupport ? intArray : arrayBuffer; + return new Blob([blobArray], { + type: mimeString + }); + } + bb = new BlobBuilder(); + bb.append(arrayBuffer); + return bb.getBlob(mimeString); + }; + + Util.prototype.throttle = function(func, wait) { + var args, call, ctx, last, rtn, throttled, timeoutID; + last = 0; + timeoutID = 0; + ctx = args = rtn = null; + call = function() { + timeoutID = 0; + last = +new Date(); + rtn = func.apply(ctx, args); + ctx = null; + return args = null; + }; + throttled = function() { + var delta; + ctx = this; + args = arguments; + delta = new Date() - last; + if (!timeoutID) { + if (delta >= wait) { + call(); + } else { + timeoutID = setTimeout(call, wait - delta); + } + } + return rtn; + }; + throttled.clear = function() { + if (!timeoutID) { + return; + } + clearTimeout(timeoutID); + return call(); + }; + return throttled; + }; + + Util.prototype.formatHTML = function(html) { + var cursor, indentString, lastMatch, level, match, re, repeatString, result, str; + re = /<(\/?)(.+?)(\/?)>/g; + result = ''; + level = 0; + lastMatch = null; + indentString = ' '; + repeatString = function(str, n) { + return new Array(n + 1).join(str); + }; + while ((match = re.exec(html)) !== null) { + match.isBlockNode = $.inArray(match[2], this.blockNodes) > -1; + match.isStartTag = match[1] !== '/' && match[3] !== '/'; + match.isEndTag = match[1] === '/' || match[3] === '/'; + cursor = lastMatch ? lastMatch.index + lastMatch[0].length : 0; + if ((str = html.substring(cursor, match.index)).length > 0 && $.trim(str)) { + result += str; + } + if (match.isBlockNode && match.isEndTag && !match.isStartTag) { + level -= 1; + } + if (match.isBlockNode && match.isStartTag) { + if (!(lastMatch && lastMatch.isBlockNode && lastMatch.isEndTag)) { + result += '\n'; + } + result += repeatString(indentString, level); + } + result += match[0]; + if (match.isBlockNode && match.isEndTag) { + result += '\n'; + } + if (match.isBlockNode && match.isStartTag) { + level += 1; + } + lastMatch = match; + } + return $.trim(result); + }; + + return Util; + +})(SimpleModule); + +Toolbar = (function(superClass) { + extend(Toolbar, superClass); + + function Toolbar() { + return Toolbar.__super__.constructor.apply(this, arguments); + } + + Toolbar.pluginName = 'Toolbar'; + + Toolbar.prototype.opts = { + toolbar: true, + toolbarFloat: true, + toolbarHidden: false, + toolbarFloatOffset: 0, + toolbarScrollContainer: window + }; + + Toolbar.prototype._tpl = { + wrapper: '<div class="simditor-toolbar"><ul></ul></div>', + separator: '<li><span class="separator"></span></li>' + }; + + Toolbar.prototype._init = function() { + var floatInitialized, initToolbarFloat, scrollContainerOffset, toolbarHeight; + this.editor = this._module; + if (!this.opts.toolbar) { + return; + } + if (!$.isArray(this.opts.toolbar)) { + this.opts.toolbar = ['bold', 'italic', 'underline', 'strikethrough', '|', 'ol', 'ul', 'blockquote', 'code', '|', 'link', 'image', '|', 'indent', 'outdent']; + } + this._render(); + this.list.on('click', function(e) { + return false; + }); + this.wrapper.on('mousedown', (function(_this) { + return function(e) { + return _this.list.find('.menu-on').removeClass('.menu-on'); + }; + })(this)); + $(document).on('mousedown.simditor' + this.editor.id, (function(_this) { + return function(e) { + return _this.list.find('.menu-on').removeClass('.menu-on'); + }; + })(this)); + if (!this.opts.toolbarHidden && this.opts.toolbarFloat) { + scrollContainerOffset = this.opts.toolbarScrollContainer === window ? { + top: 0, + left: 0 + } : $(this.opts.toolbarScrollContainer).offset(); + this.wrapper.css('top', scrollContainerOffset.top + this.opts.toolbarFloatOffset); + toolbarHeight = 0; + initToolbarFloat = (function(_this) { + return function() { + _this.wrapper.css('position', 'static'); + _this.wrapper.width('auto'); + _this.editor.util.reflow(_this.wrapper); + _this.wrapper.width(_this.wrapper.outerWidth()); + _this.wrapper.css('left', _this.editor.util.os.mobile ? _this.wrapper.position().left : _this.wrapper.offset().left - scrollContainerOffset.left); + _this.wrapper.css('position', ''); + toolbarHeight = _this.wrapper.outerHeight(); + _this.editor.placeholderEl.css('top', scrollContainerOffset.top); + return true; + }; + })(this); + floatInitialized = null; + $(window).on('resize.simditor-' + this.editor.id, function(e) { + return floatInitialized = initToolbarFloat(); + }); + $(this.opts.toolbarScrollContainer).on('scroll.simditor-' + this.editor.id, (function(_this) { + return function(e) { + var bottomEdge, scrollTop, topEdge; + if (!_this.wrapper.is(':visible')) { + return; + } + topEdge = _this.opts.toolbarScrollContainer === window ? _this.editor.wrapper.get(0).getBoundingClientRect().top : _this.editor.wrapper.offset().top - scrollContainerOffset.top; + bottomEdge = topEdge + _this.editor.wrapper.outerHeight() - 80; + scrollTop = $(_this.opts.toolbarScrollContainer).scrollTop() + _this.opts.toolbarFloatOffset; + if (topEdge > 0 || bottomEdge < 0) { + _this.editor.wrapper.removeClass('toolbar-floating').css('padding-top', ''); + if (_this.editor.util.os.mobile) { + return _this.wrapper.css('top', _this.opts.toolbarFloatOffset); + } + } else { + floatInitialized || (floatInitialized = initToolbarFloat()); + _this.editor.wrapper.addClass('toolbar-floating').css('padding-top', toolbarHeight); + if (_this.editor.util.os.mobile) { + return _this.wrapper.css('top', scrollTop - topEdge + _this.opts.toolbarFloatOffset); + } + } + }; + })(this)); + } + this.editor.on('destroy', (function(_this) { + return function() { + return _this.buttons.length = 0; + }; + })(this)); + return $(document).on("mousedown.simditor-" + this.editor.id, (function(_this) { + return function(e) { + return _this.list.find('li.menu-on').removeClass('menu-on'); + }; + })(this)); + }; + + Toolbar.prototype._render = function() { + var k, len, name, ref; + this.buttons = []; + this.wrapper = $(this._tpl.wrapper).prependTo(this.editor.wrapper); + this.list = this.wrapper.find('ul'); + ref = this.opts.toolbar; + for (k = 0, len = ref.length; k < len; k++) { + name = ref[k]; + if (name === '|') { + $(this._tpl.separator).appendTo(this.list); + continue; + } + if (!this.constructor.buttons[name]) { + throw new Error("simditor: invalid toolbar button " + name); + continue; + } + this.buttons.push(new this.constructor.buttons[name]({ + editor: this.editor + })); + } + if (this.opts.toolbarHidden) { + return this.wrapper.hide(); + } + }; + + Toolbar.prototype.findButton = function(name) { + var button; + button = this.list.find('.toolbar-item-' + name).data('button'); + return button != null ? button : null; + }; + + Toolbar.addButton = function(btn) { + return this.buttons[btn.prototype.name] = btn; + }; + + Toolbar.buttons = {}; + + return Toolbar; + +})(SimpleModule); + +Indentation = (function(superClass) { + extend(Indentation, superClass); + + function Indentation() { + return Indentation.__super__.constructor.apply(this, arguments); + } + + Indentation.pluginName = 'Indentation'; + + Indentation.prototype.opts = { + tabIndent: true + }; + + Indentation.prototype._init = function() { + this.editor = this._module; + return this.editor.keystroke.add('tab', '*', (function(_this) { + return function(e) { + var codeButton; + codeButton = _this.editor.toolbar.findButton('code'); + if (!(_this.opts.tabIndent || (codeButton && codeButton.active))) { + return; + } + return _this.indent(e.shiftKey); + }; + })(this)); + }; + + Indentation.prototype.indent = function(isBackward) { + var $blockNodes, $endNodes, $startNodes, nodes, result; + $startNodes = this.editor.selection.startNodes(); + $endNodes = this.editor.selection.endNodes(); + $blockNodes = this.editor.selection.blockNodes(); + nodes = []; + $blockNodes = $blockNodes.each(function(i, node) { + var include, j, k, len, n; + include = true; + for (j = k = 0, len = nodes.length; k < len; j = ++k) { + n = nodes[j]; + if ($.contains(node, n)) { + include = false; + break; + } else if ($.contains(n, node)) { + nodes.splice(j, 1, node); + include = false; + break; + } + } + if (include) { + return nodes.push(node); + } + }); + $blockNodes = $(nodes); + result = false; + $blockNodes.each((function(_this) { + return function(i, blockEl) { + var r; + r = isBackward ? _this.outdentBlock(blockEl) : _this.indentBlock(blockEl); + if (r) { + return result = r; + } + }; + })(this)); + return result; + }; + + Indentation.prototype.indentBlock = function(blockEl) { + var $blockEl, $childList, $nextTd, $nextTr, $parentLi, $pre, $td, $tr, marginLeft, tagName; + $blockEl = $(blockEl); + if (!$blockEl.length) { + return; + } + if ($blockEl.is('pre')) { + $pre = this.editor.selection.containerNode(); + if (!($pre.is($blockEl) || $pre.closest('pre').is($blockEl))) { + return; + } + this.indentText(this.editor.selection.range()); + } else if ($blockEl.is('li')) { + $parentLi = $blockEl.prev('li'); + if ($parentLi.length < 1) { + return; + } + this.editor.selection.save(); + tagName = $blockEl.parent()[0].tagName; + $childList = $parentLi.children('ul, ol'); + if ($childList.length > 0) { + $childList.append($blockEl); + } else { + $('<' + tagName + '/>').append($blockEl).appendTo($parentLi); + } + this.editor.selection.restore(); + } else if ($blockEl.is('p, h1, h2, h3, h4')) { + marginLeft = parseInt($blockEl.css('margin-left')) || 0; + marginLeft = (Math.round(marginLeft / this.opts.indentWidth) + 1) * this.opts.indentWidth; + $blockEl.css('margin-left', marginLeft); + } else if ($blockEl.is('table') || $blockEl.is('.simditor-table')) { + $td = this.editor.selection.containerNode().closest('td, th'); + $nextTd = $td.next('td, th'); + if (!($nextTd.length > 0)) { + $tr = $td.parent('tr'); + $nextTr = $tr.next('tr'); + if ($nextTr.length < 1 && $tr.parent().is('thead')) { + $nextTr = $tr.parent('thead').next('tbody').find('tr:first'); + } + $nextTd = $nextTr.find('td:first, th:first'); + } + if (!($td.length > 0 && $nextTd.length > 0)) { + return; + } + this.editor.selection.setRangeAtEndOf($nextTd); + } else { + return false; + } + return true; + }; + + Indentation.prototype.indentText = function(range) { + var text, textNode; + text = range.toString().replace(/^(?=.+)/mg, '\u00A0\u00A0'); + textNode = document.createTextNode(text || '\u00A0\u00A0'); + range.deleteContents(); + range.insertNode(textNode); + if (text) { + range.selectNode(textNode); + return this.editor.selection.range(range); + } else { + return this.editor.selection.setRangeAfter(textNode); + } + }; + + Indentation.prototype.outdentBlock = function(blockEl) { + var $blockEl, $parent, $parentLi, $pre, $prevTd, $prevTr, $td, $tr, marginLeft, range; + $blockEl = $(blockEl); + if (!($blockEl && $blockEl.length > 0)) { + return; + } + if ($blockEl.is('pre')) { + $pre = this.editor.selection.containerNode(); + if (!($pre.is($blockEl) || $pre.closest('pre').is($blockEl))) { + return; + } + this.outdentText(range); + } else if ($blockEl.is('li')) { + $parent = $blockEl.parent(); + $parentLi = $parent.parent('li'); + this.editor.selection.save(); + if ($parentLi.length < 1) { + range = document.createRange(); + range.setStartBefore($parent[0]); + range.setEndBefore($blockEl[0]); + $parent.before(range.extractContents()); + $('<p/>').insertBefore($parent).after($blockEl.children('ul, ol')).append($blockEl.contents()); + $blockEl.remove(); + } else { + if ($blockEl.next('li').length > 0) { + $('<' + $parent[0].tagName + '/>').append($blockEl.nextAll('li')).appendTo($blockEl); + } + $blockEl.insertAfter($parentLi); + if ($parent.children('li').length < 1) { + $parent.remove(); + } + } + this.editor.selection.restore(); + } else if ($blockEl.is('p, h1, h2, h3, h4')) { + marginLeft = parseInt($blockEl.css('margin-left')) || 0; + marginLeft = Math.max(Math.round(marginLeft / this.opts.indentWidth) - 1, 0) * this.opts.indentWidth; + $blockEl.css('margin-left', marginLeft === 0 ? '' : marginLeft); + } else if ($blockEl.is('table') || $blockEl.is('.simditor-table')) { + $td = this.editor.selection.containerNode().closest('td, th'); + $prevTd = $td.prev('td, th'); + if (!($prevTd.length > 0)) { + $tr = $td.parent('tr'); + $prevTr = $tr.prev('tr'); + if ($prevTr.length < 1 && $tr.parent().is('tbody')) { + $prevTr = $tr.parent('tbody').prev('thead').find('tr:first'); + } + $prevTd = $prevTr.find('td:last, th:last'); + } + if (!($td.length > 0 && $prevTd.length > 0)) { + return; + } + this.editor.selection.setRangeAtEndOf($prevTd); + } else { + return false; + } + return true; + }; + + Indentation.prototype.outdentText = function(range) {}; + + return Indentation; + +})(SimpleModule); + +Clipboard = (function(superClass) { + extend(Clipboard, superClass); + + function Clipboard() { + return Clipboard.__super__.constructor.apply(this, arguments); + } + + Clipboard.pluginName = 'Clipboard'; + + Clipboard.prototype.opts = { + pasteImage: false, + cleanPaste: false + }; + + Clipboard.prototype._init = function() { + this.editor = this._module; + if (this.opts.pasteImage && typeof this.opts.pasteImage !== 'string') { + this.opts.pasteImage = 'inline'; + } + return this.editor.body.on('paste', (function(_this) { + return function(e) { + var pasteBinAnchor, range; + if (_this.pasting || _this._pasteBin) { + return; + } + if (_this.editor.triggerHandler(e) === false) { + return false; + } + range = _this.editor.selection.deleteRangeContents(); + if (_this.editor.body.html()) { + if (!range.collapsed) { + range.collapse(true); + } + } else { + _this.editor.formatter.format(); + _this.editor.selection.setRangeAtStartOf(_this.editor.body.find('p:first')); + range = _this.editor.selection._range; + } + if (_this._processPasteByClipboardApi(e)) { + return false; + } + pasteBinAnchor = $('<span>'); + range.insertNode(pasteBinAnchor[0]); + _this._createPasteBin(pasteBinAnchor); + pasteBinAnchor.remove(); + range.collapse(true); + _this.editor.selection.range(range); + _this.editor.inputManager.throttledValueChanged.clear(); + _this.editor.inputManager.throttledSelectionChanged.clear(); + _this.editor.undoManager.throttledPushState.clear(); + _this.editor.selection.reset(); + _this.editor.undoManager.resetCaretPosition(); + _this.pasting = true; + return _this._getPasteContent(function(pasteContent) { + _this._processPasteContent(pasteContent); + _this._pasteInBlockEl = null; + _this._pastePlainText = null; + return _this.pasting = false; + }); + }; + })(this)); + }; + + Clipboard.prototype._processPasteByClipboardApi = function(e) { + var imageFile, pasteItem, ref, uploadOpt; + if (e.originalEvent.clipboardData && e.originalEvent.clipboardData.items && e.originalEvent.clipboardData.items.length > 0) { + pasteItem = e.originalEvent.clipboardData.items[0]; + if (/^image\//.test(pasteItem.type)) { + imageFile = pasteItem.getAsFile(); + if (!((imageFile != null) && this.opts.pasteImage)) { + return; + } + if (!imageFile.name) { + imageFile.name = "Clipboard Image.png"; + } + if (this.editor.triggerHandler('pasting', [imageFile]) === false) { + return; + } + uploadOpt = {}; + uploadOpt[this.opts.pasteImage] = true; + if ((ref = this.editor.uploader) != null) { + ref.upload(imageFile, uploadOpt); + } + return true; + } + } + }; + + Clipboard.prototype._createPasteBin = function(anchorNode) { + var anchorOffset, editorOffset; + anchorOffset = anchorNode.offset(); + editorOffset = this.editor.el.offset(); + return this._pasteBin = $('<div contenteditable="true" />').addClass('simditor-paste-bin').attr('tabIndex', '-1').css({ + top: anchorOffset.top - editorOffset.top, + left: anchorOffset.left - editorOffset.left + }).appendTo(this.editor.el); + }; + + Clipboard.prototype._getPasteContent = function(callback) { + var state; + state = { + html: this.editor.body.html(), + caret: this.editor.undoManager.caretPosition() + }; + this._pasteBin.focus(); + return setTimeout((function(_this) { + return function() { + var pasteContent; + _this.editor.hidePopover(); + _this.editor.body.get(0).innerHTML = DOMPurify ? DOMPurify.sanitize(state.html) : state.html; + _this.editor.undoManager.caretPosition(state.caret); + _this.editor.body.focus(); + _this.editor.selection.reset(); + _this.editor.selection.range(); + _this._pasteInBlockEl = _this.editor.selection.blockNodes().last(); + _this._pastePlainText = _this.opts.cleanPaste || _this._pasteInBlockEl.is('pre, table'); + if (_this._pastePlainText) { + pasteContent = _this.editor.formatter.clearHtml(_this._pasteBin.html(), true); + } else { + pasteContent = $('<div/>').append(_this._pasteBin.contents()); + pasteContent.find('style').remove(); + pasteContent.find('table colgroup').remove(); + _this._cleanPasteFontSize(pasteContent); + _this.editor.formatter.format(pasteContent); + _this.editor.formatter.decorate(pasteContent); + _this.editor.formatter.beautify(pasteContent.children()); + pasteContent = pasteContent.contents(); + } + _this._pasteBin.remove(); + _this._pasteBin = null; + return callback(pasteContent); + }; + })(this), 0); + }; + + Clipboard.prototype._processPasteContent = function(pasteContent) { + var $blockEl, $img, blob, children, dataURLtoBlob, img, insertPosition, k, l, lastLine, len, len1, len2, len3, len4, line, lines, m, node, o, q, ref, ref1, ref2, uploadOpt, uploader; + if (this.editor.triggerHandler('pasting', [pasteContent]) === false) { + return; + } + $blockEl = this._pasteInBlockEl; + if (!pasteContent) { + return; + } + if (this._pastePlainText) { + if ($blockEl.is('table')) { + lines = pasteContent.split('\n'); + lastLine = lines.pop(); + for (k = 0, len = lines.length; k < len; k++) { + line = lines[k]; + this.editor.selection.insertNode(document.createTextNode(line)); + this.editor.selection.insertNode($('<br/>')); + } + this.editor.selection.insertNode(document.createTextNode(lastLine)); + } else { + pasteContent = $('<div/>').text(pasteContent); + ref = pasteContent.contents(); + for (l = 0, len1 = ref.length; l < len1; l++) { + node = ref[l]; + this.editor.selection.insertNode($(node)[0]); + } + } + } else if ($blockEl.is(this.editor.body)) { + for (m = 0, len2 = pasteContent.length; m < len2; m++) { + node = pasteContent[m]; + this.editor.selection.insertNode(node); + } + } else if (pasteContent.length < 1) { + return; + } else if (pasteContent.length === 1) { + if (pasteContent.is('p')) { + children = pasteContent.contents(); + if ($blockEl.is('h1, h2, h3, h4, h5')) { + if (children.length) { + children.css('font-size', ''); + } + } + if (children.length === 1 && children.is('img')) { + $img = children; + if (/^data:image/.test($img.attr('src'))) { + if (!this.opts.pasteImage) { + return; + } + blob = this.editor.util.dataURLtoBlob($img.attr("src")); + blob.name = "Clipboard Image.png"; + uploadOpt = {}; + uploadOpt[this.opts.pasteImage] = true; + if ((ref1 = this.editor.uploader) != null) { + ref1.upload(blob, uploadOpt); + } + return; + } else if (new RegExp('^blob:' + location.origin + '/').test($img.attr('src'))) { + if (!this.opts.pasteImage) { + return; + } + uploadOpt = {}; + uploadOpt[this.opts.pasteImage] = true; + dataURLtoBlob = this.editor.util.dataURLtoBlob; + uploader = this.editor.uploader; + img = new Image; + img.onload = function() { + var canvas; + canvas = document.createElement('canvas'); + canvas.width = img.naturalWidth; + canvas.height = img.naturalHeight; + canvas.getContext('2d').drawImage(img, 0, 0); + blob = dataURLtoBlob(canvas.toDataURL('image/png')); + blob.name = 'Clipboard Image.png'; + if (uploader !== null) { + uploader.upload(blob, uploadOpt); + } + }; + img.src = $img.attr('src'); + return; + } else if ($img.is('img[src^="webkit-fake-url://"]')) { + return; + } + } + for (o = 0, len3 = children.length; o < len3; o++) { + node = children[o]; + this.editor.selection.insertNode(node); + } + } else if ($blockEl.is('p') && this.editor.util.isEmptyNode($blockEl)) { + $blockEl.replaceWith(pasteContent); + this.editor.selection.setRangeAtEndOf(pasteContent); + } else if (pasteContent.is('ul, ol')) { + if (pasteContent.find('li').length === 1) { + pasteContent = $('<div/>').text(pasteContent.text()); + ref2 = pasteContent.contents(); + for (q = 0, len4 = ref2.length; q < len4; q++) { + node = ref2[q]; + this.editor.selection.insertNode($(node)[0]); + } + } else if ($blockEl.is('li')) { + $blockEl.parent().after(pasteContent); + this.editor.selection.setRangeAtEndOf(pasteContent); + } else { + $blockEl.after(pasteContent); + this.editor.selection.setRangeAtEndOf(pasteContent); + } + } else { + $blockEl.after(pasteContent); + this.editor.selection.setRangeAtEndOf(pasteContent); + } + } else { + if ($blockEl.is('li')) { + $blockEl = $blockEl.parent(); + } + if (this.editor.selection.rangeAtStartOf($blockEl)) { + insertPosition = 'before'; + } else if (this.editor.selection.rangeAtEndOf($blockEl)) { + insertPosition = 'after'; + } else { + this.editor.selection.breakBlockEl($blockEl); + insertPosition = 'before'; + } + $blockEl[insertPosition](pasteContent); + this.editor.selection.setRangeAtEndOf(pasteContent.last()); + } + return this.editor.inputManager.throttledValueChanged(); + }; + + Clipboard.prototype._cleanPasteFontSize = function(node) { + var $node, sizeMap; + $node = $(node); + if (!($node.length > 0)) { + return; + } + sizeMap = ['1.5em', '1.25em', '0.75em', '0.5em']; + return $node.find('[style*="font-size"]').map(function(i, el) { + var $el; + $el = $(el); + if ($.inArray($el.css('font-size'), sizeMap) < 0) { + return $el.css('font-size', ''); + } + }); + }; + + return Clipboard; + +})(SimpleModule); + +Simditor = (function(superClass) { + extend(Simditor, superClass); + + function Simditor() { + return Simditor.__super__.constructor.apply(this, arguments); + } + + Simditor.connect(Util); + + Simditor.connect(InputManager); + + Simditor.connect(Selection); + + Simditor.connect(UndoManager); + + Simditor.connect(Keystroke); + + Simditor.connect(Formatter); + + Simditor.connect(Toolbar); + + Simditor.connect(Indentation); + + Simditor.connect(Clipboard); + + Simditor.count = 0; + + Simditor.prototype.opts = { + textarea: null, + placeholder: '', + defaultImage: 'images/image.png', + params: {}, + upload: false, + indentWidth: 40 + }; + + Simditor.prototype._init = function() { + var e, editor, uploadOpts; + this.textarea = $(this.opts.textarea); + this.opts.placeholder = this.opts.placeholder || this.textarea.attr('placeholder'); + if (!this.textarea.length) { + throw new Error('simditor: param textarea is required.'); + return; + } + editor = this.textarea.data('simditor'); + if (editor != null) { + editor.destroy(); + } + this.id = ++Simditor.count; + this._render(); + if (simpleHotkeys) { + this.hotkeys = simpleHotkeys({ + el: this.body + }); + } else { + throw new Error('simditor: simple-hotkeys is required.'); + return; + } + if (this.opts.upload && simpleUploader) { + uploadOpts = typeof this.opts.upload === 'object' ? this.opts.upload : {}; + this.uploader = simpleUploader(uploadOpts); + } + this.on('initialized', (function(_this) { + return function() { + if (_this.opts.placeholder) { + _this.on('valuechanged', function() { + return _this._placeholder(); + }); + } + _this.setValue(_this.textarea.val().trim() || ''); + if (_this.textarea.attr('autofocus')) { + return _this.focus(); + } + }; + })(this)); + if (this.util.browser.mozilla) { + this.util.reflow(); + try { + document.execCommand('enableObjectResizing', false, false); + return document.execCommand('enableInlineTableEditing', false, false); + } catch (_error) { + e = _error; + } + } + }; + + Simditor.prototype._tpl = "<div class=\"simditor\">\n <div class=\"simditor-wrapper\">\n <div class=\"simditor-placeholder\"></div>\n <div class=\"simditor-body\" contenteditable=\"true\">\n </div>\n </div>\n</div>"; + + Simditor.prototype._render = function() { + var key, ref, results, val; + this.el = $(this._tpl).insertBefore(this.textarea); + this.wrapper = this.el.find('.simditor-wrapper'); + this.body = this.wrapper.find('.simditor-body'); + this.placeholderEl = this.wrapper.find('.simditor-placeholder').append(this.opts.placeholder); + this.el.data('simditor', this); + this.wrapper.append(this.textarea); + this.textarea.data('simditor', this).blur(); + this.body.attr('tabindex', this.textarea.attr('tabindex')); + if (this.util.os.mac) { + this.el.addClass('simditor-mac'); + } else if (this.util.os.linux) { + this.el.addClass('simditor-linux'); + } + if (this.util.os.mobile) { + this.el.addClass('simditor-mobile'); + } + if (this.opts.params) { + ref = this.opts.params; + results = []; + for (key in ref) { + val = ref[key]; + results.push($('<input/>', { + type: 'hidden', + name: key, + value: val + }).insertAfter(this.textarea)); + } + return results; + } + }; + + Simditor.prototype._placeholder = function() { + var children; + children = this.body.children(); + if (children.length === 0 || (children.length === 1 && this.util.isEmptyNode(children) && parseInt(children.css('margin-left') || 0) < this.opts.indentWidth)) { + return this.placeholderEl.show(); + } else { + return this.placeholderEl.hide(); + } + }; + + Simditor.prototype.setValue = function(val) { + this.hidePopover(); + this.textarea.val(val); + this.body.get(0).innerHTML = DOMPurify ? DOMPurify.sanitize(val) : val; + this.formatter.format(); + this.formatter.decorate(); + this.util.reflow(this.body); + this.inputManager.lastCaretPosition = null; + return this.trigger('valuechanged'); + }; + + Simditor.prototype.getValue = function() { + return this.sync(); + }; + + Simditor.prototype.sync = function() { + var children, cloneBody, emptyP, firstP, lastP, val; + cloneBody = this.body.clone(); + this.formatter.undecorate(cloneBody); + this.formatter.format(cloneBody); + this.formatter.autolink(cloneBody); + children = cloneBody.children(); + lastP = children.last('p'); + firstP = children.first('p'); + while (lastP.is('p') && this.util.isEmptyNode(lastP)) { + emptyP = lastP; + lastP = lastP.prev('p'); + emptyP.remove(); + } + while (firstP.is('p') && this.util.isEmptyNode(firstP)) { + emptyP = firstP; + firstP = lastP.next('p'); + emptyP.remove(); + } + cloneBody.find('img.uploading').remove(); + val = $.trim(cloneBody.html()); + this.textarea.val(val); + return val; + }; + + Simditor.prototype.focus = function() { + var $blockEl, range; + if (!(this.body.is(':visible') && this.body.is('[contenteditable]'))) { + this.el.find('textarea:visible').focus(); + return; + } + if (this.inputManager.lastCaretPosition) { + this.undoManager.caretPosition(this.inputManager.lastCaretPosition); + return this.inputManager.lastCaretPosition = null; + } else { + $blockEl = this.body.children().last(); + if (!$blockEl.is('p')) { + $blockEl = $('<p/>').append(this.util.phBr).appendTo(this.body); + } + range = document.createRange(); + return this.selection.setRangeAtEndOf($blockEl, range); + } + }; + + Simditor.prototype.blur = function() { + if (this.body.is(':visible') && this.body.is('[contenteditable]')) { + return this.body.blur(); + } else { + return this.body.find('textarea:visible').blur(); + } + }; + + Simditor.prototype.hidePopover = function() { + return this.el.find('.simditor-popover').each(function(i, popover) { + popover = $(popover).data('popover'); + if (popover.active) { + return popover.hide(); + } + }); + }; + + Simditor.prototype.destroy = function() { + this.triggerHandler('destroy'); + this.textarea.closest('form').off('.simditor .simditor-' + this.id); + this.selection.clear(); + this.inputManager.focused = false; + this.textarea.insertBefore(this.el).hide().val('').removeData('simditor'); + this.el.remove(); + $(document).off('.simditor-' + this.id); + $(window).off('.simditor-' + this.id); + return this.off(); + }; + + return Simditor; + +})(SimpleModule); + +Simditor.i18n = { + 'zh-CN': { + 'blockquote': '引用', + 'bold': '加粗文字', + 'code': '插入代码', + 'color': '文字颜色', + 'coloredText': '彩色文字', + 'hr': '分隔线', + 'image': '插入图片', + 'externalImage': '外链图片', + 'uploadImage': '上传图片', + 'uploadFailed': '上传失败了', + 'uploadError': '上传出错了', + 'imageUrl': '图片地址', + 'imageSize': '图片尺寸', + 'imageAlt': '图片描述', + 'restoreImageSize': '还原图片尺寸', + 'uploading': '正在上传', + 'indent': '向右缩进', + 'outdent': '向左缩进', + 'italic': '斜体文字', + 'link': '插入链接', + 'linkText': '链接文字', + 'linkUrl': '链接地址', + 'linkTarget': '打开方式', + 'openLinkInCurrentWindow': '在当前窗口中打开', + 'openLinkInNewWindow': '在新窗口中打开', + 'removeLink': '移除链接', + 'ol': '有序列表', + 'ul': '无序列表', + 'strikethrough': '删除线文字', + 'table': '表格', + 'deleteRow': '删除行', + 'insertRowAbove': '在上面插入行', + 'insertRowBelow': '在下面插入行', + 'deleteColumn': '删除列', + 'insertColumnLeft': '在左边插入列', + 'insertColumnRight': '在右边插入列', + 'deleteTable': '删除表格', + 'title': '标题', + 'normalText': '普通文本', + 'underline': '下划线文字', + 'alignment': '水平对齐', + 'alignCenter': '居中', + 'alignLeft': '居左', + 'alignRight': '居右', + 'selectLanguage': '选择程序语言', + 'fontScale': '字体大小', + 'fontScaleXLarge': '超大字体', + 'fontScaleLarge': '大号字体', + 'fontScaleNormal': '正常大小', + 'fontScaleSmall': '小号字体', + 'fontScaleXSmall': '超小字体' + }, + 'en-US': { + 'blockquote': 'Block Quote', + 'bold': 'Bold', + 'code': 'Code', + 'color': 'Text Color', + 'coloredText': 'Colored Text', + 'hr': 'Horizontal Line', + 'image': 'Insert Image', + 'externalImage': 'External Image', + 'uploadImage': 'Upload Image', + 'uploadFailed': 'Upload failed', + 'uploadError': 'Error occurs during upload', + 'imageUrl': 'Url', + 'imageSize': 'Size', + 'imageAlt': 'Alt', + 'restoreImageSize': 'Restore Origin Size', + 'uploading': 'Uploading', + 'indent': 'Indent', + 'outdent': 'Outdent', + 'italic': 'Italic', + 'link': 'Insert Link', + 'linkText': 'Text', + 'linkUrl': 'Url', + 'linkTarget': 'Target', + 'openLinkInCurrentWindow': 'Open link in current window', + 'openLinkInNewWindow': 'Open link in new window', + 'removeLink': 'Remove Link', + 'ol': 'Ordered List', + 'ul': 'Unordered List', + 'strikethrough': 'Strikethrough', + 'table': 'Table', + 'deleteRow': 'Delete Row', + 'insertRowAbove': 'Insert Row Above', + 'insertRowBelow': 'Insert Row Below', + 'deleteColumn': 'Delete Column', + 'insertColumnLeft': 'Insert Column Left', + 'insertColumnRight': 'Insert Column Right', + 'deleteTable': 'Delete Table', + 'title': 'Title', + 'normalText': 'Text', + 'underline': 'Underline', + 'alignment': 'Alignment', + 'alignCenter': 'Align Center', + 'alignLeft': 'Align Left', + 'alignRight': 'Align Right', + 'selectLanguage': 'Select Language', + 'fontScale': 'Font Size', + 'fontScaleXLarge': 'X Large Size', + 'fontScaleLarge': 'Large Size', + 'fontScaleNormal': 'Normal Size', + 'fontScaleSmall': 'Small Size', + 'fontScaleXSmall': 'X Small Size' + } +}; + +Button = (function(superClass) { + extend(Button, superClass); + + Button.prototype._tpl = { + item: '<li><a tabindex="-1" unselectable="on" class="toolbar-item" href="javascript:;"><span></span></a></li>', + menuWrapper: '<div class="toolbar-menu"></div>', + menuItem: '<li><a tabindex="-1" unselectable="on" class="menu-item" href="javascript:;"><span></span></a></li>', + separator: '<li><span class="separator"></span></li>' + }; + + Button.prototype.name = ''; + + Button.prototype.icon = ''; + + Button.prototype.title = ''; + + Button.prototype.text = ''; + + Button.prototype.htmlTag = ''; + + Button.prototype.disableTag = ''; + + Button.prototype.menu = false; + + Button.prototype.active = false; + + Button.prototype.disabled = false; + + Button.prototype.needFocus = true; + + Button.prototype.shortcut = null; + + function Button(opts) { + this.editor = opts.editor; + this.title = this._t(this.name); + Button.__super__.constructor.call(this, opts); + } + + Button.prototype._init = function() { + var k, len, ref, tag; + this.render(); + this.el.on('mousedown', (function(_this) { + return function(e) { + var exceed, noFocus, param; + e.preventDefault(); + noFocus = _this.needFocus && !_this.editor.inputManager.focused; + if (_this.el.hasClass('disabled')) { + return false; + } + if (noFocus) { + _this.editor.focus(); + } + if (_this.menu) { + _this.wrapper.toggleClass('menu-on').siblings('li').removeClass('menu-on'); + if (_this.wrapper.is('.menu-on')) { + exceed = _this.menuWrapper.offset().left + _this.menuWrapper.outerWidth() + 5 - _this.editor.wrapper.offset().left - _this.editor.wrapper.outerWidth(); + if (exceed > 0) { + _this.menuWrapper.css({ + 'left': 'auto', + 'right': 0 + }); + } + _this.trigger('menuexpand'); + } + return false; + } + param = _this.el.data('param'); + _this.command(param); + return false; + }; + })(this)); + this.wrapper.on('click', 'a.menu-item', (function(_this) { + return function(e) { + var btn, noFocus, param; + e.preventDefault(); + btn = $(e.currentTarget); + _this.wrapper.removeClass('menu-on'); + noFocus = _this.needFocus && !_this.editor.inputManager.focused; + if (btn.hasClass('disabled') || noFocus) { + return false; + } + _this.editor.toolbar.wrapper.removeClass('menu-on'); + param = btn.data('param'); + _this.command(param); + return false; + }; + })(this)); + this.wrapper.on('mousedown', 'a.menu-item', function(e) { + return false; + }); + this.editor.on('blur', (function(_this) { + return function() { + var editorActive; + editorActive = _this.editor.body.is(':visible') && _this.editor.body.is('[contenteditable]'); + if (!(editorActive && !_this.editor.clipboard.pasting)) { + return; + } + _this.setActive(false); + return _this.setDisabled(false); + }; + })(this)); + if (this.shortcut != null) { + this.editor.hotkeys.add(this.shortcut, (function(_this) { + return function(e) { + _this.el.mousedown(); + return false; + }; + })(this)); + } + ref = this.htmlTag.split(','); + for (k = 0, len = ref.length; k < len; k++) { + tag = ref[k]; + tag = $.trim(tag); + if (tag && $.inArray(tag, this.editor.formatter._allowedTags) < 0) { + this.editor.formatter._allowedTags.push(tag); + } + } + return this.editor.on('selectionchanged', (function(_this) { + return function(e) { + if (_this.editor.inputManager.focused) { + return _this._status(); + } + }; + })(this)); + }; + + Button.prototype.iconClassOf = function(icon) { + if (icon) { + return "simditor-icon simditor-icon-" + icon; + } else { + return ''; + } + }; + + Button.prototype.setIcon = function(icon) { + return this.el.find('span').removeClass().addClass(this.iconClassOf(icon)).text(this.text); + }; + + Button.prototype.render = function() { + this.wrapper = $(this._tpl.item).appendTo(this.editor.toolbar.list); + this.el = this.wrapper.find('a.toolbar-item'); + this.el.attr('title', this.title).addClass("toolbar-item-" + this.name).data('button', this); + this.setIcon(this.icon); + if (!this.menu) { + return; + } + this.menuWrapper = $(this._tpl.menuWrapper).appendTo(this.wrapper); + this.menuWrapper.addClass("toolbar-menu-" + this.name); + return this.renderMenu(); + }; + + Button.prototype.renderMenu = function() { + var $menuBtnEl, $menuItemEl, k, len, menuItem, ref, ref1, results; + if (!$.isArray(this.menu)) { + return; + } + this.menuEl = $('<ul/>').appendTo(this.menuWrapper); + ref = this.menu; + results = []; + for (k = 0, len = ref.length; k < len; k++) { + menuItem = ref[k]; + if (menuItem === '|') { + $(this._tpl.separator).appendTo(this.menuEl); + continue; + } + $menuItemEl = $(this._tpl.menuItem).appendTo(this.menuEl); + $menuBtnEl = $menuItemEl.find('a.menu-item').attr({ + 'title': (ref1 = menuItem.title) != null ? ref1 : menuItem.text, + 'data-param': menuItem.param + }).addClass('menu-item-' + menuItem.name); + if (menuItem.icon) { + results.push($menuBtnEl.find('span').addClass(this.iconClassOf(menuItem.icon))); + } else { + results.push($menuBtnEl.find('span').text(menuItem.text)); + } + } + return results; + }; + + Button.prototype.setActive = function(active) { + if (active === this.active) { + return; + } + this.active = active; + return this.el.toggleClass('active', this.active); + }; + + Button.prototype.setDisabled = function(disabled) { + if (disabled === this.disabled) { + return; + } + this.disabled = disabled; + return this.el.toggleClass('disabled', this.disabled); + }; + + Button.prototype._disableStatus = function() { + var disabled, endNodes, startNodes; + startNodes = this.editor.selection.startNodes(); + endNodes = this.editor.selection.endNodes(); + disabled = startNodes.filter(this.disableTag).length > 0 || endNodes.filter(this.disableTag).length > 0; + this.setDisabled(disabled); + if (this.disabled) { + this.setActive(false); + } + return this.disabled; + }; + + Button.prototype._activeStatus = function() { + var active, endNode, endNodes, startNode, startNodes; + startNodes = this.editor.selection.startNodes(); + endNodes = this.editor.selection.endNodes(); + startNode = startNodes.filter(this.htmlTag); + endNode = endNodes.filter(this.htmlTag); + active = startNode.length > 0 && endNode.length > 0 && startNode.is(endNode); + this.node = active ? startNode : null; + this.setActive(active); + return this.active; + }; + + Button.prototype._status = function() { + this._disableStatus(); + if (this.disabled) { + return; + } + return this._activeStatus(); + }; + + Button.prototype.command = function(param) {}; + + Button.prototype._t = function() { + var args, ref, result; + args = 1 <= arguments.length ? slice.call(arguments, 0) : []; + result = Button.__super__._t.apply(this, args); + if (!result) { + result = (ref = this.editor)._t.apply(ref, args); + } + return result; + }; + + return Button; + +})(SimpleModule); + +Simditor.Button = Button; + +Popover = (function(superClass) { + extend(Popover, superClass); + + Popover.prototype.offset = { + top: 4, + left: 0 + }; + + Popover.prototype.target = null; + + Popover.prototype.active = false; + + function Popover(opts) { + this.button = opts.button; + this.editor = opts.button.editor; + Popover.__super__.constructor.call(this, opts); + } + + Popover.prototype._init = function() { + this.el = $('<div class="simditor-popover"></div>').appendTo(this.editor.el).data('popover', this); + this.render(); + this.el.on('mouseenter', (function(_this) { + return function(e) { + return _this.el.addClass('hover'); + }; + })(this)); + return this.el.on('mouseleave', (function(_this) { + return function(e) { + return _this.el.removeClass('hover'); + }; + })(this)); + }; + + Popover.prototype.render = function() {}; + + Popover.prototype._initLabelWidth = function() { + var $fields; + $fields = this.el.find('.settings-field'); + if (!($fields.length > 0)) { + return; + } + this._labelWidth = 0; + $fields.each((function(_this) { + return function(i, field) { + var $field, $label; + $field = $(field); + $label = $field.find('label'); + if (!($label.length > 0)) { + return; + } + return _this._labelWidth = Math.max(_this._labelWidth, $label.width()); + }; + })(this)); + return $fields.find('label').width(this._labelWidth); + }; + + Popover.prototype.show = function($target, position) { + if (position == null) { + position = 'bottom'; + } + if ($target == null) { + return; + } + this.el.siblings('.simditor-popover').each(function(i, popover) { + popover = $(popover).data('popover'); + if (popover && popover.active) { + return popover.hide(); + } + }); + if (this.active && this.target) { + this.target.removeClass('selected'); + } + this.target = $target.addClass('selected'); + if (this.active) { + this.refresh(position); + return this.trigger('popovershow'); + } else { + this.active = true; + this.el.css({ + left: -9999 + }).show(); + if (!this._labelWidth) { + this._initLabelWidth(); + } + this.editor.util.reflow(); + this.refresh(position); + return this.trigger('popovershow'); + } + }; + + Popover.prototype.hide = function() { + if (!this.active) { + return; + } + if (this.target) { + this.target.removeClass('selected'); + } + this.target = null; + this.active = false; + this.el.hide(); + return this.trigger('popoverhide'); + }; + + Popover.prototype.refresh = function(position) { + var editorOffset, left, maxLeft, targetH, targetOffset, top; + if (position == null) { + position = 'bottom'; + } + if (!this.active) { + return; + } + editorOffset = this.editor.el.offset(); + targetOffset = this.target.offset(); + targetH = this.target.outerHeight(); + if (position === 'bottom') { + top = targetOffset.top - editorOffset.top + targetH; + } else if (position === 'top') { + top = targetOffset.top - editorOffset.top - this.el.height(); + } + maxLeft = this.editor.wrapper.width() - this.el.outerWidth() - 10; + left = Math.min(targetOffset.left - editorOffset.left, maxLeft); + return this.el.css({ + top: top + this.offset.top, + left: left + this.offset.left + }); + }; + + Popover.prototype.destroy = function() { + this.target = null; + this.active = false; + this.editor.off('.linkpopover'); + return this.el.remove(); + }; + + Popover.prototype._t = function() { + var args, ref, result; + args = 1 <= arguments.length ? slice.call(arguments, 0) : []; + result = Popover.__super__._t.apply(this, args); + if (!result) { + result = (ref = this.button)._t.apply(ref, args); + } + return result; + }; + + return Popover; + +})(SimpleModule); + +Simditor.Popover = Popover; + +TitleButton = (function(superClass) { + extend(TitleButton, superClass); + + function TitleButton() { + return TitleButton.__super__.constructor.apply(this, arguments); + } + + TitleButton.prototype.name = 'title'; + + TitleButton.prototype.htmlTag = 'h1, h2, h3, h4, h5'; + + TitleButton.prototype.disableTag = 'pre, table'; + + TitleButton.prototype._init = function() { + this.menu = [ + { + name: 'normal', + text: this._t('normalText'), + param: 'p' + }, '|', { + name: 'h1', + text: this._t('title') + ' 1', + param: 'h1' + }, { + name: 'h2', + text: this._t('title') + ' 2', + param: 'h2' + }, { + name: 'h3', + text: this._t('title') + ' 3', + param: 'h3' + }, { + name: 'h4', + text: this._t('title') + ' 4', + param: 'h4' + }, { + name: 'h5', + text: this._t('title') + ' 5', + param: 'h5' + } + ]; + return TitleButton.__super__._init.call(this); + }; + + TitleButton.prototype.setActive = function(active, param) { + TitleButton.__super__.setActive.call(this, active); + if (active) { + param || (param = this.node[0].tagName.toLowerCase()); + } + this.el.removeClass('active-p active-h1 active-h2 active-h3 active-h4 active-h5'); + if (active) { + return this.el.addClass('active active-' + param); + } + }; + + TitleButton.prototype.command = function(param) { + var $rootNodes; + $rootNodes = this.editor.selection.rootNodes(); + this.editor.selection.save(); + $rootNodes.each((function(_this) { + return function(i, node) { + var $node; + $node = $(node); + if ($node.is('blockquote') || $node.is(param) || $node.is(_this.disableTag) || _this.editor.util.isDecoratedNode($node)) { + return; + } + return $('<' + param + '/>').append($node.contents()).replaceAll($node); + }; + })(this)); + this.editor.selection.restore(); + return this.editor.trigger('valuechanged'); + }; + + return TitleButton; + +})(Button); + +Simditor.Toolbar.addButton(TitleButton); + +FontScaleButton = (function(superClass) { + extend(FontScaleButton, superClass); + + function FontScaleButton() { + return FontScaleButton.__super__.constructor.apply(this, arguments); + } + + FontScaleButton.prototype.name = 'fontScale'; + + FontScaleButton.prototype.icon = 'font'; + + FontScaleButton.prototype.htmlTag = 'span'; + + FontScaleButton.prototype.disableTag = 'pre, h1, h2, h3, h4, h5'; + + FontScaleButton.prototype.sizeMap = { + 'x-large': '1.5em', + 'large': '1.25em', + 'small': '.75em', + 'x-small': '.5em' + }; + + FontScaleButton.prototype._init = function() { + this.menu = [ + { + name: '150%', + text: this._t('fontScaleXLarge'), + param: '5' + }, { + name: '125%', + text: this._t('fontScaleLarge'), + param: '4' + }, { + name: '100%', + text: this._t('fontScaleNormal'), + param: '3' + }, { + name: '75%', + text: this._t('fontScaleSmall'), + param: '2' + }, { + name: '50%', + text: this._t('fontScaleXSmall'), + param: '1' + } + ]; + return FontScaleButton.__super__._init.call(this); + }; + + FontScaleButton.prototype._activeStatus = function() { + var active, endNode, endNodes, range, startNode, startNodes; + range = this.editor.selection.range(); + startNodes = this.editor.selection.startNodes(); + endNodes = this.editor.selection.endNodes(); + startNode = startNodes.filter('span[style*="font-size"]'); + endNode = endNodes.filter('span[style*="font-size"]'); + active = startNodes.length > 0 && endNodes.length > 0 && startNode.is(endNode); + this.setActive(active); + return this.active; + }; + + FontScaleButton.prototype.command = function(param) { + var $scales, containerNode, range; + range = this.editor.selection.range(); + if (range.collapsed) { + return; + } + this.editor.selection.range(range); + document.execCommand('styleWithCSS', false, true); + document.execCommand('fontSize', false, param); + document.execCommand('styleWithCSS', false, false); + this.editor.selection.reset(); + this.editor.selection.range(); + containerNode = this.editor.selection.containerNode(); + if (containerNode[0].nodeType === Node.TEXT_NODE) { + $scales = containerNode.closest('span[style*="font-size"]'); + } else { + $scales = containerNode.find('span[style*="font-size"]'); + } + $scales.each((function(_this) { + return function(i, n) { + var $span, size; + $span = $(n); + size = n.style.fontSize; + if (/large|x-large|small|x-small/.test(size)) { + return $span.css('fontSize', _this.sizeMap[size]); + } else if (size === 'medium') { + if ($span[0].style.length > 1) { + return $span.css('fontSize', ''); + } else { + return $span.replaceWith($span.contents()); + } + } + }; + })(this)); + return this.editor.trigger('valuechanged'); + }; + + return FontScaleButton; + +})(Button); + +Simditor.Toolbar.addButton(FontScaleButton); + +BoldButton = (function(superClass) { + extend(BoldButton, superClass); + + function BoldButton() { + return BoldButton.__super__.constructor.apply(this, arguments); + } + + BoldButton.prototype.name = 'bold'; + + BoldButton.prototype.icon = 'bold'; + + BoldButton.prototype.htmlTag = 'b, strong'; + + BoldButton.prototype.disableTag = 'pre'; + + BoldButton.prototype.shortcut = 'cmd+b'; + + BoldButton.prototype._init = function() { + if (this.editor.util.os.mac) { + this.title = this.title + ' ( Cmd + b )'; + } else { + this.title = this.title + ' ( Ctrl + b )'; + this.shortcut = 'ctrl+b'; + } + return BoldButton.__super__._init.call(this); + }; + + BoldButton.prototype._activeStatus = function() { + var active; + active = document.queryCommandState('bold') === true; + this.setActive(active); + return this.active; + }; + + BoldButton.prototype.command = function() { + document.execCommand('bold'); + if (!this.editor.util.support.oninput) { + this.editor.trigger('valuechanged'); + } + return $(document).trigger('selectionchange'); + }; + + return BoldButton; + +})(Button); + +Simditor.Toolbar.addButton(BoldButton); + +ItalicButton = (function(superClass) { + extend(ItalicButton, superClass); + + function ItalicButton() { + return ItalicButton.__super__.constructor.apply(this, arguments); + } + + ItalicButton.prototype.name = 'italic'; + + ItalicButton.prototype.icon = 'italic'; + + ItalicButton.prototype.htmlTag = 'i'; + + ItalicButton.prototype.disableTag = 'pre'; + + ItalicButton.prototype.shortcut = 'cmd+i'; + + ItalicButton.prototype._init = function() { + if (this.editor.util.os.mac) { + this.title = this.title + " ( Cmd + i )"; + } else { + this.title = this.title + " ( Ctrl + i )"; + this.shortcut = 'ctrl+i'; + } + return ItalicButton.__super__._init.call(this); + }; + + ItalicButton.prototype._activeStatus = function() { + var active; + active = document.queryCommandState('italic') === true; + this.setActive(active); + return this.active; + }; + + ItalicButton.prototype.command = function() { + document.execCommand('italic'); + if (!this.editor.util.support.oninput) { + this.editor.trigger('valuechanged'); + } + return $(document).trigger('selectionchange'); + }; + + return ItalicButton; + +})(Button); + +Simditor.Toolbar.addButton(ItalicButton); + +UnderlineButton = (function(superClass) { + extend(UnderlineButton, superClass); + + function UnderlineButton() { + return UnderlineButton.__super__.constructor.apply(this, arguments); + } + + UnderlineButton.prototype.name = 'underline'; + + UnderlineButton.prototype.icon = 'underline'; + + UnderlineButton.prototype.htmlTag = 'u'; + + UnderlineButton.prototype.disableTag = 'pre'; + + UnderlineButton.prototype.shortcut = 'cmd+u'; + + UnderlineButton.prototype.render = function() { + if (this.editor.util.os.mac) { + this.title = this.title + ' ( Cmd + u )'; + } else { + this.title = this.title + ' ( Ctrl + u )'; + this.shortcut = 'ctrl+u'; + } + return UnderlineButton.__super__.render.call(this); + }; + + UnderlineButton.prototype._activeStatus = function() { + var active; + active = document.queryCommandState('underline') === true; + this.setActive(active); + return this.active; + }; + + UnderlineButton.prototype.command = function() { + document.execCommand('underline'); + if (!this.editor.util.support.oninput) { + this.editor.trigger('valuechanged'); + } + return $(document).trigger('selectionchange'); + }; + + return UnderlineButton; + +})(Button); + +Simditor.Toolbar.addButton(UnderlineButton); + +ColorButton = (function(superClass) { + extend(ColorButton, superClass); + + function ColorButton() { + return ColorButton.__super__.constructor.apply(this, arguments); + } + + ColorButton.prototype.name = 'color'; + + ColorButton.prototype.icon = 'tint'; + + ColorButton.prototype.disableTag = 'pre'; + + ColorButton.prototype.menu = true; + + ColorButton.prototype.render = function() { + var args; + args = 1 <= arguments.length ? slice.call(arguments, 0) : []; + return ColorButton.__super__.render.apply(this, args); + }; + + ColorButton.prototype.renderMenu = function() { + $('<ul class="color-list">\n <li><a href="javascript:;" class="font-color font-color-1"></a></li>\n <li><a href="javascript:;" class="font-color font-color-2"></a></li>\n <li><a href="javascript:;" class="font-color font-color-3"></a></li>\n <li><a href="javascript:;" class="font-color font-color-4"></a></li>\n <li><a href="javascript:;" class="font-color font-color-5"></a></li>\n <li><a href="javascript:;" class="font-color font-color-6"></a></li>\n <li><a href="javascript:;" class="font-color font-color-7"></a></li>\n <li><a href="javascript:;" class="font-color font-color-default"></a></li>\n</ul>').appendTo(this.menuWrapper); + this.menuWrapper.on('mousedown', '.color-list', function(e) { + return false; + }); + return this.menuWrapper.on('click', '.font-color', (function(_this) { + return function(e) { + var $link, $p, hex, range, rgb, textNode; + _this.wrapper.removeClass('menu-on'); + $link = $(e.currentTarget); + if ($link.hasClass('font-color-default')) { + $p = _this.editor.body.find('p, li'); + if (!($p.length > 0)) { + return; + } + rgb = window.getComputedStyle($p[0], null).getPropertyValue('color'); + hex = _this._convertRgbToHex(rgb); + } else { + rgb = window.getComputedStyle($link[0], null).getPropertyValue('background-color'); + hex = _this._convertRgbToHex(rgb); + } + if (!hex) { + return; + } + range = _this.editor.selection.range(); + if (!$link.hasClass('font-color-default') && range.collapsed) { + textNode = document.createTextNode(_this._t('coloredText')); + range.insertNode(textNode); + range.selectNodeContents(textNode); + } + _this.editor.selection.range(range); + document.execCommand('styleWithCSS', false, true); + document.execCommand('foreColor', false, hex); + document.execCommand('styleWithCSS', false, false); + if (!_this.editor.util.support.oninput) { + return _this.editor.trigger('valuechanged'); + } + }; + })(this)); + }; + + ColorButton.prototype._convertRgbToHex = function(rgb) { + var match, re, rgbToHex; + re = /rgb\((\d+),\s?(\d+),\s?(\d+)\)/g; + match = re.exec(rgb); + if (!match) { + return ''; + } + rgbToHex = function(r, g, b) { + var componentToHex; + componentToHex = function(c) { + var hex; + hex = c.toString(16); + if (hex.length === 1) { + return '0' + hex; + } else { + return hex; + } + }; + return "#" + componentToHex(r) + componentToHex(g) + componentToHex(b); + }; + return rgbToHex(match[1] * 1, match[2] * 1, match[3] * 1); + }; + + return ColorButton; + +})(Button); + +Simditor.Toolbar.addButton(ColorButton); + +ListButton = (function(superClass) { + extend(ListButton, superClass); + + function ListButton() { + return ListButton.__super__.constructor.apply(this, arguments); + } + + ListButton.prototype.type = ''; + + ListButton.prototype.disableTag = 'pre, table'; + + ListButton.prototype.command = function(param) { + var $list, $rootNodes, anotherType; + $rootNodes = this.editor.selection.blockNodes(); + anotherType = this.type === 'ul' ? 'ol' : 'ul'; + this.editor.selection.save(); + $list = null; + $rootNodes.each((function(_this) { + return function(i, node) { + var $node; + $node = $(node); + if ($node.is('blockquote, li') || $node.is(_this.disableTag) || _this.editor.util.isDecoratedNode($node) || !$.contains(document, node)) { + return; + } + if ($node.is(_this.type)) { + $node.children('li').each(function(i, li) { + var $childList, $li; + $li = $(li); + $childList = $li.children('ul, ol').insertAfter($node); + return $('<p/>').append($(li).html() || _this.editor.util.phBr).insertBefore($node); + }); + return $node.remove(); + } else if ($node.is(anotherType)) { + return $('<' + _this.type + '/>').append($node.contents()).replaceAll($node); + } else if ($list && $node.prev().is($list)) { + $('<li/>').append($node.html() || _this.editor.util.phBr).appendTo($list); + return $node.remove(); + } else { + $list = $("<" + _this.type + "><li></li></" + _this.type + ">"); + $list.find('li').append($node.html() || _this.editor.util.phBr); + return $list.replaceAll($node); + } + }; + })(this)); + this.editor.selection.restore(); + return this.editor.trigger('valuechanged'); + }; + + return ListButton; + +})(Button); + +OrderListButton = (function(superClass) { + extend(OrderListButton, superClass); + + function OrderListButton() { + return OrderListButton.__super__.constructor.apply(this, arguments); + } + + OrderListButton.prototype.type = 'ol'; + + OrderListButton.prototype.name = 'ol'; + + OrderListButton.prototype.icon = 'list-ol'; + + OrderListButton.prototype.htmlTag = 'ol'; + + OrderListButton.prototype.shortcut = 'cmd+/'; + + OrderListButton.prototype._init = function() { + if (this.editor.util.os.mac) { + this.title = this.title + ' ( Cmd + / )'; + } else { + this.title = this.title + ' ( ctrl + / )'; + this.shortcut = 'ctrl+/'; + } + return OrderListButton.__super__._init.call(this); + }; + + return OrderListButton; + +})(ListButton); + +UnorderListButton = (function(superClass) { + extend(UnorderListButton, superClass); + + function UnorderListButton() { + return UnorderListButton.__super__.constructor.apply(this, arguments); + } + + UnorderListButton.prototype.type = 'ul'; + + UnorderListButton.prototype.name = 'ul'; + + UnorderListButton.prototype.icon = 'list-ul'; + + UnorderListButton.prototype.htmlTag = 'ul'; + + UnorderListButton.prototype.shortcut = 'cmd+.'; + + UnorderListButton.prototype._init = function() { + if (this.editor.util.os.mac) { + this.title = this.title + ' ( Cmd + . )'; + } else { + this.title = this.title + ' ( Ctrl + . )'; + this.shortcut = 'ctrl+.'; + } + return UnorderListButton.__super__._init.call(this); + }; + + return UnorderListButton; + +})(ListButton); + +Simditor.Toolbar.addButton(OrderListButton); + +Simditor.Toolbar.addButton(UnorderListButton); + +BlockquoteButton = (function(superClass) { + extend(BlockquoteButton, superClass); + + function BlockquoteButton() { + return BlockquoteButton.__super__.constructor.apply(this, arguments); + } + + BlockquoteButton.prototype.name = 'blockquote'; + + BlockquoteButton.prototype.icon = 'quote-left'; + + BlockquoteButton.prototype.htmlTag = 'blockquote'; + + BlockquoteButton.prototype.disableTag = 'pre, table'; + + BlockquoteButton.prototype.command = function() { + var $rootNodes, clearCache, nodeCache; + $rootNodes = this.editor.selection.rootNodes(); + $rootNodes = $rootNodes.filter(function(i, node) { + return !$(node).parent().is('blockquote'); + }); + this.editor.selection.save(); + nodeCache = []; + clearCache = (function(_this) { + return function() { + if (nodeCache.length > 0) { + $("<" + _this.htmlTag + "/>").insertBefore(nodeCache[0]).append(nodeCache); + return nodeCache.length = 0; + } + }; + })(this); + $rootNodes.each((function(_this) { + return function(i, node) { + var $node; + $node = $(node); + if (!$node.parent().is(_this.editor.body)) { + return; + } + if ($node.is(_this.htmlTag)) { + clearCache(); + return $node.children().unwrap(); + } else if ($node.is(_this.disableTag) || _this.editor.util.isDecoratedNode($node)) { + return clearCache(); + } else { + return nodeCache.push(node); + } + }; + })(this)); + clearCache(); + this.editor.selection.restore(); + return this.editor.trigger('valuechanged'); + }; + + return BlockquoteButton; + +})(Button); + +Simditor.Toolbar.addButton(BlockquoteButton); + +CodeButton = (function(superClass) { + extend(CodeButton, superClass); + + function CodeButton() { + return CodeButton.__super__.constructor.apply(this, arguments); + } + + CodeButton.prototype.name = 'code'; + + CodeButton.prototype.icon = 'code'; + + CodeButton.prototype.htmlTag = 'pre'; + + CodeButton.prototype.disableTag = 'ul, ol, table'; + + CodeButton.prototype._init = function() { + CodeButton.__super__._init.call(this); + this.editor.on('decorate', (function(_this) { + return function(e, $el) { + return $el.find('pre').each(function(i, pre) { + return _this.decorate($(pre)); + }); + }; + })(this)); + return this.editor.on('undecorate', (function(_this) { + return function(e, $el) { + return $el.find('pre').each(function(i, pre) { + return _this.undecorate($(pre)); + }); + }; + })(this)); + }; + + CodeButton.prototype.render = function() { + var args; + args = 1 <= arguments.length ? slice.call(arguments, 0) : []; + CodeButton.__super__.render.apply(this, args); + return this.popover = new CodePopover({ + button: this + }); + }; + + CodeButton.prototype._checkMode = function() { + var $blockNodes, range; + range = this.editor.selection.range(); + if (($blockNodes = $(range.cloneContents()).find(this.editor.util.blockNodes.join(','))) > 0 || (range.collapsed && this.editor.selection.startNodes().filter('code').length === 0)) { + this.inlineMode = false; + return this.htmlTag = 'pre'; + } else { + this.inlineMode = true; + return this.htmlTag = 'code'; + } + }; + + CodeButton.prototype._status = function() { + this._checkMode(); + CodeButton.__super__._status.call(this); + if (this.inlineMode) { + return; + } + if (this.active) { + return this.popover.show(this.node); + } else { + return this.popover.hide(); + } + }; + + CodeButton.prototype.decorate = function($pre) { + var $code, lang, ref, ref1; + $code = $pre.find('> code'); + if ($code.length > 0) { + lang = (ref = $code.attr('class')) != null ? (ref1 = ref.match(/lang-(\S+)/)) != null ? ref1[1] : void 0 : void 0; + $code.contents().unwrap(); + if (lang) { + return $pre.attr('data-lang', lang); + } + } + }; + + CodeButton.prototype.undecorate = function($pre) { + var $code, lang; + lang = $pre.attr('data-lang'); + $code = $('<code/>'); + if (lang && lang !== -1) { + $code.addClass('lang-' + lang); + } + return $pre.wrapInner($code).removeAttr('data-lang'); + }; + + CodeButton.prototype.command = function() { + if (this.inlineMode) { + return this._inlineCommand(); + } else { + return this._blockCommand(); + } + }; + + CodeButton.prototype._blockCommand = function() { + var $rootNodes, clearCache, nodeCache, resultNodes; + $rootNodes = this.editor.selection.rootNodes(); + nodeCache = []; + resultNodes = []; + clearCache = (function(_this) { + return function() { + var $pre; + if (!(nodeCache.length > 0)) { + return; + } + $pre = $("<" + _this.htmlTag + "/>").insertBefore(nodeCache[0]).text(_this.editor.formatter.clearHtml(nodeCache)); + resultNodes.push($pre[0]); + return nodeCache.length = 0; + }; + })(this); + $rootNodes.each((function(_this) { + return function(i, node) { + var $node, $p; + $node = $(node); + if ($node.is(_this.htmlTag)) { + clearCache(); + $p = $('<p/>').append($node.html().replace('\n', '<br/>')).replaceAll($node); + return resultNodes.push($p[0]); + } else if ($node.is(_this.disableTag) || _this.editor.util.isDecoratedNode($node) || $node.is('blockquote')) { + return clearCache(); + } else { + return nodeCache.push(node); + } + }; + })(this)); + clearCache(); + this.editor.selection.setRangeAtEndOf($(resultNodes).last()); + return this.editor.trigger('valuechanged'); + }; + + CodeButton.prototype._inlineCommand = function() { + var $code, $contents, range; + range = this.editor.selection.range(); + if (this.active) { + range.selectNodeContents(this.node[0]); + this.editor.selection.save(range); + this.node.contents().unwrap(); + this.editor.selection.restore(); + } else { + $contents = $(range.extractContents()); + $code = $("<" + this.htmlTag + "/>").append($contents.contents()); + range.insertNode($code[0]); + range.selectNodeContents($code[0]); + this.editor.selection.range(range); + } + return this.editor.trigger('valuechanged'); + }; + + return CodeButton; + +})(Button); + +CodePopover = (function(superClass) { + extend(CodePopover, superClass); + + function CodePopover() { + return CodePopover.__super__.constructor.apply(this, arguments); + } + + CodePopover.prototype.render = function() { + var $option, k, lang, len, ref; + this._tpl = "<div class=\"code-settings\">\n <div class=\"settings-field\">\n <select class=\"select-lang\">\n <option value=\"-1\">" + (this._t('selectLanguage')) + "</option>\n </select>\n </div>\n</div>"; + this.langs = this.editor.opts.codeLanguages || [ + { + name: 'Bash', + value: 'bash' + }, { + name: 'C++', + value: 'c++' + }, { + name: 'C#', + value: 'cs' + }, { + name: 'CSS', + value: 'css' + }, { + name: 'Erlang', + value: 'erlang' + }, { + name: 'Less', + value: 'less' + }, { + name: 'Sass', + value: 'sass' + }, { + name: 'Diff', + value: 'diff' + }, { + name: 'CoffeeScript', + value: 'coffeescript' + }, { + name: 'HTML,XML', + value: 'html' + }, { + name: 'JSON', + value: 'json' + }, { + name: 'Java', + value: 'java' + }, { + name: 'JavaScript', + value: 'js' + }, { + name: 'Markdown', + value: 'markdown' + }, { + name: 'Objective C', + value: 'oc' + }, { + name: 'PHP', + value: 'php' + }, { + name: 'Perl', + value: 'parl' + }, { + name: 'Python', + value: 'python' + }, { + name: 'Ruby', + value: 'ruby' + }, { + name: 'SQL', + value: 'sql' + } + ]; + this.el.addClass('code-popover').append(this._tpl); + this.selectEl = this.el.find('.select-lang'); + ref = this.langs; + for (k = 0, len = ref.length; k < len; k++) { + lang = ref[k]; + $option = $('<option/>', { + text: lang.name, + value: lang.value + }).appendTo(this.selectEl); + } + this.selectEl.on('change', (function(_this) { + return function(e) { + var selected; + _this.lang = _this.selectEl.val(); + selected = _this.target.hasClass('selected'); + _this.target.removeClass().removeAttr('data-lang'); + if (_this.lang !== -1) { + _this.target.attr('data-lang', _this.lang); + } + if (selected) { + _this.target.addClass('selected'); + } + return _this.editor.trigger('valuechanged'); + }; + })(this)); + return this.editor.on('valuechanged', (function(_this) { + return function(e) { + if (_this.active) { + return _this.refresh(); + } + }; + })(this)); + }; + + CodePopover.prototype.show = function() { + var args; + args = 1 <= arguments.length ? slice.call(arguments, 0) : []; + CodePopover.__super__.show.apply(this, args); + this.lang = this.target.attr('data-lang'); + if (this.lang != null) { + return this.selectEl.val(this.lang); + } else { + return this.selectEl.val(-1); + } + }; + + return CodePopover; + +})(Popover); + +Simditor.Toolbar.addButton(CodeButton); + +LinkButton = (function(superClass) { + extend(LinkButton, superClass); + + function LinkButton() { + return LinkButton.__super__.constructor.apply(this, arguments); + } + + LinkButton.prototype.name = 'link'; + + LinkButton.prototype.icon = 'link'; + + LinkButton.prototype.htmlTag = 'a'; + + LinkButton.prototype.disableTag = 'pre'; + + LinkButton.prototype.render = function() { + var args; + args = 1 <= arguments.length ? slice.call(arguments, 0) : []; + LinkButton.__super__.render.apply(this, args); + return this.popover = new LinkPopover({ + button: this + }); + }; + + LinkButton.prototype._status = function() { + LinkButton.__super__._status.call(this); + if (this.active && !this.editor.selection.rangeAtEndOf(this.node)) { + return this.popover.show(this.node); + } else { + return this.popover.hide(); + } + }; + + LinkButton.prototype.command = function() { + var $contents, $link, $newBlock, linkText, range, txtNode; + range = this.editor.selection.range(); + if (this.active) { + txtNode = document.createTextNode(this.node.text()); + this.node.replaceWith(txtNode); + range.selectNode(txtNode); + } else { + $contents = $(range.extractContents()); + linkText = this.editor.formatter.clearHtml($contents.contents(), false); + $link = $('<a/>', { + href: '', + target: '_blank', + text: linkText || this._t('linkText') + }); + if (this.editor.selection.blockNodes().length > 0) { + range.insertNode($link[0]); + } else { + $newBlock = $('<p/>').append($link); + range.insertNode($newBlock[0]); + } + range.selectNodeContents($link[0]); + this.popover.one('popovershow', (function(_this) { + return function() { + if (linkText) { + _this.popover.urlEl.focus(); + return _this.popover.urlEl[0].select(); + } else { + _this.popover.textEl.focus(); + return _this.popover.textEl[0].select(); + } + }; + })(this)); + } + this.editor.selection.range(range); + return this.editor.trigger('valuechanged'); + }; + + return LinkButton; + +})(Button); + +LinkPopover = (function(superClass) { + extend(LinkPopover, superClass); + + function LinkPopover() { + return LinkPopover.__super__.constructor.apply(this, arguments); + } + + LinkPopover.prototype.render = function() { + var tpl; + tpl = "<div class=\"link-settings\">\n <div class=\"settings-field\">\n <label>" + (this._t('linkText')) + "</label>\n <input class=\"link-text\" type=\"text\"/>\n <a class=\"btn-unlink\" href=\"javascript:;\" title=\"" + (this._t('removeLink')) + "\"\n tabindex=\"-1\">\n <span class=\"simditor-icon simditor-icon-unlink\"></span>\n </a>\n </div>\n <div class=\"settings-field\">\n <label>" + (this._t('linkUrl')) + "</label>\n <input class=\"link-url\" type=\"text\"/>\n </div>\n <div class=\"settings-field\">\n <label>" + (this._t('linkTarget')) + "</label>\n <select class=\"link-target\">\n <option value=\"_blank\">" + (this._t('openLinkInNewWindow')) + " (_blank)</option>\n <option value=\"_self\">" + (this._t('openLinkInCurrentWindow')) + " (_self)</option>\n </select>\n </div>\n</div>"; + this.el.addClass('link-popover').append(tpl); + this.textEl = this.el.find('.link-text'); + this.urlEl = this.el.find('.link-url'); + this.unlinkEl = this.el.find('.btn-unlink'); + this.selectTarget = this.el.find('.link-target'); + this.textEl.on('keyup', (function(_this) { + return function(e) { + if (e.which === 13) { + return; + } + _this.target.text(_this.textEl.val()); + return _this.editor.inputManager.throttledValueChanged(); + }; + })(this)); + this.urlEl.on('keyup', (function(_this) { + return function(e) { + var val; + if (e.which === 13) { + return; + } + val = _this.urlEl.val(); + if (!(/^(http|https|ftp|ftps|file)?:\/\/|^(mailto|tel)?:|^\//ig.test(val) || !val)) { + val = 'http://' + val; + } + _this.target.attr('href', val); + return _this.editor.inputManager.throttledValueChanged(); + }; + })(this)); + $([this.urlEl[0], this.textEl[0]]).on('keydown', (function(_this) { + return function(e) { + var range; + if (e.which === 13 || e.which === 27 || (!e.shiftKey && e.which === 9 && $(e.target).hasClass('link-url'))) { + e.preventDefault(); + range = document.createRange(); + _this.editor.selection.setRangeAfter(_this.target, range); + _this.hide(); + return _this.editor.inputManager.throttledValueChanged(); + } + }; + })(this)); + this.unlinkEl.on('click', (function(_this) { + return function(e) { + var range, txtNode; + txtNode = document.createTextNode(_this.target.text()); + _this.target.replaceWith(txtNode); + _this.hide(); + range = document.createRange(); + _this.editor.selection.setRangeAfter(txtNode, range); + return _this.editor.inputManager.throttledValueChanged(); + }; + })(this)); + return this.selectTarget.on('change', (function(_this) { + return function(e) { + _this.target.attr('target', _this.selectTarget.val()); + return _this.editor.inputManager.throttledValueChanged(); + }; + })(this)); + }; + + LinkPopover.prototype.show = function() { + var args; + args = 1 <= arguments.length ? slice.call(arguments, 0) : []; + LinkPopover.__super__.show.apply(this, args); + this.textEl.val(this.target.text()); + return this.urlEl.val(this.target.attr('href')); + }; + + return LinkPopover; + +})(Popover); + +Simditor.Toolbar.addButton(LinkButton); + +ImageButton = (function(superClass) { + extend(ImageButton, superClass); + + function ImageButton() { + return ImageButton.__super__.constructor.apply(this, arguments); + } + + ImageButton.prototype.name = 'image'; + + ImageButton.prototype.icon = 'picture-o'; + + ImageButton.prototype.htmlTag = 'img'; + + ImageButton.prototype.disableTag = 'pre, table'; + + ImageButton.prototype.defaultImage = ''; + + ImageButton.prototype.needFocus = false; + + ImageButton.prototype._init = function() { + var item, k, len, ref; + if (this.editor.opts.imageButton) { + if (Array.isArray(this.editor.opts.imageButton)) { + this.menu = []; + ref = this.editor.opts.imageButton; + for (k = 0, len = ref.length; k < len; k++) { + item = ref[k]; + this.menu.push({ + name: item + '-image', + text: this._t(item + 'Image') + }); + } + } else { + this.menu = false; + } + } else { + if (this.editor.uploader != null) { + this.menu = [ + { + name: 'upload-image', + text: this._t('uploadImage') + }, { + name: 'external-image', + text: this._t('externalImage') + } + ]; + } else { + this.menu = false; + } + } + this.defaultImage = this.editor.opts.defaultImage; + this.editor.body.on('click', 'img:not([data-non-image])', (function(_this) { + return function(e) { + var $img, range; + $img = $(e.currentTarget); + range = document.createRange(); + range.selectNode($img[0]); + _this.editor.selection.range(range); + if (!_this.editor.util.support.onselectionchange) { + _this.editor.trigger('selectionchanged'); + } + return false; + }; + })(this)); + this.editor.body.on('mouseup', 'img:not([data-non-image])', function(e) { + return false; + }); + this.editor.on('selectionchanged.image', (function(_this) { + return function() { + var $contents, $img, range; + range = _this.editor.selection.range(); + if (range == null) { + return; + } + $contents = $(range.cloneContents()).contents(); + if ($contents.length === 1 && $contents.is('img:not([data-non-image])')) { + $img = $(range.startContainer).contents().eq(range.startOffset); + return _this.popover.show($img); + } else { + return _this.popover.hide(); + } + }; + })(this)); + this.editor.on('valuechanged.image', (function(_this) { + return function() { + var $masks; + $masks = _this.editor.wrapper.find('.simditor-image-loading'); + if (!($masks.length > 0)) { + return; + } + return $masks.each(function(i, mask) { + var $img, $mask, file; + $mask = $(mask); + $img = $mask.data('img'); + if (!($img && $img.parent().length > 0)) { + $mask.remove(); + if ($img) { + file = $img.data('file'); + if (file) { + _this.editor.uploader.cancel(file); + if (_this.editor.body.find('img.uploading').length < 1) { + return _this.editor.uploader.trigger('uploadready', [file]); + } + } + } + } + }); + }; + })(this)); + return ImageButton.__super__._init.call(this); + }; + + ImageButton.prototype.render = function() { + var args; + args = 1 <= arguments.length ? slice.call(arguments, 0) : []; + ImageButton.__super__.render.apply(this, args); + this.popover = new ImagePopover({ + button: this + }); + if (this.editor.opts.imageButton === 'upload') { + return this._initUploader(this.el); + } + }; + + ImageButton.prototype.renderMenu = function() { + ImageButton.__super__.renderMenu.call(this); + return this._initUploader(); + }; + + ImageButton.prototype._initUploader = function($uploadItem) { + var $input, createInput, uploadProgress; + if ($uploadItem == null) { + $uploadItem = this.menuEl.find('.menu-item-upload-image'); + } + if (this.editor.uploader == null) { + this.el.find('.btn-upload').remove(); + return; + } + $input = null; + createInput = (function(_this) { + return function() { + if ($input) { + $input.remove(); + } + return $input = $('<input/>', { + type: 'file', + title: _this._t('uploadImage'), + multiple: true, + accept: 'image/gif,image/jpeg,image/jpg,image/png,image/svg' + }).appendTo($uploadItem); + }; + })(this); + createInput(); + $uploadItem.on('click mousedown', 'input[type=file]', function(e) { + return e.stopPropagation(); + }); + $uploadItem.on('change', 'input[type=file]', (function(_this) { + return function(e) { + if (_this.editor.inputManager.focused) { + _this.editor.uploader.upload($input, { + inline: true + }); + createInput(); + } else { + _this.editor.one('focus', function(e) { + _this.editor.uploader.upload($input, { + inline: true + }); + return createInput(); + }); + _this.editor.focus(); + } + return _this.wrapper.removeClass('menu-on'); + }; + })(this)); + this.editor.uploader.on('beforeupload', (function(_this) { + return function(e, file) { + var $img; + if (!file.inline) { + return; + } + if (file.img) { + $img = $(file.img); + } else { + $img = _this.createImage(file.name); + file.img = $img; + } + $img.addClass('uploading'); + $img.data('file', file); + return _this.editor.uploader.readImageFile(file.obj, function(img) { + var src; + if (!$img.hasClass('uploading')) { + return; + } + src = img ? img.src : _this.defaultImage; + return _this.loadImage($img, src, function() { + if (_this.popover.active) { + _this.popover.refresh(); + return _this.popover.srcEl.val(_this._t('uploading')).prop('disabled', true); + } + }); + }); + }; + })(this)); + uploadProgress = $.proxy(this.editor.util.throttle(function(e, file, loaded, total) { + var $img, $mask, percent; + if (!file.inline) { + return; + } + $mask = file.img.data('mask'); + if (!$mask) { + return; + } + $img = $mask.data('img'); + if (!($img && $img.hasClass('uploading') && $img.parent().length > 0)) { + $mask.remove(); + return; + } + percent = loaded / total; + percent = (percent * 100).toFixed(0); + if (percent > 99) { + percent = 99; + } + return $mask.find('.progress').height((100 - percent) + "%"); + }, 500), this); + this.editor.uploader.on('uploadprogress', uploadProgress); + this.editor.uploader.on('uploadsuccess', (function(_this) { + return function(e, file, result) { + var $img, img_path, msg; + if (!file.inline) { + return; + } + $img = file.img; + if (!($img.hasClass('uploading') && $img.parent().length > 0)) { + return; + } + if (typeof result !== 'object') { + try { + result = $.parseJSON(result); + } catch (_error) { + e = _error; + result = { + success: false + }; + } + } + if (result.success === false) { + msg = result.msg || _this._t('uploadFailed'); + alert(msg); + img_path = _this.defaultImage; + } else { + img_path = result.file_path; + } + _this.loadImage($img, img_path, function() { + var $mask; + $img.removeData('file'); + $img.removeClass('uploading').removeClass('loading'); + $mask = $img.data('mask'); + if ($mask) { + $mask.remove(); + } + $img.removeData('mask'); + _this.editor.trigger('valuechanged'); + if (_this.editor.body.find('img.uploading').length < 1) { + return _this.editor.uploader.trigger('uploadready', [file, result]); + } + }); + if (_this.popover.active) { + _this.popover.srcEl.prop('disabled', false); + return _this.popover.srcEl.val(result.file_path); + } + }; + })(this)); + return this.editor.uploader.on('uploaderror', (function(_this) { + return function(e, file, xhr) { + var $img, msg, result; + if (!file.inline) { + return; + } + if (xhr.statusText === 'abort') { + return; + } + if (xhr.responseText) { + try { + result = $.parseJSON(xhr.responseText); + msg = result.msg; + } catch (_error) { + e = _error; + msg = _this._t('uploadError'); + } + } + $img = file.img; + if (!($img.hasClass('uploading') && $img.parent().length > 0)) { + return; + } + _this.loadImage($img, _this.defaultImage, function() { + var $mask; + $img.removeData('file'); + $img.removeClass('uploading').removeClass('loading'); + $mask = $img.data('mask'); + if ($mask) { + $mask.remove(); + } + return $img.removeData('mask'); + }); + if (_this.popover.active) { + _this.popover.srcEl.prop('disabled', false); + _this.popover.srcEl.val(_this.defaultImage); + } + _this.editor.trigger('valuechanged'); + if (_this.editor.body.find('img.uploading').length < 1) { + return _this.editor.uploader.trigger('uploadready', [file, result]); + } + }; + })(this)); + }; + + ImageButton.prototype._status = function() { + return this._disableStatus(); + }; + + ImageButton.prototype.loadImage = function($img, src, callback) { + var $mask, img, positionMask; + positionMask = (function(_this) { + return function() { + var imgOffset, wrapperOffset; + imgOffset = $img.offset(); + wrapperOffset = _this.editor.wrapper.offset(); + return $mask.css({ + top: imgOffset.top - wrapperOffset.top, + left: imgOffset.left - wrapperOffset.left, + width: $img.width(), + height: $img.height() + }).show(); + }; + })(this); + $img.addClass('loading'); + $mask = $img.data('mask'); + if (!$mask) { + $mask = $('<div class="simditor-image-loading">\n <div class="progress"></div>\n</div>').hide().appendTo(this.editor.wrapper); + positionMask(); + $img.data('mask', $mask); + $mask.data('img', $img); + } + img = new Image(); + img.onload = (function(_this) { + return function() { + var height, width; + if (!$img.hasClass('loading') && !$img.hasClass('uploading')) { + return; + } + width = img.width; + height = img.height; + $img.attr({ + src: src, + width: width, + height: height, + 'data-image-size': width + ',' + height + }).removeClass('loading'); + if ($img.hasClass('uploading')) { + _this.editor.util.reflow(_this.editor.body); + positionMask(); + } else { + $mask.remove(); + $img.removeData('mask'); + } + if ($.isFunction(callback)) { + return callback(img); + } + }; + })(this); + img.onerror = function() { + if ($.isFunction(callback)) { + callback(false); + } + $mask.remove(); + return $img.removeData('mask').removeClass('loading'); + }; + return img.setAttribute('src', src); + }; + + ImageButton.prototype.createImage = function(name) { + var $img, range; + if (name == null) { + name = 'Image'; + } + if (!this.editor.inputManager.focused) { + this.editor.focus(); + } + range = this.editor.selection.range(); + range.deleteContents(); + this.editor.selection.range(range); + $img = $('<img/>').attr('alt', name); + range.insertNode($img[0]); + this.editor.selection.setRangeAfter($img, range); + this.editor.trigger('valuechanged'); + return $img; + }; + + ImageButton.prototype.command = function(src) { + var $img; + $img = this.createImage(); + return this.loadImage($img, src || this.defaultImage, (function(_this) { + return function() { + _this.editor.trigger('valuechanged'); + _this.editor.util.reflow($img); + $img.click(); + return _this.popover.one('popovershow', function() { + _this.popover.srcEl.focus(); + return _this.popover.srcEl[0].select(); + }); + }; + })(this)); + }; + + return ImageButton; + +})(Button); + +ImagePopover = (function(superClass) { + extend(ImagePopover, superClass); + + function ImagePopover() { + return ImagePopover.__super__.constructor.apply(this, arguments); + } + + ImagePopover.prototype.offset = { + top: 6, + left: -4 + }; + + ImagePopover.prototype.render = function() { + var tpl; + tpl = "<div class=\"link-settings\">\n <div class=\"settings-field\">\n <label>" + (this._t('imageUrl')) + "</label>\n <input class=\"image-src\" type=\"text\" tabindex=\"1\" />\n <a class=\"btn-upload\" href=\"javascript:;\"\n title=\"" + (this._t('uploadImage')) + "\" tabindex=\"-1\">\n <span class=\"simditor-icon simditor-icon-upload\"></span>\n </a>\n </div>\n <div class='settings-field'>\n <label>" + (this._t('imageAlt')) + "</label>\n <input class=\"image-alt\" id=\"image-alt\" type=\"text\" tabindex=\"1\" />\n </div>\n <div class=\"settings-field\">\n <label>" + (this._t('imageSize')) + "</label>\n <input class=\"image-size\" id=\"image-width\" type=\"text\" tabindex=\"2\" />\n <span class=\"times\">×</span>\n <input class=\"image-size\" id=\"image-height\" type=\"text\" tabindex=\"3\" />\n <a class=\"btn-restore\" href=\"javascript:;\"\n title=\"" + (this._t('restoreImageSize')) + "\" tabindex=\"-1\">\n <span class=\"simditor-icon simditor-icon-undo\"></span>\n </a>\n </div>\n</div>"; + this.el.addClass('image-popover').append(tpl); + this.srcEl = this.el.find('.image-src'); + this.widthEl = this.el.find('#image-width'); + this.heightEl = this.el.find('#image-height'); + this.altEl = this.el.find('#image-alt'); + this.srcEl.on('keydown', (function(_this) { + return function(e) { + var range; + if (!(e.which === 13 && !_this.target.hasClass('uploading'))) { + return; + } + e.preventDefault(); + range = document.createRange(); + _this.button.editor.selection.setRangeAfter(_this.target, range); + return _this.hide(); + }; + })(this)); + this.srcEl.on('blur', (function(_this) { + return function(e) { + return _this._loadImage(_this.srcEl.val()); + }; + })(this)); + this.el.find('.image-size').on('blur', (function(_this) { + return function(e) { + _this._resizeImg($(e.currentTarget)); + return _this.el.data('popover').refresh(); + }; + })(this)); + this.el.find('.image-size').on('keyup', (function(_this) { + return function(e) { + var inputEl; + inputEl = $(e.currentTarget); + if (!(e.which === 13 || e.which === 27 || e.which === 9)) { + return _this._resizeImg(inputEl, true); + } + }; + })(this)); + this.el.find('.image-size').on('keydown', (function(_this) { + return function(e) { + var $img, inputEl, range; + inputEl = $(e.currentTarget); + if (e.which === 13 || e.which === 27) { + e.preventDefault(); + if (e.which === 13) { + _this._resizeImg(inputEl); + } else { + _this._restoreImg(); + } + $img = _this.target; + _this.hide(); + range = document.createRange(); + return _this.button.editor.selection.setRangeAfter($img, range); + } else if (e.which === 9) { + return _this.el.data('popover').refresh(); + } + }; + })(this)); + this.altEl.on('keydown', (function(_this) { + return function(e) { + var range; + if (e.which === 13) { + e.preventDefault(); + range = document.createRange(); + _this.button.editor.selection.setRangeAfter(_this.target, range); + return _this.hide(); + } + }; + })(this)); + this.altEl.on('keyup', (function(_this) { + return function(e) { + if (e.which === 13 || e.which === 27 || e.which === 9) { + return; + } + _this.alt = _this.altEl.val(); + return _this.target.attr('alt', _this.alt); + }; + })(this)); + this.el.find('.btn-restore').on('click', (function(_this) { + return function(e) { + _this._restoreImg(); + return _this.el.data('popover').refresh(); + }; + })(this)); + this.editor.on('valuechanged', (function(_this) { + return function(e) { + if (_this.active) { + return _this.refresh(); + } + }; + })(this)); + return this._initUploader(); + }; + + ImagePopover.prototype._initUploader = function() { + var $uploadBtn, createInput; + $uploadBtn = this.el.find('.btn-upload'); + if (this.editor.uploader == null) { + $uploadBtn.remove(); + return; + } + createInput = (function(_this) { + return function() { + if (_this.input) { + _this.input.remove(); + } + return _this.input = $('<input/>', { + type: 'file', + title: _this._t('uploadImage'), + multiple: true, + accept: 'image/gif,image/jpeg,image/jpg,image/png,image/svg' + }).appendTo($uploadBtn); + }; + })(this); + createInput(); + this.el.on('click mousedown', 'input[type=file]', function(e) { + return e.stopPropagation(); + }); + return this.el.on('change', 'input[type=file]', (function(_this) { + return function(e) { + _this.editor.uploader.upload(_this.input, { + inline: true, + img: _this.target + }); + return createInput(); + }; + })(this)); + }; + + ImagePopover.prototype._resizeImg = function(inputEl, onlySetVal) { + var height, value, width; + if (onlySetVal == null) { + onlySetVal = false; + } + value = inputEl.val() * 1; + if (!(this.target && ($.isNumeric(value) || value < 0))) { + return; + } + if (inputEl.is(this.widthEl)) { + width = value; + height = this.height * value / this.width; + this.heightEl.val(height); + } else { + height = value; + width = this.width * value / this.height; + this.widthEl.val(width); + } + if (!onlySetVal) { + this.target.attr({ + width: width, + height: height + }); + return this.editor.trigger('valuechanged'); + } + }; + + ImagePopover.prototype._restoreImg = function() { + var ref, size; + size = ((ref = this.target.data('image-size')) != null ? ref.split(",") : void 0) || [this.width, this.height]; + this.target.attr({ + width: size[0] * 1, + height: size[1] * 1 + }); + this.widthEl.val(size[0]); + this.heightEl.val(size[1]); + return this.editor.trigger('valuechanged'); + }; + + ImagePopover.prototype._loadImage = function(src, callback) { + if (/^data:image/.test(src) && !this.editor.uploader) { + if (callback) { + callback(false); + } + return; + } + if (this.target.attr('src') === src) { + return; + } + return this.button.loadImage(this.target, src, (function(_this) { + return function(img) { + var blob; + if (!img) { + return; + } + if (_this.active) { + _this.width = img.width; + _this.height = img.height; + _this.widthEl.val(_this.width); + _this.heightEl.val(_this.height); + } + if (/^data:image/.test(src)) { + blob = _this.editor.util.dataURLtoBlob(src); + blob.name = "Base64 Image.png"; + _this.editor.uploader.upload(blob, { + inline: true, + img: _this.target + }); + } else { + _this.editor.trigger('valuechanged'); + } + if (callback) { + return callback(img); + } + }; + })(this)); + }; + + ImagePopover.prototype.show = function() { + var $img, args; + args = 1 <= arguments.length ? slice.call(arguments, 0) : []; + ImagePopover.__super__.show.apply(this, args); + $img = this.target; + this.width = $img.width(); + this.height = $img.height(); + this.alt = $img.attr('alt'); + if ($img.hasClass('uploading')) { + return this.srcEl.val(this._t('uploading')).prop('disabled', true); + } else { + this.srcEl.val($img.attr('src')).prop('disabled', false); + this.widthEl.val(this.width); + this.heightEl.val(this.height); + return this.altEl.val(this.alt); + } + }; + + return ImagePopover; + +})(Popover); + +Simditor.Toolbar.addButton(ImageButton); + +IndentButton = (function(superClass) { + extend(IndentButton, superClass); + + function IndentButton() { + return IndentButton.__super__.constructor.apply(this, arguments); + } + + IndentButton.prototype.name = 'indent'; + + IndentButton.prototype.icon = 'indent'; + + IndentButton.prototype._init = function() { + var hotkey; + hotkey = this.editor.opts.tabIndent === false ? '' : ' (Tab)'; + this.title = this._t(this.name) + hotkey; + return IndentButton.__super__._init.call(this); + }; + + IndentButton.prototype._status = function() {}; + + IndentButton.prototype.command = function() { + return this.editor.indentation.indent(); + }; + + return IndentButton; + +})(Button); + +Simditor.Toolbar.addButton(IndentButton); + +OutdentButton = (function(superClass) { + extend(OutdentButton, superClass); + + function OutdentButton() { + return OutdentButton.__super__.constructor.apply(this, arguments); + } + + OutdentButton.prototype.name = 'outdent'; + + OutdentButton.prototype.icon = 'outdent'; + + OutdentButton.prototype._init = function() { + var hotkey; + hotkey = this.editor.opts.tabIndent === false ? '' : ' (Shift + Tab)'; + this.title = this._t(this.name) + hotkey; + return OutdentButton.__super__._init.call(this); + }; + + OutdentButton.prototype._status = function() {}; + + OutdentButton.prototype.command = function() { + return this.editor.indentation.indent(true); + }; + + return OutdentButton; + +})(Button); + +Simditor.Toolbar.addButton(OutdentButton); + +HrButton = (function(superClass) { + extend(HrButton, superClass); + + function HrButton() { + return HrButton.__super__.constructor.apply(this, arguments); + } + + HrButton.prototype.name = 'hr'; + + HrButton.prototype.icon = 'minus'; + + HrButton.prototype.htmlTag = 'hr'; + + HrButton.prototype._status = function() {}; + + HrButton.prototype.command = function() { + var $hr, $newBlock, $nextBlock, $rootBlock; + $rootBlock = this.editor.selection.rootNodes().first(); + $nextBlock = $rootBlock.next(); + if ($nextBlock.length > 0) { + this.editor.selection.save(); + } else { + $newBlock = $('<p/>').append(this.editor.util.phBr); + } + $hr = $('<hr/>').insertAfter($rootBlock); + if ($newBlock) { + $newBlock.insertAfter($hr); + this.editor.selection.setRangeAtStartOf($newBlock); + } else { + this.editor.selection.restore(); + } + return this.editor.trigger('valuechanged'); + }; + + return HrButton; + +})(Button); + +Simditor.Toolbar.addButton(HrButton); + +TableButton = (function(superClass) { + extend(TableButton, superClass); + + function TableButton() { + return TableButton.__super__.constructor.apply(this, arguments); + } + + TableButton.prototype.name = 'table'; + + TableButton.prototype.icon = 'table'; + + TableButton.prototype.htmlTag = 'table'; + + TableButton.prototype.disableTag = 'pre, li, blockquote'; + + TableButton.prototype.menu = true; + + TableButton.prototype._init = function() { + TableButton.__super__._init.call(this); + $.merge(this.editor.formatter._allowedTags, ['thead', 'th', 'tbody', 'tr', 'td', 'colgroup', 'col']); + $.extend(this.editor.formatter._allowedAttributes, { + td: ['rowspan', 'colspan'], + col: ['width'] + }); + $.extend(this.editor.formatter._allowedStyles, { + td: ['text-align'], + th: ['text-align'] + }); + this._initShortcuts(); + this._initResize(); + this.editor.on('decorate', (function(_this) { + return function(e, $el) { + return $el.find('table').each(function(i, table) { + return _this.decorate($(table)); + }); + }; + })(this)); + this.editor.on('undecorate', (function(_this) { + return function(e, $el) { + return $el.find('table').each(function(i, table) { + return _this.undecorate($(table)); + }); + }; + })(this)); + this.editor.on('selectionchanged.table', (function(_this) { + return function(e) { + var $container, range; + _this.editor.body.find('.simditor-table td, .simditor-table th').removeClass('active'); + range = _this.editor.selection.range(); + if (!range) { + return; + } + $container = _this.editor.selection.containerNode(); + if (range.collapsed && $container.is('.simditor-table')) { + _this.editor.selection.setRangeAtEndOf($container); + } + return $container.closest('td, th', _this.editor.body).addClass('active'); + }; + })(this)); + this.editor.on('blur.table', (function(_this) { + return function(e) { + return _this.editor.body.find('.simditor-table td, .simditor-table th').removeClass('active'); + }; + })(this)); + this.editor.keystroke.add('up', 'td', (function(_this) { + return function(e, $node) { + _this._tdNav($node, 'up'); + return true; + }; + })(this)); + this.editor.keystroke.add('up', 'th', (function(_this) { + return function(e, $node) { + _this._tdNav($node, 'up'); + return true; + }; + })(this)); + this.editor.keystroke.add('down', 'td', (function(_this) { + return function(e, $node) { + _this._tdNav($node, 'down'); + return true; + }; + })(this)); + return this.editor.keystroke.add('down', 'th', (function(_this) { + return function(e, $node) { + _this._tdNav($node, 'down'); + return true; + }; + })(this)); + }; + + TableButton.prototype._tdNav = function($td, direction) { + var $anotherTr, $tr, action, anotherTag, index, parentTag, ref; + if (direction == null) { + direction = 'up'; + } + action = direction === 'up' ? 'prev' : 'next'; + ref = direction === 'up' ? ['tbody', 'thead'] : ['thead', 'tbody'], parentTag = ref[0], anotherTag = ref[1]; + $tr = $td.parent('tr'); + $anotherTr = this["_" + action + "Row"]($tr); + if (!($anotherTr.length > 0)) { + return true; + } + index = $tr.find('td, th').index($td); + return this.editor.selection.setRangeAtEndOf($anotherTr.find('td, th').eq(index)); + }; + + TableButton.prototype._nextRow = function($tr) { + var $nextTr; + $nextTr = $tr.next('tr'); + if ($nextTr.length < 1 && $tr.parent('thead').length > 0) { + $nextTr = $tr.parent('thead').next('tbody').find('tr:first'); + } + return $nextTr; + }; + + TableButton.prototype._prevRow = function($tr) { + var $prevTr; + $prevTr = $tr.prev('tr'); + if ($prevTr.length < 1 && $tr.parent('tbody').length > 0) { + $prevTr = $tr.parent('tbody').prev('thead').find('tr'); + } + return $prevTr; + }; + + TableButton.prototype._initResize = function() { + var $editor; + $editor = this.editor; + $(document).on('mousemove.simditor-table', '.simditor-table td, .simditor-table th', function(e) { + var $col, $colgroup, $resizeHandle, $td, $wrapper, index, ref, ref1, x; + $wrapper = $(this).parents('.simditor-table'); + $resizeHandle = $wrapper.find('.simditor-resize-handle'); + $colgroup = $wrapper.find('colgroup'); + if ($wrapper.hasClass('resizing')) { + return; + } + $td = $(e.currentTarget); + x = e.pageX - $(e.currentTarget).offset().left; + if (x < 5 && $td.prev().length > 0) { + $td = $td.prev(); + } + if ($td.next('td, th').length < 1) { + $resizeHandle.hide(); + return; + } + if ((ref = $resizeHandle.data('td')) != null ? ref.is($td) : void 0) { + $resizeHandle.show(); + return; + } + index = $td.parent().find('td, th').index($td); + $col = $colgroup.find('col').eq(index); + if ((ref1 = $resizeHandle.data('col')) != null ? ref1.is($col) : void 0) { + $resizeHandle.show(); + return; + } + return $resizeHandle.css('left', $td.position().left + $td.outerWidth() - 5).data('td', $td).data('col', $col).show(); + }); + $(document).on('mouseleave.simditor-table', '.simditor-table', function(e) { + return $(this).find('.simditor-resize-handle').hide(); + }); + return $(document).on('mousedown.simditor-resize-handle', '.simditor-resize-handle', function(e) { + var $handle, $leftCol, $leftTd, $rightCol, $rightTd, $wrapper, minWidth, startHandleLeft, startLeftWidth, startRightWidth, startX, tableWidth; + $wrapper = $(this).parent('.simditor-table'); + $handle = $(e.currentTarget); + $leftTd = $handle.data('td'); + $leftCol = $handle.data('col'); + $rightTd = $leftTd.next('td, th'); + $rightCol = $leftCol.next('col'); + startX = e.pageX; + startLeftWidth = $leftTd.outerWidth() * 1; + startRightWidth = $rightTd.outerWidth() * 1; + startHandleLeft = parseFloat($handle.css('left')); + tableWidth = $leftTd.closest('table').width(); + minWidth = 50; + $(document).on('mousemove.simditor-resize-table', function(e) { + var deltaX, leftWidth, rightWidth; + deltaX = e.pageX - startX; + leftWidth = startLeftWidth + deltaX; + rightWidth = startRightWidth - deltaX; + if (leftWidth < minWidth) { + leftWidth = minWidth; + deltaX = minWidth - startLeftWidth; + rightWidth = startRightWidth - deltaX; + } else if (rightWidth < minWidth) { + rightWidth = minWidth; + deltaX = startRightWidth - minWidth; + leftWidth = startLeftWidth + deltaX; + } + $leftCol.attr('width', (leftWidth / tableWidth * 100) + '%'); + $rightCol.attr('width', (rightWidth / tableWidth * 100) + '%'); + return $handle.css('left', startHandleLeft + deltaX); + }); + $(document).one('mouseup.simditor-resize-table', function(e) { + $editor.sync(); + $(document).off('.simditor-resize-table'); + return $wrapper.removeClass('resizing'); + }); + $wrapper.addClass('resizing'); + return false; + }); + }; + + TableButton.prototype._initShortcuts = function() { + this.editor.hotkeys.add('ctrl+alt+up', (function(_this) { + return function(e) { + _this.editMenu.find('.menu-item[data-param=insertRowAbove]').click(); + return false; + }; + })(this)); + this.editor.hotkeys.add('ctrl+alt+down', (function(_this) { + return function(e) { + _this.editMenu.find('.menu-item[data-param=insertRowBelow]').click(); + return false; + }; + })(this)); + this.editor.hotkeys.add('ctrl+alt+left', (function(_this) { + return function(e) { + _this.editMenu.find('.menu-item[data-param=insertColLeft]').click(); + return false; + }; + })(this)); + return this.editor.hotkeys.add('ctrl+alt+right', (function(_this) { + return function(e) { + _this.editMenu.find('.menu-item[data-param=insertColRight]').click(); + return false; + }; + })(this)); + }; + + TableButton.prototype.decorate = function($table) { + var $colgroup, $headRow, $resizeHandle, $tbody, $thead, $wrapper; + if ($table.parent('.simditor-table').length > 0) { + this.undecorate($table); + } + $table.wrap('<div class="simditor-table"></div>'); + $wrapper = $table.parent('.simditor-table'); + $colgroup = $table.find('colgroup'); + if ($table.find('thead').length < 1) { + $thead = $('<thead />'); + $headRow = $table.find('tr').first(); + $thead.append($headRow); + this._changeCellTag($headRow, 'th'); + $tbody = $table.find('tbody'); + if ($tbody.length > 0) { + $tbody.before($thead); + } else { + $table.prepend($thead); + } + } + if ($colgroup.length < 1) { + $colgroup = $('<colgroup/>').prependTo($table); + $table.find('thead tr th').each(function(i, td) { + var $col; + return $col = $('<col/>').appendTo($colgroup); + }); + this.refreshTableWidth($table); + } + $resizeHandle = $('<div />', { + "class": 'simditor-resize-handle', + contenteditable: 'false' + }).appendTo($wrapper); + return $table.parent(); + }; + + TableButton.prototype.undecorate = function($table) { + if (!($table.parent('.simditor-table').length > 0)) { + return; + } + return $table.parent().replaceWith($table); + }; + + TableButton.prototype.renderMenu = function() { + var $table; + $("<div class=\"menu-create-table\">\n</div>\n<div class=\"menu-edit-table\">\n <ul>\n <li>\n <a tabindex=\"-1\" unselectable=\"on\" class=\"menu-item\"\n href=\"javascript:;\" data-param=\"deleteRow\">\n <span>" + (this._t('deleteRow')) + "</span>\n </a>\n </li>\n <li>\n <a tabindex=\"-1\" unselectable=\"on\" class=\"menu-item\"\n href=\"javascript:;\" data-param=\"insertRowAbove\">\n <span>" + (this._t('insertRowAbove')) + " ( Ctrl + Alt + ↑ )</span>\n </a>\n </li>\n <li>\n <a tabindex=\"-1\" unselectable=\"on\" class=\"menu-item\"\n href=\"javascript:;\" data-param=\"insertRowBelow\">\n <span>" + (this._t('insertRowBelow')) + " ( Ctrl + Alt + ↓ )</span>\n </a>\n </li>\n <li><span class=\"separator\"></span></li>\n <li>\n <a tabindex=\"-1\" unselectable=\"on\" class=\"menu-item\"\n href=\"javascript:;\" data-param=\"deleteCol\">\n <span>" + (this._t('deleteColumn')) + "</span>\n </a>\n </li>\n <li>\n <a tabindex=\"-1\" unselectable=\"on\" class=\"menu-item\"\n href=\"javascript:;\" data-param=\"insertColLeft\">\n <span>" + (this._t('insertColumnLeft')) + " ( Ctrl + Alt + ← )</span>\n </a>\n </li>\n <li>\n <a tabindex=\"-1\" unselectable=\"on\" class=\"menu-item\"\n href=\"javascript:;\" data-param=\"insertColRight\">\n <span>" + (this._t('insertColumnRight')) + " ( Ctrl + Alt + → )</span>\n </a>\n </li>\n <li><span class=\"separator\"></span></li>\n <li>\n <a tabindex=\"-1\" unselectable=\"on\" class=\"menu-item\"\n href=\"javascript:;\" data-param=\"deleteTable\">\n <span>" + (this._t('deleteTable')) + "</span>\n </a>\n </li>\n </ul>\n</div>").appendTo(this.menuWrapper); + this.createMenu = this.menuWrapper.find('.menu-create-table'); + this.editMenu = this.menuWrapper.find('.menu-edit-table'); + $table = this.createTable(6, 6).appendTo(this.createMenu); + this.createMenu.on('mouseenter', 'td, th', (function(_this) { + return function(e) { + var $td, $tr, $trs, num; + _this.createMenu.find('td, th').removeClass('selected'); + $td = $(e.currentTarget); + $tr = $td.parent(); + num = $tr.find('td, th').index($td) + 1; + $trs = $tr.prevAll('tr').addBack(); + if ($tr.parent().is('tbody')) { + $trs = $trs.add($table.find('thead tr')); + } + return $trs.find("td:lt(" + num + "), th:lt(" + num + ")").addClass('selected'); + }; + })(this)); + this.createMenu.on('mouseleave', function(e) { + return $(e.currentTarget).find('td, th').removeClass('selected'); + }); + return this.createMenu.on('mousedown', 'td, th', (function(_this) { + return function(e) { + var $closestBlock, $td, $tr, colNum, rowNum; + _this.wrapper.removeClass('menu-on'); + if (!_this.editor.inputManager.focused) { + return; + } + $td = $(e.currentTarget); + $tr = $td.parent(); + colNum = $tr.find('td').index($td) + 1; + rowNum = $tr.prevAll('tr').length + 1; + if ($tr.parent().is('tbody')) { + rowNum += 1; + } + $table = _this.createTable(rowNum, colNum, true); + $closestBlock = _this.editor.selection.blockNodes().last(); + if (_this.editor.util.isEmptyNode($closestBlock)) { + $closestBlock.replaceWith($table); + } else { + $closestBlock.after($table); + } + _this.decorate($table); + _this.editor.selection.setRangeAtStartOf($table.find('th:first')); + _this.editor.trigger('valuechanged'); + return false; + }; + })(this)); + }; + + TableButton.prototype.createTable = function(row, col, phBr) { + var $table, $tbody, $td, $thead, $tr, c, k, l, r, ref, ref1; + $table = $('<table/>'); + $thead = $('<thead/>').appendTo($table); + $tbody = $('<tbody/>').appendTo($table); + for (r = k = 0, ref = row; 0 <= ref ? k < ref : k > ref; r = 0 <= ref ? ++k : --k) { + $tr = $('<tr/>'); + $tr.appendTo(r === 0 ? $thead : $tbody); + for (c = l = 0, ref1 = col; 0 <= ref1 ? l < ref1 : l > ref1; c = 0 <= ref1 ? ++l : --l) { + $td = $(r === 0 ? '<th/>' : '<td/>').appendTo($tr); + if (phBr) { + $td.append(this.editor.util.phBr); + } + } + } + return $table; + }; + + TableButton.prototype.refreshTableWidth = function($table) { + return setTimeout((function(_this) { + return function() { + var cols, tableWidth; + tableWidth = $table.width(); + cols = $table.find('col'); + return $table.find('thead tr th').each(function(i, td) { + var $col; + $col = cols.eq(i); + return $col.attr('width', ($(td).outerWidth() / tableWidth * 100) + '%'); + }); + }; + })(this), 0); + }; + + TableButton.prototype.setActive = function(active) { + TableButton.__super__.setActive.call(this, active); + if (active) { + this.createMenu.hide(); + return this.editMenu.show(); + } else { + this.createMenu.show(); + return this.editMenu.hide(); + } + }; + + TableButton.prototype._changeCellTag = function($tr, tagName) { + return $tr.find('td, th').each(function(i, cell) { + var $cell; + $cell = $(cell); + return $cell.replaceWith("<" + tagName + ">" + ($cell.html()) + "</" + tagName + ">"); + }); + }; + + TableButton.prototype.deleteRow = function($td) { + var $newTr, $tr, index; + $tr = $td.parent('tr'); + if ($tr.closest('table').find('tr').length < 1) { + return this.deleteTable($td); + } else { + $newTr = this._nextRow($tr); + if (!($newTr.length > 0)) { + $newTr = this._prevRow($tr); + } + index = $tr.find('td, th').index($td); + if ($tr.parent().is('thead')) { + $newTr.appendTo($tr.parent()); + this._changeCellTag($newTr, 'th'); + } + $tr.remove(); + return this.editor.selection.setRangeAtEndOf($newTr.find('td, th').eq(index)); + } + }; + + TableButton.prototype.insertRow = function($td, direction) { + var $newTr, $table, $tr, cellTag, colNum, i, index, k, ref; + if (direction == null) { + direction = 'after'; + } + $tr = $td.parent('tr'); + $table = $tr.closest('table'); + colNum = 0; + $table.find('tr').each(function(i, tr) { + return colNum = Math.max(colNum, $(tr).find('td').length); + }); + index = $tr.find('td, th').index($td); + $newTr = $('<tr/>'); + cellTag = 'td'; + if (direction === 'after' && $tr.parent().is('thead')) { + $tr.parent().next('tbody').prepend($newTr); + } else if (direction === 'before' && $tr.parent().is('thead')) { + $tr.before($newTr); + $tr.parent().next('tbody').prepend($tr); + this._changeCellTag($tr, 'td'); + cellTag = 'th'; + } else { + $tr[direction]($newTr); + } + for (i = k = 1, ref = colNum; 1 <= ref ? k <= ref : k >= ref; i = 1 <= ref ? ++k : --k) { + $("<" + cellTag + "/>").append(this.editor.util.phBr).appendTo($newTr); + } + return this.editor.selection.setRangeAtStartOf($newTr.find('td, th').eq(index)); + }; + + TableButton.prototype.deleteCol = function($td) { + var $newTd, $table, $tr, index, noOtherCol, noOtherRow; + $tr = $td.parent('tr'); + noOtherRow = $tr.closest('table').find('tr').length < 2; + noOtherCol = $td.siblings('td, th').length < 1; + if (noOtherRow && noOtherCol) { + return this.deleteTable($td); + } else { + index = $tr.find('td, th').index($td); + $newTd = $td.next('td, th'); + if (!($newTd.length > 0)) { + $newTd = $tr.prev('td, th'); + } + $table = $tr.closest('table'); + $table.find('col').eq(index).remove(); + $table.find('tr').each(function(i, tr) { + return $(tr).find('td, th').eq(index).remove(); + }); + this.refreshTableWidth($table); + return this.editor.selection.setRangeAtEndOf($newTd); + } + }; + + TableButton.prototype.insertCol = function($td, direction) { + var $col, $newCol, $newTd, $table, $tr, index, tableWidth, width; + if (direction == null) { + direction = 'after'; + } + $tr = $td.parent('tr'); + index = $tr.find('td, th').index($td); + $table = $td.closest('table'); + $col = $table.find('col').eq(index); + $table.find('tr').each((function(_this) { + return function(i, tr) { + var $newTd, cellTag; + cellTag = $(tr).parent().is('thead') ? 'th' : 'td'; + $newTd = $("<" + cellTag + "/>").append(_this.editor.util.phBr); + return $(tr).find('td, th').eq(index)[direction]($newTd); + }; + })(this)); + $newCol = $('<col/>'); + $col[direction]($newCol); + tableWidth = $table.width(); + width = Math.max(parseFloat($col.attr('width')) / 2, 50 / tableWidth * 100); + $col.attr('width', width + '%'); + $newCol.attr('width', width + '%'); + this.refreshTableWidth($table); + $newTd = direction === 'after' ? $td.next('td, th') : $td.prev('td, th'); + return this.editor.selection.setRangeAtStartOf($newTd); + }; + + TableButton.prototype.deleteTable = function($td) { + var $block, $table; + $table = $td.closest('.simditor-table'); + $block = $table.next('p'); + $table.remove(); + if ($block.length > 0) { + return this.editor.selection.setRangeAtStartOf($block); + } + }; + + TableButton.prototype.command = function(param) { + var $td; + $td = this.editor.selection.containerNode().closest('td, th'); + if (!($td.length > 0)) { + return; + } + if (param === 'deleteRow') { + this.deleteRow($td); + } else if (param === 'insertRowAbove') { + this.insertRow($td, 'before'); + } else if (param === 'insertRowBelow') { + this.insertRow($td); + } else if (param === 'deleteCol') { + this.deleteCol($td); + } else if (param === 'insertColLeft') { + this.insertCol($td, 'before'); + } else if (param === 'insertColRight') { + this.insertCol($td); + } else if (param === 'deleteTable') { + this.deleteTable($td); + } else { + return; + } + return this.editor.trigger('valuechanged'); + }; + + return TableButton; + +})(Button); + +Simditor.Toolbar.addButton(TableButton); + +StrikethroughButton = (function(superClass) { + extend(StrikethroughButton, superClass); + + function StrikethroughButton() { + return StrikethroughButton.__super__.constructor.apply(this, arguments); + } + + StrikethroughButton.prototype.name = 'strikethrough'; + + StrikethroughButton.prototype.icon = 'strikethrough'; + + StrikethroughButton.prototype.htmlTag = 'strike'; + + StrikethroughButton.prototype.disableTag = 'pre'; + + StrikethroughButton.prototype._activeStatus = function() { + var active; + active = document.queryCommandState('strikethrough') === true; + this.setActive(active); + return this.active; + }; + + StrikethroughButton.prototype.command = function() { + document.execCommand('strikethrough'); + if (!this.editor.util.support.oninput) { + this.editor.trigger('valuechanged'); + } + return $(document).trigger('selectionchange'); + }; + + return StrikethroughButton; + +})(Button); + +Simditor.Toolbar.addButton(StrikethroughButton); + +AlignmentButton = (function(superClass) { + extend(AlignmentButton, superClass); + + function AlignmentButton() { + return AlignmentButton.__super__.constructor.apply(this, arguments); + } + + AlignmentButton.prototype.name = "alignment"; + + AlignmentButton.prototype.icon = 'align-left'; + + AlignmentButton.prototype.htmlTag = 'p, h1, h2, h3, h4, td, th'; + + AlignmentButton.prototype._init = function() { + this.menu = [ + { + name: 'left', + text: this._t('alignLeft'), + icon: 'align-left', + param: 'left' + }, { + name: 'center', + text: this._t('alignCenter'), + icon: 'align-center', + param: 'center' + }, { + name: 'right', + text: this._t('alignRight'), + icon: 'align-right', + param: 'right' + } + ]; + return AlignmentButton.__super__._init.call(this); + }; + + AlignmentButton.prototype.setActive = function(active, align) { + if (align == null) { + align = 'left'; + } + if (align !== 'left' && align !== 'center' && align !== 'right') { + align = 'left'; + } + if (align === 'left') { + AlignmentButton.__super__.setActive.call(this, false); + } else { + AlignmentButton.__super__.setActive.call(this, active); + } + this.el.removeClass('align-left align-center align-right'); + if (active) { + this.el.addClass('align-' + align); + } + this.setIcon('align-' + align); + return this.menuEl.find('.menu-item').show().end().find('.menu-item-' + align).hide(); + }; + + AlignmentButton.prototype._status = function() { + this.nodes = this.editor.selection.nodes().filter(this.htmlTag); + if (this.nodes.length < 1) { + this.setDisabled(true); + return this.setActive(false); + } else { + this.setDisabled(false); + return this.setActive(true, this.nodes.first().css('text-align')); + } + }; + + AlignmentButton.prototype.command = function(align) { + if (align !== 'left' && align !== 'center' && align !== 'right') { + throw new Error("simditor alignment button: invalid align " + align); + } + this.nodes.css({ + 'text-align': align === 'left' ? '' : align + }); + this.editor.trigger('valuechanged'); + return this.editor.inputManager.throttledSelectionChanged(); + }; + + return AlignmentButton; + +})(Button); + +Simditor.Toolbar.addButton(AlignmentButton); + +return Simditor; + +})); diff --git a/public/vendor/laravel-admin-ext/simditor/simditor-2.3.28/scripts/uploader.js b/public/vendor/laravel-admin-ext/simditor/simditor-2.3.28/scripts/uploader.js new file mode 100644 index 00000000..b46d1ab1 --- /dev/null +++ b/public/vendor/laravel-admin-ext/simditor/simditor-2.3.28/scripts/uploader.js @@ -0,0 +1,261 @@ +(function (root, factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module unless amdModuleId is set + define('simple-uploader', ["jquery","simple-module"], function ($, SimpleModule) { + return (root['uploader'] = factory($, SimpleModule)); + }); + } 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"),require("simple-module")); + } else { + root.simple = root.simple || {}; + root.simple['uploader'] = factory(jQuery,SimpleModule); + } +}(this, function ($, SimpleModule) { + +var Uploader, uploader, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + +Uploader = (function(superClass) { + extend(Uploader, superClass); + + function Uploader() { + return Uploader.__super__.constructor.apply(this, arguments); + } + + Uploader.count = 0; + + Uploader.prototype.opts = { + url: '', + params: null, + fileKey: 'upload_file', + connectionCount: 3 + }; + + Uploader.prototype._init = function() { + this.files = []; + this.queue = []; + this.id = ++Uploader.count; + this.on('uploadcomplete', (function(_this) { + return function(e, file) { + _this.files.splice($.inArray(file, _this.files), 1); + if (_this.queue.length > 0 && _this.files.length < _this.opts.connectionCount) { + return _this.upload(_this.queue.shift()); + } else if (_this.files.length === 0) { + return _this.uploading = false; + } + }; + })(this)); + return $(window).on('beforeunload.uploader-' + this.id, (function(_this) { + return function(e) { + if (!_this.uploading) { + return; + } + e.originalEvent.returnValue = _this._t('leaveConfirm'); + return _this._t('leaveConfirm'); + }; + })(this)); + }; + + Uploader.prototype.generateId = (function() { + var id; + id = 0; + return function() { + return id += 1; + }; + })(); + + Uploader.prototype.upload = function(file, opts) { + var f, i, key, len; + if (opts == null) { + opts = {}; + } + if (file == null) { + return; + } + if ($.isArray(file) || file instanceof FileList) { + for (i = 0, len = file.length; i < len; i++) { + f = file[i]; + this.upload(f, opts); + } + } else if ($(file).is('input:file')) { + key = $(file).attr('name'); + if (key) { + opts.fileKey = key; + } + this.upload($.makeArray($(file)[0].files), opts); + } else if (!file.id || !file.obj) { + file = this.getFile(file); + } + if (!(file && file.obj)) { + return; + } + $.extend(file, opts); + if (this.files.length >= this.opts.connectionCount) { + this.queue.push(file); + return; + } + if (this.triggerHandler('beforeupload', [file]) === false) { + return; + } + this.files.push(file); + this._xhrUpload(file); + return this.uploading = true; + }; + + Uploader.prototype.getFile = function(fileObj) { + var name, ref, ref1; + if (fileObj instanceof window.File || fileObj instanceof window.Blob) { + name = (ref = fileObj.fileName) != null ? ref : fileObj.name; + } else { + return null; + } + return { + id: this.generateId(), + url: this.opts.url, + params: this.opts.params, + fileKey: this.opts.fileKey, + name: name, + size: (ref1 = fileObj.fileSize) != null ? ref1 : fileObj.size, + ext: name ? name.split('.').pop().toLowerCase() : '', + obj: fileObj + }; + }; + + Uploader.prototype._xhrUpload = function(file) { + var formData, k, ref, v; + formData = new FormData(); + formData.append(file.fileKey, file.obj); + formData.append("original_filename", file.name); + if (file.params) { + ref = file.params; + for (k in ref) { + v = ref[k]; + formData.append(k, v); + } + } + return file.xhr = $.ajax({ + url: file.url, + data: formData, + processData: false, + contentType: false, + type: 'POST', + headers: { + 'X-File-Name': encodeURIComponent(file.name) + }, + xhr: function() { + var req; + req = $.ajaxSettings.xhr(); + if (req) { + req.upload.onprogress = (function(_this) { + return function(e) { + return _this.progress(e); + }; + })(this); + } + return req; + }, + progress: (function(_this) { + return function(e) { + if (!e.lengthComputable) { + return; + } + return _this.trigger('uploadprogress', [file, e.loaded, e.total]); + }; + })(this), + error: (function(_this) { + return function(xhr, status, err) { + return _this.trigger('uploaderror', [file, xhr, status]); + }; + })(this), + success: (function(_this) { + return function(result) { + _this.trigger('uploadprogress', [file, file.size, file.size]); + _this.trigger('uploadsuccess', [file, result]); + return $(document).trigger('uploadsuccess', [file, result, _this]); + }; + })(this), + complete: (function(_this) { + return function(xhr, status) { + return _this.trigger('uploadcomplete', [file, xhr.responseText]); + }; + })(this) + }); + }; + + Uploader.prototype.cancel = function(file) { + var f, i, len, ref; + if (!file.id) { + ref = this.files; + for (i = 0, len = ref.length; i < len; i++) { + f = ref[i]; + if (f.id === file * 1) { + file = f; + break; + } + } + } + this.trigger('uploadcancel', [file]); + if (file.xhr) { + file.xhr.abort(); + } + return file.xhr = null; + }; + + Uploader.prototype.readImageFile = function(fileObj, callback) { + var fileReader, img; + if (!$.isFunction(callback)) { + return; + } + img = new Image(); + img.onload = function() { + return callback(img); + }; + img.onerror = function() { + return callback(); + }; + if (window.FileReader && FileReader.prototype.readAsDataURL && /^image/.test(fileObj.type)) { + fileReader = new FileReader(); + fileReader.onload = function(e) { + return img.src = e.target.result; + }; + return fileReader.readAsDataURL(fileObj); + } else { + return callback(); + } + }; + + Uploader.prototype.destroy = function() { + var file, i, len, ref; + this.queue.length = 0; + ref = this.files; + for (i = 0, len = ref.length; i < len; i++) { + file = ref[i]; + this.cancel(file); + } + $(window).off('.uploader-' + this.id); + return $(document).off('.uploader-' + this.id); + }; + + Uploader.i18n = { + 'zh-CN': { + leaveConfirm: '正在上传文件,如果离开上传会自动取消' + } + }; + + Uploader.locale = 'zh-CN'; + + return Uploader; + +})(SimpleModule); + +uploader = function(opts) { + return new Uploader(opts); +}; + +return uploader; + +})); diff --git a/public/vendor/laravel-admin-ext/simditor/simditor-2.3.28/styles/customized.css b/public/vendor/laravel-admin-ext/simditor/simditor-2.3.28/styles/customized.css new file mode 100644 index 00000000..2296a58b --- /dev/null +++ b/public/vendor/laravel-admin-ext/simditor/simditor-2.3.28/styles/customized.css @@ -0,0 +1,11 @@ +/*! +* github.com/jxlwqq +* 2020-11-20 +*/ + +/*It prevents the used value of the width property from becoming larger than the value specified by max-width.*/ +.simditor .simditor-body img { + cursor: pointer; + max-width: 100%; + height: auto; +} \ No newline at end of file diff --git a/public/vendor/laravel-admin-ext/simditor/simditor-2.3.28/styles/simditor.css b/public/vendor/laravel-admin-ext/simditor/simditor-2.3.28/styles/simditor.css new file mode 100644 index 00000000..bb9cc4d9 --- /dev/null +++ b/public/vendor/laravel-admin-ext/simditor/simditor-2.3.28/styles/simditor.css @@ -0,0 +1,749 @@ +/*! +* Simditor v2.3.27 +* http://simditor.tower.im/ +* 2019-08-15 +*/ +@font-face { + font-family: 'Simditor'; + src: url(data:application/font-woff;charset=utf-8;base64,d09GRgABAAAAABp8AA4AAAAAKmwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABGRlRNAAAaYAAAABoAAAAcdO8GE09TLzIAAAG0AAAARQAAAGAQ+ZFXY21hcAAAAkgAAABRAAABWuA2Gx9jdnQgAAAEgAAAAAoAAAAKAwQAxGZwZ20AAAKcAAABsQAAAmUPtC+nZ2x5ZgAABNgAABPeAAAgZG/p6QxoZWFkAAABRAAAADAAAAA2BvuCgGhoZWEAAAF0AAAAHgAAACQH9QTlaG10eAAAAfwAAABKAAAAlHv7AItsb2NhAAAEjAAAAEwAAABMi4qTXm1heHAAAAGUAAAAIAAAACABRwHNbmFtZQAAGLgAAAEFAAAB12vS/ulwb3N0AAAZwAAAAJ4AAAFsyCrvunByZXAAAARQAAAALgAAAC6w8isUeNpjYGRgYADiKAkPy3h+m68M8swfgCIMF0/IVyDo/84sFswJQC4HAxNIFAAZwAnyeNpjYGRgYE5gmMAQzWLBwPD/O5AEiqAAVQBa6wPkAAAAAQAAACUAoAAKAAAAAAACAAEAAgAWAAABAAEpAAAAAHjaY2BhnsA4gYGVgYGpn+kgAwNDL4RmfMxgxMgCFGVgZWaAAUYBBjTQwMDwQY454X8BQzRzAsMEIJcRSVaBgREAQ9oK6QAAAHjaY8xhUGQAAsYABgbmDwjMYsEgxCzBwMDkAOQnALEEgx1UjhNMr4BjTqBakDxC/wqIPsYMqJoEKIbpk0C1C4zXM3DA5AEzchbtAAB42mNgYGBmgGAZBkYGEAgB8hjBfBYGCyDNxcDBwASEDAy8DAof5P7/B6sCsRmAbOb/3/8/FWCD6oUCRjaIkWA2SCcLAyoAqmZlGN4AALmUC0kAAAB42l1Ru05bQRDdDQ8DgcTYIDnaFLOZkALvhTZIIK4uwsh2YzlC2o1c5GJcwAdQIFGD9msGaChTpE2DkAskPoFPiJSZNYmiNDs7s3POmTNLypGqd2m956lzFkjhboNmm34npNpFgAfS9Y1GRtrBIy02M3rlun2/j8FmNOVOGkB5z1vKQ0bTTqAW7bl/Mj+D4T7/yzwHg5Zmmp5aZyE9hMB8M25p8DWjWXf9QV+xOlwNBoYU01Tc9cdUyv+W5lxtGbY2M5p3cCEiP5gGaGqtjUDTnzqkej6OYgly+WysDSamrD/JRHBhMl3VVC0zvnZwn+wsOtikSnPgAQ6wVZ6Ch+OjCYX0LYkyS0OEg9gqMULEJIdCTjl3sj8pUD6ShDFvktLOuGGtgXHkNTCozdMcvsxmU9tbhzB+EUfw3S/Gkg4+sqE2RoTYjlgKYAKRkFFVvqHGcy+LAbnU/jMQJWB5+u1fJwKtOzYRL2VtnWOMFYKe3zbf+WXF3apc50Whu3dVNVTplOZDL2ff4xFPj4XhoLHgzed9f6NA7Q2LGw2aA8GQ3o3e/9FadcRV3gsf2W81s7EWAAAAuAH/hbABjQBLsAhQWLEBAY5ZsUYGK1ghsBBZS7AUUlghsIBZHbAGK1xYWbAUKwAAAAAAowCFACECfwAAAAAAKgAqACoAKgAqACoAfgEkAcAChAK+A2oElgU2BbQGxgeYCBgIPgjGCU4KZgqKCq4LQAuYDDoMcAzuDXINoA4MDngO4g86D6QQMnjazVl5cBvXeX9vF4tdXHsBuwBBEvdBAgQXxOIgRPGQSEkULcoJJds6Yku2Na6TKJXHsnx0XNptHcvNpLaSJpkczthV68Zu0ulbQE58qXXaHK3j7ThjD6PmmnQmaTydSaqkmdbxkFC/tyApinXiuP2jlcC37/vegX3f8fu+7wExKIkQLjCPIxbxaNjCyNja4l3sTyqWm/vu1hbLQBdZLGVzlN3i3a7lrS1M+aaSVPKmkk5iz+tf/zrz+MrRJHMDgp3US3/tyjEvIQn1oiJCWd6dx7kGrsexLuGwjlm3AXSQ0h5M+5M4D3/1MNbx4b5AoPNmIIDdgQB0v/e9AJ78JqemVLfT4uN0sDtAHzBtvvvYsIK5aqWgcF6XyizRR+f+K9cAhRB9T3TpGTbCRlAARdAEehiRCYNwNulNLCmkzyZ+g6g2GTSIaJKCTUo2JpMGSS0RZBOp0kohb7E9lerzFMlghSDZ4nGRbLGJRpdXbGsKFy2UUlRL7Gk2iaacYzlfeCITbhJeJY0msvycorZj8eYWylMV4JFBtaXlKs1mszyS5UNh3azUqvlhnOLZsAZEvZpLp9gU35jAjfo4lvM5GEzn6xkzXAnrWogXMR/DITfvTuMy9hSyr0XSx+6VXa6+1NFbTrwrPvD+v8OevSHFLzT9cYbZgqXZ+U9cVahEC7nrTo6ZN33w2fdsCykvTOaaCTc+/vn7XbOf27X840CNEYXYRJYp6gEOswb24YPlHbsHtIgSvO1Tt/aNgglRWTJTIMsB9FeIDIAcTZKzidsmIYNoNumpEE0mvSDCQcMqgKDq0ecmDv/sY0grekXil4n0opXCvyTxF4Foi34pWCQpuZ1IxYPFdpK2LWAmPpT4UNotKmqzBTx4kEQTPe0X44lkatj5h6+gyFQUI8s9AErADCghpxChSUIq6W9aWq+iEh0EzeVzKTffqK/+V2sg03wjXKk33FSeImbcYKhhN4/fd9OemVtlr18f6ZF5rjKH9R0+33cKp0KsIC1o7ti2EsbaPoaf9TE+XHZxvoCWEf8N39gvBlhmi0fAkSinC+Kfdr71j6KX8/f3IsaxwaMgt13oOvSHqDWPUJHst4lgUJPbYrSVYGw6EzbJmG2FpioVMiaTCDWwcZMkbLKjgskBgwSWSMZuZQLUIDMxT7EVyNBuIAi2mZGtEbDEg/A3kgGDi/RuGQODQ1aiABSWA3WgrMgWkMa2JhlTyCTIBLxUhbO706lhZhxXc/mUgetmuFGpm3xYc6d4dz+mQgGbBJFN4OowNjCYIp9vmGG9EdZDsFbEwRoYbDIFk0O6mazUmTcx5w8nC4c/c/3p7WF9p8ozvPRZIiZYjLPTXh4L3N6Rxs1jUZ8Wcgksy/T3NAXGODmw0+tiotqg/xavsPwVwesV2K2Cl/ly0tv5m+Nbkjur+2+/7oX3J1hmBPMc5rMcJ/LTyd/77O8O9A6F5NSO04195WQ+hpmymxFwMCDybv/ymxm6EW2o/U5c+g/m28xHURrwSg9J2A0n5mmTq1J0gqZeiYPXQUOHmZdkeY9cVJ94Qi1CR37iiU30Y7+Cv0av4c9F0L2EBtEcWkTENMiMo3vJJmmD6OAuVwEILZGs3Z7IqkKRTNokK1uz4EAl29oDOp2cAMXJTZJVqPpm1afj+kChYlJIKSnnIv3R4qCjbWEGtF0ojU5SbaclIGQ12k+n6QqJUJVXdFCTG9SVA43XzUauVm3UzUoYAEUC7eaom4RA5WHeBPWKbIpqnBoHIFEjhqktgCHkc+z3qVyXq7TtjF6156NX3+4OMLwh9MVGPrhn7u6bzQd+7Ar7hq87cLq0N+lnmKasspMnM/trJQXf2tUIbTKzV98yuyunv6/pYVhmf9zcfnhPKp4+ox3a2j88qgd0r9fDjw8N4giTLrtu7Js5MCBRXHcjz6XbQK6HURiV0RSaR9ejD+BB1KpT3xq3iatCxmXC2hTHAeNlm0QNMmyTsk32GeSQTVIGydvkZoNsN8n7bKqSbZXWzM3UpWau8hQx+W2DsEtkrkIYmzCytQPUMW8TvtLaMU8n7Zj2FNvq/A7QV8IkXruleilbpaFiXrYMX5FE6J7WCVAgwyoqgJYWy+ym2tihtEOl4V1OSFCfllE4lb+KEvOK5RsCCPOqbTc3WHB0KvsB2LwB4NaVtkcMhuhEVrV4DVhIIUCNq8TdtIajYCS9TbIP4lqTlFVSapJDyrlYojCUoWtSKsk2SV4hg2AIDV5L10zNCSSpfMOJQXy+Pom1dK4KCFmrplNAmxWdBhrerHHaBrNJVnRM19fSbgoG2uZBZRP9QH3r87X+5Ph7s4m+SHlMqgT2v8wOhKfi0WA5tnNwNBceZ3ax+73Cyn5qF8wXBO/y6+fHsSsyMD/GXrORv7F/iOm/ZmQbPzhXzVaiiSwX3+a/cFAyG2IuEksmx40Zw5+KJNvH6Xza4J81Gmc8WnHXD//pMi+y3u3aFbr0XfYi8wvIlCQUR3nUANQ+gVoatSvIF1iKyzwkCgap2sRHKfDjccen05TKgz/PQmhcsvwZgHJsW0KiUrF24yKy+jSKxi4OUf+sloDw+AMCJWbGgUhmsgkgyiN1UAqoobL2xJvkiX4Ff7PcL0wemlz7sNddKd63YG7sn3KW/bPTdv5iXUaMsZlzpQAZJ+l6EvAujibRAmpxVG4Zk4puK6QHIDWT+G0yBDFtyiDCEgiI9NitHoE6T48CzoNlawB8LWmTpt1qDlB+c8RTtLaBBAHB4IhFnMrVlGp9bBXOgHaiD6W5txmH9K50oTT51F0ZSdOkzNg1CX2xNInfeEvuDPAmS/jDdz2lSbOSds2Yqiecif+NSY/tXT87tRwDzn81OgK2cx96BD2GHkStj1NZ+G1r6D1gGJxhZfabVDDWnnsrVDTWzB1Ab7Wt4x8GumZYxx4A+lGwp8cN8skl4rGtyCiMeGQLAabIZegP2tbsrfQpWwngTR2F/kHbuvsh+pStdwHvtvuh/xHb+hNHflmI1hvkUafYvpHmNo3j2q8ff6fzN39fQ+maLNWXgysJr3COGtQVzUZu5wdvzf9N5lxuZmvZFX+2Vssyv8hVD62b8A/We69ctvBn3oL5NsOX93lh5VHna46B5Gk+4Ln0ZfYx9jqomhqQDT7u1CNRm+x0ckE3RZBrneC013ayvrklmmLnZCsGPrFgk+10hm6TBdlinFLESfq25yC+JPtmds7vpWiixyBmTO+DALGgWKH98GTUds/4xLVORNkJgeJphm9u2TZNJxfcMHmGTrpWsYp0UUpt53bPvduBomy9CmlBio8xkO+5U8Ns3h2C7KgClZ4zAElUlx5m8hSSYiy3llnlqo38WnLVTan4cL0SZtOyfEoaVlnFzXkTMUnkZVaV7pBLUuer3ec+mCCXNk7A3zfK+4wHyyeNSqV8euTUFdTDsOQUpBcyz/sHEi6fW2FVAzaS8He6zwV5SL5ywr+PPDi8YJTvGDkNTmScuoJCLpqzuUbBj3kkohgaRu9FrbCDY4D/BkV/2SBF0I8BOcQSCUH9I1scaMNL8b6FOYpZ2NPFsl7gJ2yrDFrCUAsSf5P0KiQAemDDgPkCRACnXFSICOK+jOzJWiOMs5BXa0o3rwYPyYU3e8utDowz9y2/fu4QTuDE8r1O4vwAtAu17PK91N3ZB3JVZncXt19YPk4nnt0I9erKfsdCv5CrVimEQZ2HE2wEvwE4piEAKgrYfjiubFjKOghvjDNsJKGv7NcTCZ35gp7Af3ucdmmDOAcTLzr1dz8qoXHI1OqoFaTSjDr5r8upuyEphqoa5DcNJg9ftdewrqYR0yzQsg7RWll1zMo5OhjT5leovUP6a9xZXvR6Rf4sa6wlsuzLTgx81BHMsc39y3PwR/38Wc4r4BnBy53t/OjXwsMrV+QXby8PdoM8fG8tD4Gn8giCLax7l/6/lccFKgrOEQobeacCYYY7L1BR8I5cOrO/uUAEpz56kj2KPGBrSdRE74ZM/r3oJPo2apWpVAbsFiQVxTY7UIZUe4DCH2TycZtca5DDNkVPipR3OEi5HfBRtmTwOB8IT7aOQe+ITY7IVhVT77VOUaycAxEyHOCcrHzRo4fHZ3bMUw/0qWRvkxxT2kMlp3gmR1Qy0CRV5UtGvt44cPD4CcrMqOQk+G60rKhfFELBzFCpStlxhaQBQNV2vTGzgzIOK2R3k0yoX9oytn3uxpuOf4Ay9yrkdif5hpyb3oXpYY36O9VBRc91ExcnbVmvTnN5qLMrkw7YNvRwns+vQS6f24Csrg1r8YY9w+vf9J9nQDmBwJlAdMEre+GzuB4LmbMAp6WHys97xdOfkoYp/H7aKyknLhOqeH5tCr59fV3nQnenH61v/fEzHOd0MuuxdtGZ0tNF2Be8uvfTFI9L0mdOe6Tfukz4/efXpow7K3BifYvr13btYhM6x0wBNgWQiojbcIBJNCzJASZ0OfaAVTNFzbfsSXiWfZqE38BvaHHoAieuOfvM4hnmIdgniJwdeKjYIFtf3ehKsJlxVtH1+O61/STYvBsrwH63OvVCHnK+21CLp3Yrmt3AQG9wIGh4TRo9+rppr7lEhiAHli0MZhmwSUC2PNBT7JZHobHDE+nmu9aQCbY6thVsFSuWKwPPgEomwf4yCRgwyhQHMlWnZqf3hs6zscGzx3AMO1kWFHIsmMhqcjyO012zoLbDvKLFNC32hNNen9CXv0LR+6JvNH0mPeq7qCe+JPSc0aQzknYGsnR12dfnW1adyaufs+foAtoMDCQS+Fp9mSbRy3pYptKWu/eGzv1XDlURFYbk3BjmQHN55+YDxD5A0S0kKeo5jLzRXuotOcVKZegJkexOp3KrHhPDzhVpig/r/Ophqo16HNcT7NFO68a/nPD5592Ka/Cu6bueeur1ffOqV+iBF4K32X0fvp6Jdh7tLMwFfPNuhquNPfXTp+b3ymEdXpeebfauVYxefd8gZGlpVEQm+ghqFalWDUeZoLKwQWIm6YVUrUIPYcJZqgYZWYKMnCbjPaBOzSaabCWh12+TftnKdi90aqBXrQdSMJ87XzAq9KRJpc0yAT/t9qtPS8Fccdh0UrVwAOYJSmawVKaDvUo7OzA04iRmWMRUJhOYiqRC7+dieC17cK0+VTmXcMt6AgSYyMn1BLOo3f7w7Ron9vW5xD037BFdfX1i50eFrYXCVjznPJ57tbP06qu4gHtXOp9eWcG3YHZm374ZsdcjiqXR0ZIoenoxR2eufjp/jAuv0kVMb3fBytq9+zTEORP8wgtZVA61/FR+gMuQT3hAWpJBgRpZnF9RW4ybd+7DsYnT+SSfxmwS15Ia/sZRvGtxrvOZubvwyT/C0ZV76ZYr/mefZe7s/NnKv54/j7o1p+ODEajeG2gvIl6jFUs2TCiefHarN12tQAEEzlc0wNAwGTWsJv1inxdciI+DT2WUViBqwguQotrWI8MGlTVWiOZcklbqZi5Pr0kbE2wDm0HIhGNMHIf4fIoH/KXgXAN0FnEoxgKe83j0SU7jyo3OT3rLW7BY6U8KOD17j7qQjhSjewUWL2l/z8xh3tu7sCI35EQk78J4gMGPnFh5zCWUXALfozE/7/xL4Rt7x09oMpv0cB5BjEkMK8jaeZz7RFT1cC6c9HKrZ/+Y8/uGgnT0eUQ8Br30gvxUMgFPCKoQBo5t0h85ggA+YcOKdC/mXxx/c5FezBN1WCT6i5zFML8UiffF5ya/8eYFOsARDCMijATpSOhFjohyG4k4WCSMDAbrDRbbHtpSvkT5LGp7xZDu3NFP+RFmWI9XlNRgl7X2j0xFaQ7ZSAaT9M4xHcdmrRFM5nGS5bLMvUJHjuID/hMn+Jv8LzMv9XU+4bmE2Mhs5/nOeUa+ufPq/bHY1Y828SgeuQULy986fHhVDmBvzEtgeSEaGVBX2VBV6w6ga2BOWUANiKCN/AQex9gMa+zFlWeDmd7snj/4UEIKM8K7m+cPHnwt0BPfw39wiNVEE3+nuYdi/GrOtlbX51bvNSAv1gx6tZE1KKDXDKjeKcCv3lVkN+VY+U10423G2YuASwcomLJPStoFTeoIlKChBwB5+XVnJNId+aQzcqukHZ+lPdr8w6/tof9H51opU4J5pXuux52Ro92Ru52Rh/5PzvVOc+grz7XxWBtP9T86FIuESyfZZ5ivQkSKoRTUDEQwWu6gTlHOY7c4NUxRLmBArMFQRlgZCnEegUJciKYNCmG6+KrHsZbna3VwPBGHIQPNSbg2gScxZs0gVJ34z3fjqbypLn3zHtfCG2bIJd3w+B2l2jjLYu3I157BLuary52g12X4vcNy9OWTh4WouyT6XEWfznGM2rmEv3XgAMV/qgPmTuf34RQ6hloC1YAO2OTcdSlxeHHJeVfiW6J8XabVJb33S3ZvO1ibnsJKKlA1p5ok5txrs/R3PWTpcDJKasq5YKQ/meqGxIqubSyQsZLm82nFrIUbGtdI19Jamv1cvFCIL5+lLf7p4g1HFheP3IC3PHZk8QbmzkK80+cM/DBe6Aj4dxYXOw+ev+ee8/HvOoHm8t1mEU2hQ6s2lbBbCVrwo0QBCv4ep1im59rm3G52Iz8cg+Y42+E0mX4o+pXhStOJ7z2QxrWH6036gw2RFCfVu1xer1b5EN8hGS1i51e2tdsAsDkIPGYliDdesazes7CRI9OdoekjR6bxa8mk4OL7XB7OJ3aGoMLP4ddyVS7j5kK/36mLGfHnojgBj4/h49BOiPiadnfd9BGRDfJ9nKua6657hIdVGMMiWEOnOmvoYoT+C93/Vj8AAHjafY+/asMwEIc/JU6aQhsyltJBQ6eCg20IgdCt1GTwlNJsHUJijCCxwHaeqVufpM/Qta/Ri31ZOkTipO9Ov/sjYMwXhm7d8qBsGPGs3OOKd+U+j3wqB6L5UR5wY4zykJGxojTBtXj3bdaJDROelHvS91W5z5IP5UA038oD7vhVHjIxY1I8JQ2ObUs1lkz2C6S+bNzWl7XNMnHfRHNgJ2cjykoC7rBzjRdakVNwZM/m9LDKi+N+I3AunrYJhagsCVMiuRdi/0t20Vg0IXOxRJQxs26U1FdFbpNpZBf23FowTsJ5mETx7OKEa+ldyedcO9GpRzcF67yqnS9tLHUvVfgDz/ZF8gAAAHjabc25DgFhGIXh/53B2Pd9J9HPN/bSWolC4iI0OjfgxhFO6SQnT/k6z333errI/dvkc5yHh+98YsRJEJAkRZoMWXLkKVCkRJkKVWrUadCkRZsOXXr0GTBkxDh2vp5O3u4SPO63YxiG0mQkp3Im53Ihl3Il13Ijt3In9/Igjz9NfVPf1Df1TX1T39Q39U19U9/UN/VNfVPfDm8tR0peAAB42mNgYGBkAIKLcceVwfQJ+XIoXQEARe8GegAA) format("woff"); + font-weight: normal; + font-style: normal; +} +.simditor-icon { + display: inline-block; + font: normal normal normal 14px/1 'Simditor'; + font-size: inherit; + text-rendering: auto; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + transform: translate(0, 0); +} + +.simditor-icon-code:before { + content: '\f000'; +} + +.simditor-icon-bold:before { + content: '\f001'; +} + +.simditor-icon-italic:before { + content: '\f002'; +} + +.simditor-icon-underline:before { + content: '\f003'; +} + +.simditor-icon-times:before { + content: '\f004'; +} + +.simditor-icon-strikethrough:before { + content: '\f005'; +} + +.simditor-icon-list-ol:before { + content: '\f006'; +} + +.simditor-icon-list-ul:before { + content: '\f007'; +} + +.simditor-icon-quote-left:before { + content: '\f008'; +} + +.simditor-icon-table:before { + content: '\f009'; +} + +.simditor-icon-link:before { + content: '\f00a'; +} + +.simditor-icon-picture-o:before { + content: '\f00b'; +} + +.simditor-icon-minus:before { + content: '\f00c'; +} + +.simditor-icon-indent:before { + content: '\f00d'; +} + +.simditor-icon-outdent:before { + content: '\f00e'; +} + +.simditor-icon-unlink:before { + content: '\f00f'; +} + +.simditor-icon-caret-down:before { + content: '\f010'; +} + +.simditor-icon-caret-right:before { + content: '\f011'; +} + +.simditor-icon-upload:before { + content: '\f012'; +} + +.simditor-icon-undo:before { + content: '\f013'; +} + +.simditor-icon-smile-o:before { + content: '\f014'; +} + +.simditor-icon-tint:before { + content: '\f015'; +} + +.simditor-icon-font:before { + content: '\f016'; +} + +.simditor-icon-html5:before { + content: '\f017'; +} + +.simditor-icon-mark:before { + content: '\f018'; +} + +.simditor-icon-align-center:before { + content: '\f019'; +} + +.simditor-icon-align-left:before { + content: '\f01a'; +} + +.simditor-icon-align-right:before { + content: '\f01b'; +} + +.simditor-icon-font-minus:before { + content: '\f01c'; +} + +.simditor-icon-markdown:before { + content: '\f01d'; +} + +.simditor-icon-checklist:before { + content: '\f01e'; +} + +.simditor { + position: relative; + border: 1px solid #c9d8db; +} +.simditor .simditor-wrapper { + position: relative; + background: #ffffff; +} +.simditor .simditor-wrapper > textarea { + display: none !important; + width: 100%; + box-sizing: border-box; + font-family: monaco; + font-size: 16px; + line-height: 1.6; + border: none; + padding: 22px 15px 40px; + min-height: 300px; + outline: none; + background: transparent; + resize: none; +} +.simditor .simditor-wrapper .simditor-placeholder { + display: none; + position: absolute; + left: 0; + z-index: 0; + padding: 22px 15px; + font-size: 16px; + font-family: arial, sans-serif; + line-height: 1.5; + color: #999999; + background: transparent; +} +.simditor .simditor-wrapper.toolbar-floating .simditor-toolbar { + position: fixed; + top: 0; + z-index: 10; + box-shadow: 0 0 6px rgba(0, 0, 0, 0.1); +} +.simditor .simditor-wrapper .simditor-image-loading { + width: 100%; + height: 100%; + position: absolute; + top: 0; + left: 0; + z-index: 2; +} +.simditor .simditor-wrapper .simditor-image-loading .progress { + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.4); + position: absolute; + bottom: 0; + left: 0; +} +.simditor .simditor-body { + padding: 22px 15px 40px; + min-height: 300px; + outline: none; + cursor: text; + position: relative; + z-index: 1; + background: transparent; +} +.simditor .simditor-body a.selected { + background: #b3d4fd; +} +.simditor .simditor-body a.simditor-mention { + cursor: pointer; +} +.simditor .simditor-body .simditor-table { + position: relative; +} +.simditor .simditor-body .simditor-table.resizing { + cursor: col-resize; +} +.simditor .simditor-body .simditor-table .simditor-resize-handle { + position: absolute; + left: 0; + top: 0; + width: 10px; + height: 100%; + cursor: col-resize; +} +.simditor .simditor-body pre { + /*min-height: 28px;*/ + box-sizing: border-box; + -moz-box-sizing: border-box; + word-wrap: break-word !important; + white-space: pre-wrap !important; +} +.simditor .simditor-body img { + cursor: pointer; +} +.simditor .simditor-body img.selected { + box-shadow: 0 0 0 4px #cccccc; +} +.simditor .simditor-paste-bin { + position: absolute; + width: 1px; + height: 20px; + font-size: 1px; + line-height: 1px; + overflow: hidden; + padding: 0; + margin: 0; + opacity: 0; + -webkit-user-select: text; +} +.simditor .simditor-toolbar { + border-bottom: 1px solid #eeeeee; + background: #ffffff; + width: 100%; +} +.simditor .simditor-toolbar > ul { + margin: 0; + padding: 0 0 0 6px; + list-style: none; +} +.simditor .simditor-toolbar > ul > li { + position: relative; + display: inline-block; + font-size: 0; +} +.simditor .simditor-toolbar > ul > li > span.separator { + display: inline-block; + background: #cfcfcf; + width: 1px; + height: 18px; + margin: 11px 15px; + vertical-align: middle; +} +.simditor .simditor-toolbar > ul > li > .toolbar-item { + display: inline-block; + width: 46px; + height: 40px; + outline: none; + color: #333333; + font-size: 15px; + line-height: 40px; + vertical-align: middle; + text-align: center; + text-decoration: none; +} +.simditor .simditor-toolbar > ul > li > .toolbar-item span { + opacity: 0.6; +} +.simditor .simditor-toolbar > ul > li > .toolbar-item span.simditor-icon { + display: inline; + line-height: normal; +} +.simditor .simditor-toolbar > ul > li > .toolbar-item:hover span { + opacity: 1; +} +.simditor .simditor-toolbar > ul > li > .toolbar-item.active { + background: #eeeeee; +} +.simditor .simditor-toolbar > ul > li > .toolbar-item.active span { + opacity: 1; +} +.simditor .simditor-toolbar > ul > li > .toolbar-item.disabled { + cursor: default; +} +.simditor .simditor-toolbar > ul > li > .toolbar-item.disabled span { + opacity: 0.3; +} +.simditor .simditor-toolbar > ul > li > .toolbar-item.toolbar-item-title span:before { + content: "H"; + font-size: 19px; + font-weight: bold; + font-family: 'Times New Roman'; +} +.simditor .simditor-toolbar > ul > li > .toolbar-item.toolbar-item-title.active-h1 span:before { + content: 'H1'; + font-size: 18px; +} +.simditor .simditor-toolbar > ul > li > .toolbar-item.toolbar-item-title.active-h2 span:before { + content: 'H2'; + font-size: 18px; +} +.simditor .simditor-toolbar > ul > li > .toolbar-item.toolbar-item-title.active-h3 span:before { + content: 'H3'; + font-size: 18px; +} +.simditor .simditor-toolbar > ul > li > .toolbar-item.toolbar-item-image { + position: relative; + overflow: hidden; +} +.simditor .simditor-toolbar > ul > li > .toolbar-item.toolbar-item-image > input[type=file] { + position: absolute; + right: 0px; + top: 0px; + opacity: 0; + font-size: 100px; + cursor: pointer; +} +.simditor .simditor-toolbar > ul > li.menu-on .toolbar-item { + position: relative; + z-index: 20; + background: #ffffff; + box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3); +} +.simditor .simditor-toolbar > ul > li.menu-on .toolbar-item span { + opacity: 1; +} +.simditor .simditor-toolbar > ul > li.menu-on .toolbar-menu { + display: block; +} +.simditor .simditor-toolbar .toolbar-menu { + display: none; + position: absolute; + top: 40px; + left: 0; + z-index: 21; + background: #ffffff; + text-align: left; + box-shadow: 0 0 4px rgba(0, 0, 0, 0.3); +} +.simditor .simditor-toolbar .toolbar-menu:before { + content: ''; + display: block; + width: 46px; + height: 4px; + background: #ffffff; + position: absolute; + top: -3px; + left: 0; +} +.simditor .simditor-toolbar .toolbar-menu ul { + min-width: 160px; + list-style: none; + margin: 0; + padding: 10px 1px; +} +.simditor .simditor-toolbar .toolbar-menu ul > li .menu-item { + display: block; + font-size: 16px; + line-height: 2em; + padding: 0 10px; + text-decoration: none; + color: #666666; +} +.simditor .simditor-toolbar .toolbar-menu ul > li .menu-item:hover { + background: #f6f6f6; +} +.simditor .simditor-toolbar .toolbar-menu ul > li .menu-item.menu-item-h1 { + font-size: 24px; + color: #333333; +} +.simditor .simditor-toolbar .toolbar-menu ul > li .menu-item.menu-item-h2 { + font-size: 22px; + color: #333333; +} +.simditor .simditor-toolbar .toolbar-menu ul > li .menu-item.menu-item-h3 { + font-size: 20px; + color: #333333; +} +.simditor .simditor-toolbar .toolbar-menu ul > li .menu-item.menu-item-h4 { + font-size: 18px; + color: #333333; +} +.simditor .simditor-toolbar .toolbar-menu ul > li .menu-item.menu-item-h5 { + font-size: 16px; + color: #333333; +} +.simditor .simditor-toolbar .toolbar-menu ul > li .separator { + display: block; + border-top: 1px solid #cccccc; + height: 0; + line-height: 0; + font-size: 0; + margin: 6px 0; +} +.simditor .simditor-toolbar .toolbar-menu.toolbar-menu-color { + width: 96px; +} +.simditor .simditor-toolbar .toolbar-menu.toolbar-menu-color .color-list { + height: 40px; + margin: 10px 6px 6px 10px; + padding: 0; + min-width: 0; +} +.simditor .simditor-toolbar .toolbar-menu.toolbar-menu-color .color-list li { + float: left; + margin: 0 4px 4px 0; +} +.simditor .simditor-toolbar .toolbar-menu.toolbar-menu-color .color-list li .font-color { + display: block; + width: 16px; + height: 16px; + background: #dfdfdf; + border-radius: 2px; +} +.simditor .simditor-toolbar .toolbar-menu.toolbar-menu-color .color-list li .font-color:hover { + opacity: 0.8; +} +.simditor .simditor-toolbar .toolbar-menu.toolbar-menu-color .color-list li .font-color.font-color-default { + background: #333333; +} +.simditor .simditor-toolbar .toolbar-menu.toolbar-menu-color .color-list li .font-color-1 { + background: #E33737; +} +.simditor .simditor-toolbar .toolbar-menu.toolbar-menu-color .color-list li .font-color-2 { + background: #e28b41; +} +.simditor .simditor-toolbar .toolbar-menu.toolbar-menu-color .color-list li .font-color-3 { + background: #c8a732; +} +.simditor .simditor-toolbar .toolbar-menu.toolbar-menu-color .color-list li .font-color-4 { + background: #209361; +} +.simditor .simditor-toolbar .toolbar-menu.toolbar-menu-color .color-list li .font-color-5 { + background: #418caf; +} +.simditor .simditor-toolbar .toolbar-menu.toolbar-menu-color .color-list li .font-color-6 { + background: #aa8773; +} +.simditor .simditor-toolbar .toolbar-menu.toolbar-menu-color .color-list li .font-color-7 { + background: #999999; +} +.simditor .simditor-toolbar .toolbar-menu.toolbar-menu-table .menu-create-table { + background: #ffffff; + padding: 1px; +} +.simditor .simditor-toolbar .toolbar-menu.toolbar-menu-table .menu-create-table table { + border: none; + border-collapse: collapse; + border-spacing: 0; + table-layout: fixed; +} +.simditor .simditor-toolbar .toolbar-menu.toolbar-menu-table .menu-create-table table td { + padding: 0; + cursor: pointer; +} +.simditor .simditor-toolbar .toolbar-menu.toolbar-menu-table .menu-create-table table td:before { + width: 16px; + height: 16px; + border: 1px solid #ffffff; + background: #f3f3f3; + display: block; + content: ""; +} +.simditor .simditor-toolbar .toolbar-menu.toolbar-menu-table .menu-create-table table td.selected:before { + background: #cfcfcf; +} +.simditor .simditor-toolbar .toolbar-menu.toolbar-menu-table .menu-edit-table { + display: none; +} +.simditor .simditor-toolbar .toolbar-menu.toolbar-menu-table .menu-edit-table ul li { + white-space: nowrap; +} +.simditor .simditor-toolbar .toolbar-menu.toolbar-menu-image .menu-item-upload-image { + position: relative; + overflow: hidden; +} +.simditor .simditor-toolbar .toolbar-menu.toolbar-menu-image .menu-item-upload-image input[type=file] { + position: absolute; + right: 0px; + top: 0px; + opacity: 0; + font-size: 100px; + cursor: pointer; +} +.simditor .simditor-toolbar .toolbar-menu.toolbar-menu-alignment { + width: 100%; +} +.simditor .simditor-toolbar .toolbar-menu.toolbar-menu-alignment ul { + min-width: 100%; +} +.simditor .simditor-toolbar .toolbar-menu.toolbar-menu-alignment .menu-item { + text-align: center; +} +.simditor .simditor-popover { + display: none; + padding: 5px 8px 0; + background: #ffffff; + box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4); + border-radius: 2px; + position: absolute; + z-index: 2; +} +.simditor .simditor-popover .settings-field { + margin: 0 0 5px 0; + font-size: 12px; + height: 25px; + line-height: 25px; +} +.simditor .simditor-popover .settings-field label { + display: inline-block; + margin: 0 5px 0 0; +} +.simditor .simditor-popover .settings-field input[type=text] { + display: inline-block; + width: 200px; + box-sizing: border-box; + font-size: 12px; +} +.simditor .simditor-popover .settings-field input[type=text].image-size { + width: 83px; +} +.simditor .simditor-popover .settings-field .times { + display: inline-block; + width: 26px; + font-size: 12px; + text-align: center; +} +.simditor .simditor-popover.link-popover .btn-unlink, .simditor .simditor-popover.image-popover .btn-upload, .simditor .simditor-popover.image-popover .btn-restore { + display: inline-block; + margin: 0 0 0 5px; + color: #333333; + font-size: 14px; + outline: 0; +} +.simditor .simditor-popover.link-popover .btn-unlink span, .simditor .simditor-popover.image-popover .btn-upload span, .simditor .simditor-popover.image-popover .btn-restore span { + opacity: 0.6; +} +.simditor .simditor-popover.link-popover .btn-unlink:hover span, .simditor .simditor-popover.image-popover .btn-upload:hover span, .simditor .simditor-popover.image-popover .btn-restore:hover span { + opacity: 1; +} +.simditor .simditor-popover.image-popover .btn-upload { + position: relative; + display: inline-block; + overflow: hidden; + vertical-align: middle; +} +.simditor .simditor-popover.image-popover .btn-upload input[type=file] { + position: absolute; + right: 0px; + top: 0px; + opacity: 0; + height: 100%; + width: 28px; +} +.simditor.simditor-mobile .simditor-wrapper.toolbar-floating .simditor-toolbar { + position: absolute; + top: 0; + z-index: 10; + box-shadow: 0 0 6px rgba(0, 0, 0, 0.1); +} + +.simditor .simditor-body, .editor-style { + font-size: 16px; + font-family: arial, sans-serif; + line-height: 1.6; + color: #333; + outline: none; + word-wrap: break-word; +} +.simditor .simditor-body > :first-child, .editor-style > :first-child { + margin-top: 0 !important; +} +.simditor .simditor-body a, .editor-style a { + color: #4298BA; + text-decoration: none; + word-break: break-all; +} +.simditor .simditor-body a:visited, .editor-style a:visited { + color: #4298BA; +} +.simditor .simditor-body a:hover, .editor-style a:hover { + color: #0F769F; +} +.simditor .simditor-body a:active, .editor-style a:active { + color: #9E792E; +} +.simditor .simditor-body a:hover, .simditor .simditor-body a:active, .editor-style a:hover, .editor-style a:active { + outline: 0; +} +.simditor .simditor-body h1, .simditor .simditor-body h2, .simditor .simditor-body h3, .simditor .simditor-body h4, .simditor .simditor-body h5, .simditor .simditor-body h6, .editor-style h1, .editor-style h2, .editor-style h3, .editor-style h4, .editor-style h5, .editor-style h6 { + font-weight: normal; + margin: 40px 0 20px; + color: #000000; +} +.simditor .simditor-body h1, .editor-style h1 { + font-size: 24px; +} +.simditor .simditor-body h2, .editor-style h2 { + font-size: 22px; +} +.simditor .simditor-body h3, .editor-style h3 { + font-size: 20px; +} +.simditor .simditor-body h4, .editor-style h4 { + font-size: 18px; +} +.simditor .simditor-body h5, .editor-style h5 { + font-size: 16px; +} +.simditor .simditor-body h6, .editor-style h6 { + font-size: 16px; +} +.simditor .simditor-body p, .simditor .simditor-body div, .editor-style p, .editor-style div { + word-wrap: break-word; + margin: 0 0 15px 0; + color: #333; + word-wrap: break-word; +} +.simditor .simditor-body b, .simditor .simditor-body strong, .editor-style b, .editor-style strong { + font-weight: bold; +} +.simditor .simditor-body i, .simditor .simditor-body em, .editor-style i, .editor-style em { + font-style: italic; +} +.simditor .simditor-body u, .editor-style u { + text-decoration: underline; +} +.simditor .simditor-body strike, .simditor .simditor-body del, .editor-style strike, .editor-style del { + text-decoration: line-through; +} +.simditor .simditor-body ul, .simditor .simditor-body ol, .editor-style ul, .editor-style ol { + list-style: disc outside none; + margin: 15px 0; + padding: 0 0 0 40px; + line-height: 1.6; +} +.simditor .simditor-body ul li, .simditor .simditor-body ol li, .editor-style ul li, .editor-style ol li { + list-style-type: inherit; +} +.simditor .simditor-body ul ul, .simditor .simditor-body ul ol, .simditor .simditor-body ol ul, .simditor .simditor-body ol ol, .editor-style ul ul, .editor-style ul ol, .editor-style ol ul, .editor-style ol ol { + padding-left: 30px; +} +.simditor .simditor-body ul ul, .simditor .simditor-body ol ul, .editor-style ul ul, .editor-style ol ul { + list-style: circle outside none; +} +.simditor .simditor-body ul ul ul, .simditor .simditor-body ol ul ul, .editor-style ul ul ul, .editor-style ol ul ul { + list-style: square outside none; +} +.simditor .simditor-body ol, .editor-style ol { + list-style: decimal; +} +.simditor .simditor-body blockquote, .editor-style blockquote { + border-left: 6px solid #ddd; + padding: 5px 0 5px 10px; + margin: 15px 0 15px 15px; +} +.simditor .simditor-body blockquote > :first-child, .editor-style blockquote > :first-child { + margin-top: 0; +} +.simditor .simditor-body code, .editor-style code { + display: inline-block; + padding: 0 4px; + margin: 0 5px; + background: #eeeeee; + border-radius: 3px; + font-size: 13px; + font-family: 'monaco', 'Consolas', "Liberation Mono", Courier, monospace; + word-break: break-all; + word-wrap: break-word; +} +.simditor .simditor-body pre, .editor-style pre { + padding: 10px 5px 10px 10px; + margin: 15px 0; + display: block; + line-height: 18px; + background: #F0F0F0; + border-radius: 3px; + font-size: 13px; + font-family: 'monaco', 'Consolas', "Liberation Mono", Courier, monospace; + white-space: pre; + word-wrap: normal; + overflow-x: auto; +} +.simditor .simditor-body pre code, .editor-style pre code { + display: block; + padding: 0; + margin: 0; + background: none; + border-radius: 0; +} +.simditor .simditor-body hr, .editor-style hr { + display: block; + height: 0px; + border: 0; + border-top: 1px solid #ccc; + margin: 15px 0; + padding: 0; +} +.simditor .simditor-body table, .editor-style table { + width: 100%; + table-layout: fixed; + border-collapse: collapse; + border-spacing: 0; + margin: 15px 0; +} +.simditor .simditor-body table thead, .editor-style table thead { + background-color: #f9f9f9; +} +.simditor .simditor-body table td, .simditor .simditor-body table th, .editor-style table td, .editor-style table th { + min-width: 40px; + height: 30px; + border: 1px solid #ccc; + vertical-align: top; + padding: 2px 4px; + text-align: left; + box-sizing: border-box; +} +.simditor .simditor-body table td.active, .simditor .simditor-body table th.active, .editor-style table td.active, .editor-style table th.active { + background-color: #ffffee; +} +.simditor .simditor-body img, .editor-style img { + margin: 0 5px; + vertical-align: middle; +}