├── .gitignore ├── LICENSE ├── README.md ├── composer.json └── src ├── EndaEditor.php ├── EndaEditorServiceProvider.php ├── Facade └── EndaEditorFacade.php ├── Parsedown.php └── config ├── editor.php ├── editor ├── css │ ├── editor.css │ ├── editor.css.map │ ├── pygment_trac.css │ ├── stylesheet.css │ └── zoom.css ├── images │ ├── code.png │ ├── editor@2x.png │ ├── loader.gif │ ├── pattern.png │ ├── tar.png │ ├── top.png │ └── zip.png └── js │ ├── MIDI.js │ ├── bacheditor.js │ ├── bootstrap3-typeahead.js │ ├── fileupload.js │ ├── highlight.js │ ├── marimba-mp3.js │ ├── modal.js │ ├── piano.js │ ├── template.js │ └── zoom.js └── views ├── decode.blade.php └── head.blade.php /.gitignore: -------------------------------------------------------------------------------- 1 | /bootstrap/compiled.php 2 | .env.*.php 3 | .env.php 4 | .env 5 | .idea 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # laravel-5-markdown-editor 2 | Based on the markdown editor laravel 5 3 | 4 | 一个基于 laravel 5 的markdown 编辑器 5 | 6 | 本项目基于 html&js 一个有情怀的编辑器二次开发完成 [传送门](https://github.com/Integ/BachEditor) 7 | 8 | 9 | # 安装使用详细教程 10 | 11 | phphub: [https://phphub.org/topics/853](https://phphub.org/topics/853) 12 | 13 | 如果访问 phphub 比较慢的同学,可以访问这个 14 | 15 | SegmentFault:[http://segmentfault.com/a/1190000002780158](http://segmentfault.com/a/1190000002780158) 16 | 17 | # 不需要敲语法可界面操作的功能 18 | 1. 加粗字体 19 | 2. 加斜字体 20 | 3. `无需手写 md插入链接` 21 | 4. 引用 22 | 5. `无需手写 md 语法插入图片` 23 | 6. 数字列表 24 | 7. 普通列表 25 | 8. 标题 26 | 9. 分割 27 | 10. 撤销 28 | 11. 重做 29 | 12. 全屏 30 | 31 | # Bug 反馈&交流 32 | 33 | 欢迎加入我们的 laravel 学习小组:`365969825` 34 | 35 | # 预览 36 | 37 | 38 | 39 | 40 | # Update Log 41 | 42 | `2015-05-18` 初版提交 43 | 44 | `2015-05-19` 图片上传移植到扩展内部处理 45 | 46 | `2015-05-19` 新增解析 markdown 为 html 功能 47 | 48 | # Installation 49 | 50 | 1.在 `composer.json` 的 require里 加入 51 | 52 | ``` 53 | "yuanchao/laravel-5-markdown-editor": "dev-master" 54 | ``` 55 | 2.执行 `composer update` 56 | 57 | 3.在config/app.php 的 `providers` 数组加入一条 58 | 59 | ``` 60 | 'YuanChao\Editor\EndaEditorServiceProvider' 61 | ``` 62 | 63 | 4.在config/app.php 的 `aliases` 数组加入一条 64 | 65 | ``` 66 | 'EndaEditor' => 'YuanChao\Editor\Facade\EndaEditorFacade' 67 | 68 | ``` 69 | 70 | 5.执行 `php artisan vendor:publish --tag=EndaEditor` 71 | 72 | 执行完上面的命令后,会生成配置文件和视图文件到你的 config/ 和 views/vendor 目录 73 | 74 | # Usage 75 | 76 | 1.在需要编辑器的地方插入以下代码 77 | 78 | ``` 79 | // 引入编辑器代码 80 | @include('editor::head') 81 | 82 | // 编辑器一定要被一个 class 为 editor 的容器包住 83 |
84 | // 创建一个 textarea 而已,具体的看手册,主要在于它的 id 为 myEditor 85 | {!! Form::textarea('content', '', ['class' => 'form-control','id'=>'myEditor']) !!} 86 | 87 | // 上面的 Form::textarea ,在laravel 5 中被提了出去,如果你没安装的话,直接这样用 88 | 89 | 90 | // 主要还是在容器的 ID 为 myEditor 就行 91 | 92 |
93 | 94 | ``` 95 | 96 | 这个时候,编辑器就出来啦~ 97 | 98 | #### 图片上传移植到扩展内部处理 99 | 100 | `图片上传移植到扩展的功能上传时间为 2015-05-19 10:40 如果在这个时间前安装的朋友,请先更新` 101 | 102 | 2.图片上传配置,打开config/editor.php 配置文件,修改里面的 `uploadUrl` 配置项,为你的处理上传的 action 103 | 104 | 我的上传 action 代码为 105 | 106 | ``` 107 | use EndaEditor; 108 | 109 | public function postUpload(){ 110 | 111 | 112 | // endaEdit 为你 public 下的目录 update 2015-05-19 113 | $data = EndaEditor::uploadImgFile('endaEdit'); 114 | 115 | return json_encode($data); 116 | } 117 | 118 | 119 | ``` 120 | 121 | 3.链接添加功能添加了方便的添加系统内部文章的特性,首先在config/editor.php配置文件添加 `ajaxTopicSearchUrl` 配置项,关于返回的数据格式,请在配置文件中查看注释。 122 | 123 | 之后在您没有选中任何字符的情况下点击添加链接,将会看到多了一个标题输入框,您输入一些字符,它会根据 `ajaxTopicSearchUrl` 获得的文章标题列表来生成自动补全的下拉列表。 124 | 125 | 当您选中某个文章之后,下面的链接也会自动被填上。 126 | ###完成以上这些配置,你就可以在线插入图片啦 127 | 128 | 129 | ### 新增解析 markdown 为 html 功能 130 | 131 | 头部引用文件 132 | ``` 133 | use EndaEditor; 134 | 135 | ``` 136 | 137 | 列子如下: 138 | ``` 139 | 140 | $art = Article::find(16); 141 | 142 | 143 | return view('test',[ 144 | 'content'=>EndaEditor::MarkDecode($art->content) 145 | ]); 146 | 147 | 148 | ``` 149 | 150 | 直接把需要解析的 markdown 扔进这个方法就行 151 | 152 | ``` 153 | EndaEditor::MarkDecode("#我是参数") 154 | 155 | ``` 156 | 157 | 为了保证图片的显示正常,加入[zoom插件](https://github.com/fat/zoom.js) 158 | 159 | 在需要解码的页面确保引入了bootstrap,并加入如下代码 160 | ``` 161 | @include('editor::decode') 162 | 163 | ``` -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "yuanchao/laravel-5-markdown-editor", 3 | "description": "Based on the markdown editor laravel 5", 4 | "authors": [ 5 | { 6 | "name": "yuanchao", 7 | "email": "653069653@qq.com" 8 | } 9 | ], 10 | "license": "MIT", 11 | "minimum-stability": "dev", 12 | "require": {}, 13 | "autoload": { 14 | "psr-4": { 15 | "YuanChao\\Editor\\":"src/" 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/EndaEditor.php: -------------------------------------------------------------------------------- 1 | 5 | * Time: 2015.05.18 下午2:11 6 | */ 7 | namespace YuanChao\Editor; 8 | 9 | use Illuminate\Support\Facades\Request; 10 | 11 | class EndaEditor{ 12 | 13 | static $_errors=array(); 14 | 15 | protected static function addError($message){ 16 | if(!empty($message)){ 17 | self::$_errors[] = $message; 18 | } 19 | } 20 | 21 | protected static function getLastError(){ 22 | return empty(self::$_errors) ? '' : array_pop(self::$_errors); 23 | } 24 | 25 | /** 26 | * EndaEditor Upload ImgFile 27 | * @param string $path 28 | * @return array 29 | */ 30 | public static function uploadImgFile($path){ 31 | try{ 32 | // File Upload 33 | if (Request::hasFile('image')){ 34 | $pic = Request::file('image'); 35 | if($pic->isValid()){ 36 | $newName = md5(rand(1,1000).$pic->getClientOriginalName()).".".$pic->getClientOriginalExtension(); 37 | $pic->move($path,$newName); 38 | $url = asset($path.'/'.$newName); 39 | }else{ 40 | self::addError('The file is invalid'); 41 | } 42 | }else{ 43 | self::addError('Not File'); 44 | } 45 | }catch (\Exception $e){ 46 | self::addError($e->getMessage()); 47 | } 48 | 49 | $data = array( 50 | 'status'=>empty($message)?0:1, 51 | 'message'=>self::getLastError(), 52 | 'url'=>!empty($url)?$url:'' 53 | ); 54 | 55 | return $data; 56 | } 57 | 58 | 59 | /** 60 | * 转换 mark 文本 61 | * @param $markdownText 62 | * @return string 63 | */ 64 | public static function MarkDecode($markdownText){ 65 | $parsedown = new \YuanChao\Editor\Parsedown(); 66 | return $parsedown->text($markdownText); 67 | } 68 | 69 | } -------------------------------------------------------------------------------- /src/EndaEditorServiceProvider.php: -------------------------------------------------------------------------------- 1 | loadViewsFrom(__DIR__.'/config/views', 'editor'); 17 | 18 | $this->publishes([ 19 | __DIR__.'/config/views' => base_path('resources/views/vendor/editor'), 20 | ],'EndaEditor'); 21 | $this->publishes([ 22 | __DIR__.'/config/editor' => base_path('public/plugin/editor'), 23 | ],'EndaEditor'); 24 | $this->publishes([ 25 | __DIR__.'/config/editor.php' => config_path('editor.php'), 26 | ],'EndaEditor'); 27 | } 28 | 29 | /** 30 | * Register the application services. 31 | * 32 | * @return void 33 | */ 34 | public function register() 35 | { 36 | // 37 | $this->app->singleton('EndaEditor', function ($app) { 38 | return new \YuanChao\Editor\EndaEditor; 39 | }); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/Facade/EndaEditorFacade.php: -------------------------------------------------------------------------------- 1 | 4 | * Time: 2015.05.18 上午10:33 5 | */ 6 | namespace YuanChao\Editor\Facade; 7 | use Illuminate\Support\Facades\Facade; 8 | 9 | class EndaEditorFacade extends Facade{ 10 | protected static function getFacadeAccessor(){ 11 | return 'EndaEditor'; 12 | } 13 | } -------------------------------------------------------------------------------- /src/Parsedown.php: -------------------------------------------------------------------------------- 1 | 4 | * Time: 2015.05.19 下午5:34 5 | */ 6 | namespace YuanChao\Editor; 7 | class Parsedown 8 | { 9 | # ~ 10 | 11 | const version = '1.5.3'; 12 | 13 | # ~ 14 | 15 | function text($text) 16 | { 17 | # make sure no definitions are set 18 | $this->DefinitionData = array(); 19 | 20 | # standardize line breaks 21 | $text = str_replace(array("\r\n", "\r"), "\n", $text); 22 | 23 | # remove surrounding line breaks 24 | $text = trim($text, "\n"); 25 | 26 | # split text into lines 27 | $lines = explode("\n", $text); 28 | 29 | # iterate through lines to identify blocks 30 | $markup = $this->lines($lines); 31 | 32 | # trim line breaks 33 | $markup = trim($markup, "\n"); 34 | 35 | return $markup; 36 | } 37 | 38 | # 39 | # Setters 40 | # 41 | 42 | function setBreaksEnabled($breaksEnabled) 43 | { 44 | $this->breaksEnabled = $breaksEnabled; 45 | 46 | return $this; 47 | } 48 | 49 | protected $breaksEnabled; 50 | 51 | function setMarkupEscaped($markupEscaped) 52 | { 53 | $this->markupEscaped = $markupEscaped; 54 | 55 | return $this; 56 | } 57 | 58 | protected $markupEscaped; 59 | 60 | function setUrlsLinked($urlsLinked) 61 | { 62 | $this->urlsLinked = $urlsLinked; 63 | 64 | return $this; 65 | } 66 | 67 | protected $urlsLinked = true; 68 | 69 | # 70 | # Lines 71 | # 72 | 73 | protected $BlockTypes = array( 74 | '#' => array('Header'), 75 | '*' => array('Rule', 'List'), 76 | '+' => array('List'), 77 | '-' => array('SetextHeader', 'Table', 'Rule', 'List'), 78 | '0' => array('List'), 79 | '1' => array('List'), 80 | '2' => array('List'), 81 | '3' => array('List'), 82 | '4' => array('List'), 83 | '5' => array('List'), 84 | '6' => array('List'), 85 | '7' => array('List'), 86 | '8' => array('List'), 87 | '9' => array('List'), 88 | ':' => array('Table'), 89 | '<' => array('Comment', 'Markup'), 90 | '=' => array('SetextHeader'), 91 | '>' => array('Quote'), 92 | '[' => array('Reference'), 93 | '_' => array('Rule'), 94 | '`' => array('FencedCode'), 95 | '|' => array('Table'), 96 | '~' => array('FencedCode'), 97 | ); 98 | 99 | # ~ 100 | 101 | protected $DefinitionTypes = array( 102 | '[' => array('Reference'), 103 | ); 104 | 105 | # ~ 106 | 107 | protected $unmarkedBlockTypes = array( 108 | 'Code', 109 | ); 110 | 111 | # 112 | # Blocks 113 | # 114 | 115 | private function lines(array $lines) 116 | { 117 | $CurrentBlock = null; 118 | 119 | foreach ($lines as $line) 120 | { 121 | if (chop($line) === '') 122 | { 123 | if (isset($CurrentBlock)) 124 | { 125 | $CurrentBlock['interrupted'] = true; 126 | } 127 | 128 | continue; 129 | } 130 | 131 | if (strpos($line, "\t") !== false) 132 | { 133 | $parts = explode("\t", $line); 134 | 135 | $line = $parts[0]; 136 | 137 | unset($parts[0]); 138 | 139 | foreach ($parts as $part) 140 | { 141 | $shortage = 4 - mb_strlen($line, 'utf-8') % 4; 142 | 143 | $line .= str_repeat(' ', $shortage); 144 | $line .= $part; 145 | } 146 | } 147 | 148 | $indent = 0; 149 | 150 | while (isset($line[$indent]) and $line[$indent] === ' ') 151 | { 152 | $indent ++; 153 | } 154 | 155 | $text = $indent > 0 ? substr($line, $indent) : $line; 156 | 157 | # ~ 158 | 159 | $Line = array('body' => $line, 'indent' => $indent, 'text' => $text); 160 | 161 | # ~ 162 | 163 | if (isset($CurrentBlock['incomplete'])) 164 | { 165 | $Block = $this->{'block'.$CurrentBlock['type'].'Continue'}($Line, $CurrentBlock); 166 | 167 | if (isset($Block)) 168 | { 169 | $CurrentBlock = $Block; 170 | 171 | continue; 172 | } 173 | else 174 | { 175 | if (method_exists($this, 'block'.$CurrentBlock['type'].'Complete')) 176 | { 177 | $CurrentBlock = $this->{'block'.$CurrentBlock['type'].'Complete'}($CurrentBlock); 178 | } 179 | 180 | unset($CurrentBlock['incomplete']); 181 | } 182 | } 183 | 184 | # ~ 185 | 186 | $marker = $text[0]; 187 | 188 | # ~ 189 | 190 | $blockTypes = $this->unmarkedBlockTypes; 191 | 192 | if (isset($this->BlockTypes[$marker])) 193 | { 194 | foreach ($this->BlockTypes[$marker] as $blockType) 195 | { 196 | $blockTypes []= $blockType; 197 | } 198 | } 199 | 200 | # 201 | # ~ 202 | 203 | foreach ($blockTypes as $blockType) 204 | { 205 | $Block = $this->{'block'.$blockType}($Line, $CurrentBlock); 206 | 207 | if (isset($Block)) 208 | { 209 | $Block['type'] = $blockType; 210 | 211 | if ( ! isset($Block['identified'])) 212 | { 213 | $Blocks []= $CurrentBlock; 214 | 215 | $Block['identified'] = true; 216 | } 217 | 218 | if (method_exists($this, 'block'.$blockType.'Continue')) 219 | { 220 | $Block['incomplete'] = true; 221 | } 222 | 223 | $CurrentBlock = $Block; 224 | 225 | continue 2; 226 | } 227 | } 228 | 229 | # ~ 230 | 231 | if (isset($CurrentBlock) and ! isset($CurrentBlock['type']) and ! isset($CurrentBlock['interrupted'])) 232 | { 233 | $CurrentBlock['element']['text'] .= "\n".$text; 234 | } 235 | else 236 | { 237 | $Blocks []= $CurrentBlock; 238 | 239 | $CurrentBlock = $this->paragraph($Line); 240 | 241 | $CurrentBlock['identified'] = true; 242 | } 243 | } 244 | 245 | # ~ 246 | 247 | if (isset($CurrentBlock['incomplete']) and method_exists($this, 'block'.$CurrentBlock['type'].'Complete')) 248 | { 249 | $CurrentBlock = $this->{'block'.$CurrentBlock['type'].'Complete'}($CurrentBlock); 250 | } 251 | 252 | # ~ 253 | 254 | $Blocks []= $CurrentBlock; 255 | 256 | unset($Blocks[0]); 257 | 258 | # ~ 259 | 260 | $markup = ''; 261 | 262 | foreach ($Blocks as $Block) 263 | { 264 | if (isset($Block['hidden'])) 265 | { 266 | continue; 267 | } 268 | 269 | $markup .= "\n"; 270 | $markup .= isset($Block['markup']) ? $Block['markup'] : $this->element($Block['element']); 271 | } 272 | 273 | $markup .= "\n"; 274 | 275 | # ~ 276 | 277 | return $markup; 278 | } 279 | 280 | # 281 | # Code 282 | 283 | protected function blockCode($Line, $Block = null) 284 | { 285 | if (isset($Block) and ! isset($Block['type']) and ! isset($Block['interrupted'])) 286 | { 287 | return; 288 | } 289 | 290 | if ($Line['indent'] >= 4) 291 | { 292 | $text = substr($Line['body'], 4); 293 | 294 | $Block = array( 295 | 'element' => array( 296 | 'name' => 'pre', 297 | 'handler' => 'element', 298 | 'text' => array( 299 | 'name' => 'code', 300 | 'text' => $text, 301 | ), 302 | ), 303 | ); 304 | 305 | return $Block; 306 | } 307 | } 308 | 309 | protected function blockCodeContinue($Line, $Block) 310 | { 311 | if ($Line['indent'] >= 4) 312 | { 313 | if (isset($Block['interrupted'])) 314 | { 315 | $Block['element']['text']['text'] .= "\n"; 316 | 317 | unset($Block['interrupted']); 318 | } 319 | 320 | $Block['element']['text']['text'] .= "\n"; 321 | 322 | $text = substr($Line['body'], 4); 323 | 324 | $Block['element']['text']['text'] .= $text; 325 | 326 | return $Block; 327 | } 328 | } 329 | 330 | protected function blockCodeComplete($Block) 331 | { 332 | $text = $Block['element']['text']['text']; 333 | 334 | $text = htmlspecialchars($text, ENT_NOQUOTES, 'UTF-8'); 335 | 336 | $Block['element']['text']['text'] = $text; 337 | 338 | return $Block; 339 | } 340 | 341 | # 342 | # Comment 343 | 344 | protected function blockComment($Line) 345 | { 346 | if ($this->markupEscaped) 347 | { 348 | return; 349 | } 350 | 351 | if (isset($Line['text'][3]) and $Line['text'][3] === '-' and $Line['text'][2] === '-' and $Line['text'][1] === '!') 352 | { 353 | $Block = array( 354 | 'markup' => $Line['body'], 355 | ); 356 | 357 | if (preg_match('/-->$/', $Line['text'])) 358 | { 359 | $Block['closed'] = true; 360 | } 361 | 362 | return $Block; 363 | } 364 | } 365 | 366 | protected function blockCommentContinue($Line, array $Block) 367 | { 368 | if (isset($Block['closed'])) 369 | { 370 | return; 371 | } 372 | 373 | $Block['markup'] .= "\n" . $Line['body']; 374 | 375 | if (preg_match('/-->$/', $Line['text'])) 376 | { 377 | $Block['closed'] = true; 378 | } 379 | 380 | return $Block; 381 | } 382 | 383 | # 384 | # Fenced Code 385 | 386 | protected function blockFencedCode($Line) 387 | { 388 | if (preg_match('/^(['.$Line['text'][0].']{3,})[ ]*([\w-]+)?[ ]*$/', $Line['text'], $matches)) 389 | { 390 | $Element = array( 391 | 'name' => 'code', 392 | 'text' => '', 393 | ); 394 | 395 | if (isset($matches[2])) 396 | { 397 | $class = 'language-'.$matches[2]; 398 | 399 | $Element['attributes'] = array( 400 | 'class' => $class, 401 | ); 402 | } 403 | 404 | $Block = array( 405 | 'char' => $Line['text'][0], 406 | 'element' => array( 407 | 'name' => 'pre', 408 | 'handler' => 'element', 409 | 'text' => $Element, 410 | ), 411 | ); 412 | 413 | return $Block; 414 | } 415 | } 416 | 417 | protected function blockFencedCodeContinue($Line, $Block) 418 | { 419 | if (isset($Block['complete'])) 420 | { 421 | return; 422 | } 423 | 424 | if (isset($Block['interrupted'])) 425 | { 426 | $Block['element']['text']['text'] .= "\n"; 427 | 428 | unset($Block['interrupted']); 429 | } 430 | 431 | if (preg_match('/^'.$Block['char'].'{3,}[ ]*$/', $Line['text'])) 432 | { 433 | $Block['element']['text']['text'] = substr($Block['element']['text']['text'], 1); 434 | 435 | $Block['complete'] = true; 436 | 437 | return $Block; 438 | } 439 | 440 | $Block['element']['text']['text'] .= "\n".$Line['body'];; 441 | 442 | return $Block; 443 | } 444 | 445 | protected function blockFencedCodeComplete($Block) 446 | { 447 | $text = $Block['element']['text']['text']; 448 | 449 | $text = htmlspecialchars($text, ENT_NOQUOTES, 'UTF-8'); 450 | 451 | $Block['element']['text']['text'] = $text; 452 | 453 | return $Block; 454 | } 455 | 456 | # 457 | # Header 458 | 459 | protected function blockHeader($Line) 460 | { 461 | if (isset($Line['text'][1])) 462 | { 463 | $level = 1; 464 | 465 | while (isset($Line['text'][$level]) and $Line['text'][$level] === '#') 466 | { 467 | $level ++; 468 | } 469 | 470 | if ($level > 6) 471 | { 472 | return; 473 | } 474 | 475 | $text = trim($Line['text'], '# '); 476 | 477 | $Block = array( 478 | 'element' => array( 479 | 'name' => 'h' . min(6, $level), 480 | 'text' => $text, 481 | 'handler' => 'line', 482 | ), 483 | ); 484 | 485 | return $Block; 486 | } 487 | } 488 | 489 | # 490 | # List 491 | 492 | protected function blockList($Line) 493 | { 494 | list($name, $pattern) = $Line['text'][0] <= '-' ? array('ul', '[*+-]') : array('ol', '[0-9]+[.]'); 495 | 496 | if (preg_match('/^('.$pattern.'[ ]+)(.*)/', $Line['text'], $matches)) 497 | { 498 | $Block = array( 499 | 'indent' => $Line['indent'], 500 | 'pattern' => $pattern, 501 | 'element' => array( 502 | 'name' => $name, 503 | 'handler' => 'elements', 504 | ), 505 | ); 506 | 507 | $Block['li'] = array( 508 | 'name' => 'li', 509 | 'handler' => 'li', 510 | 'text' => array( 511 | $matches[2], 512 | ), 513 | ); 514 | 515 | $Block['element']['text'] []= & $Block['li']; 516 | 517 | return $Block; 518 | } 519 | } 520 | 521 | protected function blockListContinue($Line, array $Block) 522 | { 523 | if ($Block['indent'] === $Line['indent'] and preg_match('/^'.$Block['pattern'].'(?:[ ]+(.*)|$)/', $Line['text'], $matches)) 524 | { 525 | if (isset($Block['interrupted'])) 526 | { 527 | $Block['li']['text'] []= ''; 528 | 529 | unset($Block['interrupted']); 530 | } 531 | 532 | unset($Block['li']); 533 | 534 | $text = isset($matches[1]) ? $matches[1] : ''; 535 | 536 | $Block['li'] = array( 537 | 'name' => 'li', 538 | 'handler' => 'li', 539 | 'text' => array( 540 | $text, 541 | ), 542 | ); 543 | 544 | $Block['element']['text'] []= & $Block['li']; 545 | 546 | return $Block; 547 | } 548 | 549 | if ($Line['text'][0] === '[' and $this->blockReference($Line)) 550 | { 551 | return $Block; 552 | } 553 | 554 | if ( ! isset($Block['interrupted'])) 555 | { 556 | $text = preg_replace('/^[ ]{0,4}/', '', $Line['body']); 557 | 558 | $Block['li']['text'] []= $text; 559 | 560 | return $Block; 561 | } 562 | 563 | if ($Line['indent'] > 0) 564 | { 565 | $Block['li']['text'] []= ''; 566 | 567 | $text = preg_replace('/^[ ]{0,4}/', '', $Line['body']); 568 | 569 | $Block['li']['text'] []= $text; 570 | 571 | unset($Block['interrupted']); 572 | 573 | return $Block; 574 | } 575 | } 576 | 577 | # 578 | # Quote 579 | 580 | protected function blockQuote($Line) 581 | { 582 | if (preg_match('/^>[ ]?(.*)/', $Line['text'], $matches)) 583 | { 584 | $Block = array( 585 | 'element' => array( 586 | 'name' => 'blockquote', 587 | 'handler' => 'lines', 588 | 'text' => (array) $matches[1], 589 | ), 590 | ); 591 | 592 | return $Block; 593 | } 594 | } 595 | 596 | protected function blockQuoteContinue($Line, array $Block) 597 | { 598 | if ($Line['text'][0] === '>' and preg_match('/^>[ ]?(.*)/', $Line['text'], $matches)) 599 | { 600 | if (isset($Block['interrupted'])) 601 | { 602 | $Block['element']['text'] []= ''; 603 | 604 | unset($Block['interrupted']); 605 | } 606 | 607 | $Block['element']['text'] []= $matches[1]; 608 | 609 | return $Block; 610 | } 611 | 612 | if ( ! isset($Block['interrupted'])) 613 | { 614 | $Block['element']['text'] []= $Line['text']; 615 | 616 | return $Block; 617 | } 618 | } 619 | 620 | # 621 | # Rule 622 | 623 | protected function blockRule($Line) 624 | { 625 | if (preg_match('/^(['.$Line['text'][0].'])([ ]*\1){2,}[ ]*$/', $Line['text'])) 626 | { 627 | $Block = array( 628 | 'element' => array( 629 | 'name' => 'hr' 630 | ), 631 | ); 632 | 633 | return $Block; 634 | } 635 | } 636 | 637 | # 638 | # Setext 639 | 640 | protected function blockSetextHeader($Line, array $Block = null) 641 | { 642 | if ( ! isset($Block) or isset($Block['type']) or isset($Block['interrupted'])) 643 | { 644 | return; 645 | } 646 | 647 | if (chop($Line['text'], $Line['text'][0]) === '') 648 | { 649 | $Block['element']['name'] = $Line['text'][0] === '=' ? 'h1' : 'h2'; 650 | 651 | return $Block; 652 | } 653 | } 654 | 655 | # 656 | # Markup 657 | 658 | protected function blockMarkup($Line) 659 | { 660 | if ($this->markupEscaped) 661 | { 662 | return; 663 | } 664 | 665 | if (preg_match('/^<(\w*)(?:[ ]*'.$this->regexHtmlAttribute.')*[ ]*(\/)?>/', $Line['text'], $matches)) 666 | { 667 | if (in_array($matches[1], $this->textLevelElements)) 668 | { 669 | return; 670 | } 671 | 672 | $Block = array( 673 | 'name' => $matches[1], 674 | 'depth' => 0, 675 | 'markup' => $Line['text'], 676 | ); 677 | 678 | $length = strlen($matches[0]); 679 | 680 | $remainder = substr($Line['text'], $length); 681 | 682 | if (trim($remainder) === '') 683 | { 684 | if (isset($matches[2]) or in_array($matches[1], $this->voidElements)) 685 | { 686 | $Block['closed'] = true; 687 | 688 | $Block['void'] = true; 689 | } 690 | } 691 | else 692 | { 693 | if (isset($matches[2]) or in_array($matches[1], $this->voidElements)) 694 | { 695 | return; 696 | } 697 | 698 | if (preg_match('/<\/'.$matches[1].'>[ ]*$/i', $remainder)) 699 | { 700 | $Block['closed'] = true; 701 | } 702 | } 703 | 704 | return $Block; 705 | } 706 | } 707 | 708 | protected function blockMarkupContinue($Line, array $Block) 709 | { 710 | if (isset($Block['closed'])) 711 | { 712 | return; 713 | } 714 | 715 | if (preg_match('/^<'.$Block['name'].'(?:[ ]*'.$this->regexHtmlAttribute.')*[ ]*>/i', $Line['text'])) # open 716 | { 717 | $Block['depth'] ++; 718 | } 719 | 720 | if (preg_match('/(.*?)<\/'.$Block['name'].'>[ ]*$/i', $Line['text'], $matches)) # close 721 | { 722 | if ($Block['depth'] > 0) 723 | { 724 | $Block['depth'] --; 725 | } 726 | else 727 | { 728 | $Block['closed'] = true; 729 | } 730 | } 731 | 732 | if (isset($Block['interrupted'])) 733 | { 734 | $Block['markup'] .= "\n"; 735 | 736 | unset($Block['interrupted']); 737 | } 738 | 739 | $Block['markup'] .= "\n".$Line['body']; 740 | 741 | return $Block; 742 | } 743 | 744 | # 745 | # Reference 746 | 747 | protected function blockReference($Line) 748 | { 749 | if (preg_match('/^\[(.+?)\]:[ ]*?(?:[ ]+["\'(](.+)["\')])?[ ]*$/', $Line['text'], $matches)) 750 | { 751 | $id = strtolower($matches[1]); 752 | 753 | $Data = array( 754 | 'url' => $matches[2], 755 | 'title' => null, 756 | ); 757 | 758 | if (isset($matches[3])) 759 | { 760 | $Data['title'] = $matches[3]; 761 | } 762 | 763 | $this->DefinitionData['Reference'][$id] = $Data; 764 | 765 | $Block = array( 766 | 'hidden' => true, 767 | ); 768 | 769 | return $Block; 770 | } 771 | } 772 | 773 | # 774 | # Table 775 | 776 | protected function blockTable($Line, array $Block = null) 777 | { 778 | if ( ! isset($Block) or isset($Block['type']) or isset($Block['interrupted'])) 779 | { 780 | return; 781 | } 782 | 783 | if (strpos($Block['element']['text'], '|') !== false and chop($Line['text'], ' -:|') === '') 784 | { 785 | $alignments = array(); 786 | 787 | $divider = $Line['text']; 788 | 789 | $divider = trim($divider); 790 | $divider = trim($divider, '|'); 791 | 792 | $dividerCells = explode('|', $divider); 793 | 794 | foreach ($dividerCells as $dividerCell) 795 | { 796 | $dividerCell = trim($dividerCell); 797 | 798 | if ($dividerCell === '') 799 | { 800 | continue; 801 | } 802 | 803 | $alignment = null; 804 | 805 | if ($dividerCell[0] === ':') 806 | { 807 | $alignment = 'left'; 808 | } 809 | 810 | if (substr($dividerCell, - 1) === ':') 811 | { 812 | $alignment = $alignment === 'left' ? 'center' : 'right'; 813 | } 814 | 815 | $alignments []= $alignment; 816 | } 817 | 818 | # ~ 819 | 820 | $HeaderElements = array(); 821 | 822 | $header = $Block['element']['text']; 823 | 824 | $header = trim($header); 825 | $header = trim($header, '|'); 826 | 827 | $headerCells = explode('|', $header); 828 | 829 | foreach ($headerCells as $index => $headerCell) 830 | { 831 | $headerCell = trim($headerCell); 832 | 833 | $HeaderElement = array( 834 | 'name' => 'th', 835 | 'text' => $headerCell, 836 | 'handler' => 'line', 837 | ); 838 | 839 | if (isset($alignments[$index])) 840 | { 841 | $alignment = $alignments[$index]; 842 | 843 | $HeaderElement['attributes'] = array( 844 | 'style' => 'text-align: '.$alignment.';', 845 | ); 846 | } 847 | 848 | $HeaderElements []= $HeaderElement; 849 | } 850 | 851 | # ~ 852 | 853 | $Block = array( 854 | 'alignments' => $alignments, 855 | 'identified' => true, 856 | 'element' => array( 857 | 'name' => 'table', 858 | 'handler' => 'elements', 859 | ), 860 | ); 861 | 862 | $Block['element']['text'] []= array( 863 | 'name' => 'thead', 864 | 'handler' => 'elements', 865 | ); 866 | 867 | $Block['element']['text'] []= array( 868 | 'name' => 'tbody', 869 | 'handler' => 'elements', 870 | 'text' => array(), 871 | ); 872 | 873 | $Block['element']['text'][0]['text'] []= array( 874 | 'name' => 'tr', 875 | 'handler' => 'elements', 876 | 'text' => $HeaderElements, 877 | ); 878 | 879 | return $Block; 880 | } 881 | } 882 | 883 | protected function blockTableContinue($Line, array $Block) 884 | { 885 | if (isset($Block['interrupted'])) 886 | { 887 | return; 888 | } 889 | 890 | if ($Line['text'][0] === '|' or strpos($Line['text'], '|')) 891 | { 892 | $Elements = array(); 893 | 894 | $row = $Line['text']; 895 | 896 | $row = trim($row); 897 | $row = trim($row, '|'); 898 | 899 | preg_match_all('/(?:(\\\\[|])|[^|`]|`[^`]+`|`)+/', $row, $matches); 900 | 901 | foreach ($matches[0] as $index => $cell) 902 | { 903 | $cell = trim($cell); 904 | 905 | $Element = array( 906 | 'name' => 'td', 907 | 'handler' => 'line', 908 | 'text' => $cell, 909 | ); 910 | 911 | if (isset($Block['alignments'][$index])) 912 | { 913 | $Element['attributes'] = array( 914 | 'style' => 'text-align: '.$Block['alignments'][$index].';', 915 | ); 916 | } 917 | 918 | $Elements []= $Element; 919 | } 920 | 921 | $Element = array( 922 | 'name' => 'tr', 923 | 'handler' => 'elements', 924 | 'text' => $Elements, 925 | ); 926 | 927 | $Block['element']['text'][1]['text'] []= $Element; 928 | 929 | return $Block; 930 | } 931 | } 932 | 933 | # 934 | # ~ 935 | # 936 | 937 | protected function paragraph($Line) 938 | { 939 | $Block = array( 940 | 'element' => array( 941 | 'name' => 'p', 942 | 'text' => $Line['text'], 943 | 'handler' => 'line', 944 | ), 945 | ); 946 | 947 | return $Block; 948 | } 949 | 950 | # 951 | # Inline Elements 952 | # 953 | 954 | protected $InlineTypes = array( 955 | '"' => array('SpecialCharacter'), 956 | '!' => array('Image'), 957 | '&' => array('SpecialCharacter'), 958 | '*' => array('Emphasis'), 959 | ':' => array('Url'), 960 | '<' => array('UrlTag', 'EmailTag', 'Markup', 'SpecialCharacter'), 961 | '>' => array('SpecialCharacter'), 962 | '[' => array('Link'), 963 | '_' => array('Emphasis'), 964 | '`' => array('Code'), 965 | '~' => array('Strikethrough'), 966 | '\\' => array('EscapeSequence'), 967 | ); 968 | 969 | # ~ 970 | 971 | protected $inlineMarkerList = '!"*_&[:<>`~\\'; 972 | 973 | # 974 | # ~ 975 | # 976 | 977 | public function line($text) 978 | { 979 | $markup = ''; 980 | 981 | $unexaminedText = $text; 982 | 983 | $markerPosition = 0; 984 | 985 | while ($excerpt = strpbrk($unexaminedText, $this->inlineMarkerList)) 986 | { 987 | $marker = $excerpt[0]; 988 | 989 | $markerPosition += strpos($unexaminedText, $marker); 990 | 991 | $Excerpt = array('text' => $excerpt, 'context' => $text); 992 | 993 | foreach ($this->InlineTypes[$marker] as $inlineType) 994 | { 995 | $Inline = $this->{'inline'.$inlineType}($Excerpt); 996 | 997 | if ( ! isset($Inline)) 998 | { 999 | continue; 1000 | } 1001 | 1002 | if (isset($Inline['position']) and $Inline['position'] > $markerPosition) # position is ahead of marker 1003 | { 1004 | continue; 1005 | } 1006 | 1007 | if ( ! isset($Inline['position'])) 1008 | { 1009 | $Inline['position'] = $markerPosition; 1010 | } 1011 | 1012 | $unmarkedText = substr($text, 0, $Inline['position']); 1013 | 1014 | $markup .= $this->unmarkedText($unmarkedText); 1015 | 1016 | $markup .= isset($Inline['markup']) ? $Inline['markup'] : $this->element($Inline['element']); 1017 | 1018 | $text = substr($text, $Inline['position'] + $Inline['extent']); 1019 | 1020 | $unexaminedText = $text; 1021 | 1022 | $markerPosition = 0; 1023 | 1024 | continue 2; 1025 | } 1026 | 1027 | $unexaminedText = substr($excerpt, 1); 1028 | 1029 | $markerPosition ++; 1030 | } 1031 | 1032 | $markup .= $this->unmarkedText($text); 1033 | 1034 | return $markup; 1035 | } 1036 | 1037 | # 1038 | # ~ 1039 | # 1040 | 1041 | protected function inlineCode($Excerpt) 1042 | { 1043 | $marker = $Excerpt['text'][0]; 1044 | 1045 | if (preg_match('/^('.$marker.'+)[ ]*(.+?)[ ]*(? strlen($matches[0]), 1053 | 'element' => array( 1054 | 'name' => 'code', 1055 | 'text' => $text, 1056 | ), 1057 | ); 1058 | } 1059 | } 1060 | 1061 | protected function inlineEmailTag($Excerpt) 1062 | { 1063 | if (strpos($Excerpt['text'], '>') !== false and preg_match('/^<((mailto:)?\S+?@\S+?)>/i', $Excerpt['text'], $matches)) 1064 | { 1065 | $url = $matches[1]; 1066 | 1067 | if ( ! isset($matches[2])) 1068 | { 1069 | $url = 'mailto:' . $url; 1070 | } 1071 | 1072 | return array( 1073 | 'extent' => strlen($matches[0]), 1074 | 'element' => array( 1075 | 'name' => 'a', 1076 | 'text' => $matches[1], 1077 | 'attributes' => array( 1078 | 'href' => $url, 1079 | ), 1080 | ), 1081 | ); 1082 | } 1083 | } 1084 | 1085 | protected function inlineEmphasis($Excerpt) 1086 | { 1087 | if ( ! isset($Excerpt['text'][1])) 1088 | { 1089 | return; 1090 | } 1091 | 1092 | $marker = $Excerpt['text'][0]; 1093 | 1094 | if ($Excerpt['text'][1] === $marker and preg_match($this->StrongRegex[$marker], $Excerpt['text'], $matches)) 1095 | { 1096 | $emphasis = 'strong'; 1097 | } 1098 | elseif (preg_match($this->EmRegex[$marker], $Excerpt['text'], $matches)) 1099 | { 1100 | $emphasis = 'em'; 1101 | } 1102 | else 1103 | { 1104 | return; 1105 | } 1106 | 1107 | return array( 1108 | 'extent' => strlen($matches[0]), 1109 | 'element' => array( 1110 | 'name' => $emphasis, 1111 | 'handler' => 'line', 1112 | 'text' => $matches[1], 1113 | ), 1114 | ); 1115 | } 1116 | 1117 | protected function inlineEscapeSequence($Excerpt) 1118 | { 1119 | if (isset($Excerpt['text'][1]) and in_array($Excerpt['text'][1], $this->specialCharacters)) 1120 | { 1121 | return array( 1122 | 'markup' => $Excerpt['text'][1], 1123 | 'extent' => 2, 1124 | ); 1125 | } 1126 | } 1127 | 1128 | protected function inlineImage($Excerpt) 1129 | { 1130 | if ( ! isset($Excerpt['text'][1]) or $Excerpt['text'][1] !== '[') 1131 | { 1132 | return; 1133 | } 1134 | 1135 | $Excerpt['text']= substr($Excerpt['text'], 1); 1136 | 1137 | $Link = $this->inlineLink($Excerpt); 1138 | 1139 | if ($Link === null) 1140 | { 1141 | return; 1142 | } 1143 | 1144 | $Inline = array( 1145 | 'extent' => $Link['extent'] + 1, 1146 | 'element' => array( 1147 | 'name' => 'img', 1148 | 'attributes' => array( 1149 | 'src' => $Link['element']['attributes']['href'], 1150 | 'alt' => $Link['element']['text'], 1151 | 'data-action' => 'zoom', 1152 | 'style' => 'max-width:100%', 1153 | ), 1154 | ), 1155 | ); 1156 | 1157 | $Inline['element']['attributes'] += $Link['element']['attributes']; 1158 | 1159 | unset($Inline['element']['attributes']['href']); 1160 | 1161 | return $Inline; 1162 | } 1163 | 1164 | protected function inlineLink($Excerpt) 1165 | { 1166 | $Element = array( 1167 | 'name' => 'a', 1168 | 'handler' => 'line', 1169 | 'text' => null, 1170 | 'attributes' => array( 1171 | 'href' => null, 1172 | 'title' => null, 1173 | ), 1174 | ); 1175 | 1176 | $extent = 0; 1177 | 1178 | $remainder = $Excerpt['text']; 1179 | 1180 | if (preg_match('/\[((?:[^][]|(?R))*)\]/', $remainder, $matches)) 1181 | { 1182 | $Element['text'] = $matches[1]; 1183 | 1184 | $extent += strlen($matches[0]); 1185 | 1186 | $remainder = substr($remainder, $extent); 1187 | } 1188 | else 1189 | { 1190 | return; 1191 | } 1192 | 1193 | if (preg_match('/^[(]((?:[^ ()]|[(][^ )]+[)])+)(?:[ ]+("[^"]*"|\'[^\']*\'))?[)]/', $remainder, $matches)) 1194 | { 1195 | $Element['attributes']['href'] = $matches[1]; 1196 | 1197 | if (isset($matches[2])) 1198 | { 1199 | $Element['attributes']['title'] = substr($matches[2], 1, - 1); 1200 | } 1201 | 1202 | $extent += strlen($matches[0]); 1203 | } 1204 | else 1205 | { 1206 | if (preg_match('/^\s*\[(.*?)\]/', $remainder, $matches)) 1207 | { 1208 | $definition = strlen($matches[1]) ? $matches[1] : $Element['text']; 1209 | $definition = strtolower($definition); 1210 | 1211 | $extent += strlen($matches[0]); 1212 | } 1213 | else 1214 | { 1215 | $definition = strtolower($Element['text']); 1216 | } 1217 | 1218 | if ( ! isset($this->DefinitionData['Reference'][$definition])) 1219 | { 1220 | return; 1221 | } 1222 | 1223 | $Definition = $this->DefinitionData['Reference'][$definition]; 1224 | 1225 | $Element['attributes']['href'] = $Definition['url']; 1226 | $Element['attributes']['title'] = $Definition['title']; 1227 | } 1228 | 1229 | $Element['attributes']['href'] = str_replace(array('&', '<'), array('&', '<'), $Element['attributes']['href']); 1230 | 1231 | return array( 1232 | 'extent' => $extent, 1233 | 'element' => $Element, 1234 | ); 1235 | } 1236 | 1237 | protected function inlineMarkup($Excerpt) 1238 | { 1239 | if ($this->markupEscaped or strpos($Excerpt['text'], '>') === false) 1240 | { 1241 | return; 1242 | } 1243 | 1244 | if ($Excerpt['text'][1] === '/' and preg_match('/^<\/\w*[ ]*>/s', $Excerpt['text'], $matches)) 1245 | { 1246 | return array( 1247 | 'markup' => $matches[0], 1248 | 'extent' => strlen($matches[0]), 1249 | ); 1250 | } 1251 | 1252 | if ($Excerpt['text'][1] === '!' and preg_match('/^/s', $Excerpt['text'], $matches)) 1253 | { 1254 | return array( 1255 | 'markup' => $matches[0], 1256 | 'extent' => strlen($matches[0]), 1257 | ); 1258 | } 1259 | 1260 | if ($Excerpt['text'][1] !== ' ' and preg_match('/^<\w*(?:[ ]*'.$this->regexHtmlAttribute.')*[ ]*\/?>/s', $Excerpt['text'], $matches)) 1261 | { 1262 | return array( 1263 | 'markup' => $matches[0], 1264 | 'extent' => strlen($matches[0]), 1265 | ); 1266 | } 1267 | } 1268 | 1269 | protected function inlineSpecialCharacter($Excerpt) 1270 | { 1271 | if ($Excerpt['text'][0] === '&' and ! preg_match('/^&#?\w+;/', $Excerpt['text'])) 1272 | { 1273 | return array( 1274 | 'markup' => '&', 1275 | 'extent' => 1, 1276 | ); 1277 | } 1278 | 1279 | $SpecialCharacter = array('>' => 'gt', '<' => 'lt', '"' => 'quot'); 1280 | 1281 | if (isset($SpecialCharacter[$Excerpt['text'][0]])) 1282 | { 1283 | return array( 1284 | 'markup' => '&'.$SpecialCharacter[$Excerpt['text'][0]].';', 1285 | 'extent' => 1, 1286 | ); 1287 | } 1288 | } 1289 | 1290 | protected function inlineStrikethrough($Excerpt) 1291 | { 1292 | if ( ! isset($Excerpt['text'][1])) 1293 | { 1294 | return; 1295 | } 1296 | 1297 | if ($Excerpt['text'][1] === '~' and preg_match('/^~~(?=\S)(.+?)(?<=\S)~~/', $Excerpt['text'], $matches)) 1298 | { 1299 | return array( 1300 | 'extent' => strlen($matches[0]), 1301 | 'element' => array( 1302 | 'name' => 'del', 1303 | 'text' => $matches[1], 1304 | 'handler' => 'line', 1305 | ), 1306 | ); 1307 | } 1308 | } 1309 | 1310 | protected function inlineUrl($Excerpt) 1311 | { 1312 | if ($this->urlsLinked !== true or ! isset($Excerpt['text'][2]) or $Excerpt['text'][2] !== '/') 1313 | { 1314 | return; 1315 | } 1316 | 1317 | if (preg_match('/\bhttps?:[\/]{2}[^\s<]+\b\/*/ui', $Excerpt['context'], $matches, PREG_OFFSET_CAPTURE)) 1318 | { 1319 | $Inline = array( 1320 | 'extent' => strlen($matches[0][0]), 1321 | 'position' => $matches[0][1], 1322 | 'element' => array( 1323 | 'name' => 'a', 1324 | 'text' => $matches[0][0], 1325 | 'attributes' => array( 1326 | 'href' => $matches[0][0], 1327 | ), 1328 | ), 1329 | ); 1330 | 1331 | return $Inline; 1332 | } 1333 | } 1334 | 1335 | protected function inlineUrlTag($Excerpt) 1336 | { 1337 | if (strpos($Excerpt['text'], '>') !== false and preg_match('/^<(\w+:\/{2}[^ >]+)>/i', $Excerpt['text'], $matches)) 1338 | { 1339 | $url = str_replace(array('&', '<'), array('&', '<'), $matches[1]); 1340 | 1341 | return array( 1342 | 'extent' => strlen($matches[0]), 1343 | 'element' => array( 1344 | 'name' => 'a', 1345 | 'text' => $url, 1346 | 'attributes' => array( 1347 | 'href' => $url, 1348 | ), 1349 | ), 1350 | ); 1351 | } 1352 | } 1353 | 1354 | # ~ 1355 | 1356 | protected function unmarkedText($text) 1357 | { 1358 | if ($this->breaksEnabled) 1359 | { 1360 | $text = preg_replace('/[ ]*\n/', "
\n", $text); 1361 | } 1362 | else 1363 | { 1364 | $text = preg_replace('/(?:[ ][ ]+|[ ]*\\\\)\n/', "
\n", $text); 1365 | $text = str_replace(" \n", "\n", $text); 1366 | } 1367 | 1368 | return $text; 1369 | } 1370 | 1371 | # 1372 | # Handlers 1373 | # 1374 | 1375 | protected function element(array $Element) 1376 | { 1377 | $markup = '<'.$Element['name']; 1378 | 1379 | if (isset($Element['attributes'])) 1380 | { 1381 | foreach ($Element['attributes'] as $name => $value) 1382 | { 1383 | if ($value === null) 1384 | { 1385 | continue; 1386 | } 1387 | 1388 | $markup .= ' '.$name.'="'.$value.'"'; 1389 | } 1390 | } 1391 | 1392 | if (isset($Element['text'])) 1393 | { 1394 | $markup .= '>'; 1395 | 1396 | if (isset($Element['handler'])) 1397 | { 1398 | $markup .= $this->{$Element['handler']}($Element['text']); 1399 | } 1400 | else 1401 | { 1402 | $markup .= $Element['text']; 1403 | } 1404 | 1405 | $markup .= ''; 1406 | } 1407 | else 1408 | { 1409 | $markup .= ' />'; 1410 | } 1411 | 1412 | return $markup; 1413 | } 1414 | 1415 | protected function elements(array $Elements) 1416 | { 1417 | $markup = ''; 1418 | 1419 | foreach ($Elements as $Element) 1420 | { 1421 | $markup .= "\n" . $this->element($Element); 1422 | } 1423 | 1424 | $markup .= "\n"; 1425 | 1426 | return $markup; 1427 | } 1428 | 1429 | # ~ 1430 | 1431 | protected function li($lines) 1432 | { 1433 | $markup = $this->lines($lines); 1434 | 1435 | $trimmedMarkup = trim($markup); 1436 | 1437 | if ( ! in_array('', $lines) and substr($trimmedMarkup, 0, 3) === '

') 1438 | { 1439 | $markup = $trimmedMarkup; 1440 | $markup = substr($markup, 3); 1441 | 1442 | $position = strpos($markup, "

"); 1443 | 1444 | $markup = substr_replace($markup, '', $position, 4); 1445 | } 1446 | 1447 | return $markup; 1448 | } 1449 | 1450 | # 1451 | # Deprecated Methods 1452 | # 1453 | 1454 | function parse($text) 1455 | { 1456 | $markup = $this->text($text); 1457 | 1458 | return $markup; 1459 | } 1460 | 1461 | # 1462 | # Static Methods 1463 | # 1464 | 1465 | static function instance($name = 'default') 1466 | { 1467 | if (isset(self::$instances[$name])) 1468 | { 1469 | return self::$instances[$name]; 1470 | } 1471 | 1472 | $instance = new self(); 1473 | 1474 | self::$instances[$name] = $instance; 1475 | 1476 | return $instance; 1477 | } 1478 | 1479 | private static $instances = array(); 1480 | 1481 | # 1482 | # Fields 1483 | # 1484 | 1485 | protected $DefinitionData; 1486 | 1487 | # 1488 | # Read-Only 1489 | 1490 | protected $specialCharacters = array( 1491 | '\\', '`', '*', '_', '{', '}', '[', ']', '(', ')', '>', '#', '+', '-', '.', '!', '|', 1492 | ); 1493 | 1494 | protected $StrongRegex = array( 1495 | '*' => '/^[*]{2}((?:\\\\\*|[^*]|[*][^*]*[*])+?)[*]{2}(?![*])/s', 1496 | '_' => '/^__((?:\\\\_|[^_]|_[^_]*_)+?)__(?!_)/us', 1497 | ); 1498 | 1499 | protected $EmRegex = array( 1500 | '*' => '/^[*]((?:\\\\\*|[^*]|[*][*][^*]+?[*][*])+?)[*](?![*])/s', 1501 | '_' => '/^_((?:\\\\_|[^_]|__[^_]*__)+?)_(?!_)\b/us', 1502 | ); 1503 | 1504 | protected $regexHtmlAttribute = '[a-zA-Z_:][\w:.-]*(?:\s*=\s*(?:[^"\'=<>`\s]+|"[^"]*"|\'[^\']*\'))?'; 1505 | 1506 | protected $voidElements = array( 1507 | 'area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source', 1508 | ); 1509 | 1510 | protected $textLevelElements = array( 1511 | 'a', 'br', 'bdo', 'abbr', 'blink', 'nextid', 'acronym', 'basefont', 1512 | 'b', 'em', 'big', 'cite', 'small', 'spacer', 'listing', 1513 | 'i', 'rp', 'del', 'code', 'strike', 'marquee', 1514 | 'q', 'rt', 'ins', 'font', 'strong', 1515 | 's', 'tt', 'sub', 'mark', 1516 | 'u', 'xm', 'sup', 'nobr', 1517 | 'var', 'ruby', 1518 | 'wbr', 'span', 1519 | 'time', 1520 | ); 1521 | } -------------------------------------------------------------------------------- /src/config/editor.php: -------------------------------------------------------------------------------- 1 | '890px', 6 | 'uploadUrl'=>'home/upload', 7 | /* 8 | * 在添加链接的时候可以给定一个ajax链接,这样可以方便的添加在系统中的文章 9 | * 服务器返回的数据格式为:{'title':'url','title2':'url2'} 10 | */ 11 | // 'ajaxTopicSearchUrl' => 'home/ajax-search-topics' 12 | ]; -------------------------------------------------------------------------------- /src/config/editor/css/editor.css: -------------------------------------------------------------------------------- 1 | .editor { 2 | position: relative; 3 | z-index: 1; 4 | margin-bottom: 20px; 5 | min-height: 300px; } 6 | .editor textarea { 7 | resize: none; } 8 | .editor .text-muted { 9 | cursor: default; 10 | text-decoration: none; } 11 | .editor .text-muted:hover { 12 | cursor: default; 13 | color: #999; } 14 | .editor__input { 15 | border: none; 16 | width: 100%; 17 | resize: none; 18 | padding: 10px; 19 | margin-bottom: -5px; 20 | border-radius: 5px; } 21 | .editor__resize { 22 | position: absolute; 23 | width: 100px; 24 | height: 4px; 25 | left: 50%; 26 | margin-left: -50px; 27 | margin-top: 2px; 28 | border-top: 1px solid #ddd; 29 | border-bottom: 1px solid #ddd; 30 | text-indent: -9999px; 31 | cursor: row-resize; } 32 | 33 | .editor__menu { 34 | list-style: none; 35 | margin: 0; 36 | padding: 0 5px; 37 | border: 1px solid #ddd; 38 | border-bottom: none; 39 | background-color: #f6f6f6; 40 | border-radius: 2px 2px 0 0; 41 | position: relative; 42 | z-index: 2; } 43 | .editor__menu li { 44 | float: left; 45 | margin: 0 2px; 46 | vertical-align: text-top; } 47 | .editor__menu a { 48 | cursor: pointer; 49 | display: block; 50 | border: 5px solid #f6f6f6; 51 | box-sizing: content-box; 52 | width: 20px; 53 | height: 20px; 54 | background-repeat: no-repeat; 55 | background-size: 380px 60px; 56 | background-image: url(../images/editor@2x.png); 57 | text-indent: -9999px; } 58 | .editor__menu a.muted, 59 | .editor__menu a.muted:hover { 60 | background-position-y: -20px; 61 | background-color: #f6f6f6; 62 | border-color: #f6f6f6; 63 | cursor: default; } 64 | .editor__menu a:hover, 65 | .editor__menu a.active { 66 | border-color: #fff; 67 | background-color: #fff; 68 | background-position-y: -40px; 69 | text-decoration: none; } 70 | .editor__menu .active { 71 | color: #999; } 72 | .editor__menu--bold { 73 | background-position: -1px 0px; } 74 | .editor__menu--italic { 75 | background-position: -21px 0px; } 76 | .editor__menu--link { 77 | background-position: -40px 0px; } 78 | .editor__menu--quote { 79 | background-position: -60px 0px; } 80 | .editor__menu--code { 81 | background-position: -80px 0px; } 82 | .editor__menu--img { 83 | background-position: -100px 0px; } 84 | .editor__menu--ol { 85 | background-position: -120px 0px; } 86 | .editor__menu--ul { 87 | background-position: -140px 0px; } 88 | .editor__menu--title { 89 | background-position: -160px 0px; } 90 | .editor__menu--hr { 91 | background-position: -180px 0px; } 92 | .editor__menu--undo { 93 | background-position: -200px 0px; } 94 | .editor__menu--redo { 95 | background-position: -220px 0px; } 96 | .editor__menu--zen { 97 | background-position: -240px 0px; } 98 | .editor__menu--unzen { 99 | background-position: -260px 0px; } 100 | .editor__menu--two { 101 | background-position: -280px 0px; } 102 | .editor__menu--help { 103 | background-position: -300px 0px; } 104 | .editor__menu .editor__menu--divider { 105 | margin: 5px 4px; 106 | width: 0; 107 | text-indent: -9999px; 108 | height: 20px; 109 | padding-left: 0; 110 | padding-right: 0; 111 | border-right: 1px solid #ddd; } 112 | .editor__menu--edit { 113 | background-position: -320px 0px; } 114 | .editor__menu--live { 115 | background-position: -340px 0px; } 116 | .editor__menu--preview { 117 | background-position: -360px 0px; } 118 | 119 | .editor-help { 120 | border: 1px solid #ddd; 121 | border-bottom: none; 122 | background-color: #faf2cc; 123 | font-size: 13px; } 124 | .editor-help .nav-tabs { 125 | border-bottom: none; 126 | background-color: #fcf8e3; } 127 | .editor-help .nav > li { 128 | margin: 0; } 129 | .editor-help .nav > li > a { 130 | margin: 0; 131 | padding: 6px 10px; 132 | border: none; 133 | color: #8a6d3b; 134 | border-radius: 0; } 135 | .editor-help .nav > li.active > a, 136 | .editor-help .nav > li > a:hover { 137 | border: none; 138 | background-color: #faf2cc; 139 | color: #8a6d3b; 140 | cursor: pointer; } 141 | .editor-help .nav > li.active > a { 142 | font-weight: bold; } 143 | 144 | .editor-help-content { 145 | padding: 10px; } 146 | .editor-help-content pre { 147 | padding: 5px 8px; 148 | border: none; 149 | background-color: #fcf8e3; 150 | font-size: 12px; } 151 | .editor-help-content code { 152 | white-space: normal; } 153 | 154 | .widget-editor__wrap { 155 | background: #F6F6F6; 156 | border-top: 1px solid #DDD; } 157 | 158 | .widget-editor .widget-editor__help { 159 | margin-top: 40px; } 160 | 161 | .CodeMirror { 162 | height: auto; 163 | /*min-height: 420px;*/ 164 | padding: 0; } 165 | .CodeMirror .CodeMirror-scroll { 166 | height: 100%; 167 | min-height: 420px; } 168 | .CodeMirror .CodeMirror-cursor { 169 | height: 20px !important; } 170 | 171 | /* DEFAULT THEME */ 172 | .cm-s-paper .cm-keyword { 173 | color: #555; } 174 | 175 | .cm-s-paper .cm-atom { 176 | color: #7f8c8d; } 177 | 178 | .cm-s-paper .cm-number { 179 | color: #7f8c8d; } 180 | 181 | .cm-s-paper .cm-def { 182 | color: #00f; } 183 | 184 | .cm-s-paper .cm-variable { 185 | color: black; } 186 | 187 | .cm-s-paper .cm-variable-2 { 188 | color: #555; } 189 | 190 | .cm-s-paper .cm-variable-3 { 191 | color: #085; } 192 | 193 | .cm-s-paper .cm-property { 194 | color: black; } 195 | 196 | .cm-s-paper .cm-operator { 197 | color: black; } 198 | 199 | .cm-s-paper .cm-comment { 200 | color: #959595; } 201 | 202 | .cm-s-paper .cm-string { 203 | color: #7f8c8d; } 204 | 205 | .cm-s-paper .cm-string-2 { 206 | color: #f50; } 207 | 208 | .cm-s-paper .cm-meta { 209 | color: #555; } 210 | 211 | .cm-s-paper .cm-error { 212 | color: #f00; } 213 | 214 | .cm-s-paper .cm-qualifier { 215 | color: #555; } 216 | 217 | .cm-s-paper .cm-builtin { 218 | color: #555; } 219 | 220 | .cm-s-paper .cm-bracket { 221 | color: #997; } 222 | 223 | .cm-s-paper .cm-tag { 224 | color: #7f8c8d; } 225 | 226 | .cm-s-paper .cm-attribute { 227 | color: #7f8c8d; } 228 | 229 | .cm-s-paper .cm-header { 230 | color: #000; } 231 | 232 | .cm-s-paper .cm-quote { 233 | color: #888; } 234 | 235 | .cm-s-paper .cm-hr { 236 | color: #999; } 237 | 238 | .cm-s-paper .cm-link { 239 | color: #7f8c8d; } 240 | 241 | .cm-negative { 242 | color: #d44; } 243 | 244 | .cm-positive { 245 | color: #292; } 246 | 247 | .cm-header, .cm-strong { 248 | font-weight: bold; } 249 | 250 | .cm-em { 251 | font-style: italic; } 252 | 253 | .cm-link { 254 | text-decoration: underline; } 255 | 256 | .cm-invalidchar { 257 | color: #f00; } 258 | 259 | div.CodeMirror span.CodeMirror-matchingbracket { 260 | color: #0f0; } 261 | 262 | div.CodeMirror span.CodeMirror-nonmatchingbracket { 263 | color: #f22; } 264 | 265 | .CodeMirror-focused { 266 | border-color: #66afe9; 267 | outline: 0; 268 | box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); } 269 | 270 | :-webkit-full-screen { 271 | background: #f9f9f5; 272 | padding: 0.5em 1em; 273 | width: 100%; 274 | height: 100%; } 275 | 276 | :-moz-full-screen { 277 | padding: 0.5em 1em; 278 | background: #f9f9f5; 279 | width: 100%; 280 | height: 100%; } 281 | 282 | .editor-preview { 283 | position: absolute; 284 | padding: 20px; 285 | background-color: #f6f6f6; 286 | width: 100%; 287 | height: 100%; 288 | top: 0; 289 | left: 100%; 290 | z-index: 999; 291 | overflow: auto; 292 | overflow-x: hidden; 293 | -webkit-transition: left 0.1s ease; 294 | -moz-transition: left 0.1s ease; 295 | -ms-transition: left 0.1s ease; 296 | transition: left 0.1s ease; } 297 | .editor-preview code, .editor-preview pre, .editor-preview kbd { 298 | background-color: #eee !important; } 299 | 300 | .editor-preview-active { 301 | left: 0; } 302 | 303 | .editor-preview-active.onlive { 304 | left: 50%; 305 | width: 50%; } 306 | 307 | .editor-preview > p { 308 | margin-top: 0; } 309 | 310 | .editor-preview pre.hljs { 311 | padding: 10px; 312 | } 313 | 314 | .widget-upload { 315 | position: relative; 316 | } 317 | .widget-upload .widget-upload__file { 318 | position: absolute; 319 | opacity: 0; 320 | width: 85%; 321 | height: 100%; 322 | z-index: 10; 323 | cursor: pointer; 324 | } 325 | 326 | input.loading { 327 | background: url(../images/loader.gif) no-repeat right center; 328 | } 329 | -------------------------------------------------------------------------------- /src/config/editor/css/editor.css.map: -------------------------------------------------------------------------------- 1 | { 2 | "version": 3, 3 | "mappings": "AACQ,oDAAyC;AAEjD,OAAQ;EACN,QAAQ,EAAE,QAAQ;EAClB,OAAO,EAAE,CAAC;EACV,aAAa,EAAE,IAAI;EACnB,UAAU,EAAE,KAAK;EACjB,gBAAS;IACP,MAAM,EAAE,IAAI;EAEd,mBAAY;IACR,MAAM,EAAE,OAAO;IACf,eAAe,EAAE,IAAI;IACrB,yBAAQ;MACN,MAAM,EAAE,OAAO;MACf,KAAK,EAAE,IAAI;EAGjB,cAAS;IACP,MAAM,EAAE,IAAI;IACZ,KAAK,EAAE,IAAI;IACX,MAAM,EAAE,IAAI;IACZ,OAAO,EAAE,IAAI;IACb,aAAa,EAAE,IAAI;IACnB,aAAa,EAAE,GAAG;EAEpB,eAAU;IACR,QAAQ,EAAE,QAAQ;IAClB,KAAK,EAAE,KAAK;IACZ,MAAM,EAAE,GAAG;IACX,IAAI,EAAE,GAAG;IACT,WAAW,EAAE,KAAK;IAClB,UAAU,EAAE,GAAG;IACf,UAAU,EAAE,cAAc;IAC1B,aAAa,EAAE,cAAc;IAC7B,WAAW,EAAE,OAAO;IACpB,MAAM,EAAE,UAAU;;AAKtB,aAAc;EACZ,UAAU,EAAE,IAAI;EAChB,MAAM,EAAE,CAAC;EACT,OAAO,EAAE,KAAK;EACd,MAAM,EAAE,cAAc;EACtB,aAAa,EAAE,IAAI;EACnB,gBAAgB,EAAE,OAAO;EACzB,aAAa,EAAE,WAAW;EAC1B,QAAQ,EAAE,QAAQ;EAClB,OAAO,EAAE,CAAC;EACV,gBAAG;IACD,KAAK,EAAE,IAAI;IACX,MAAM,EAAE,KAAK;IACb,cAAc,EAAE,QAAQ;EAE1B,eAAE;IACA,MAAM,EAAE,OAAO;IACf,OAAO,EAAE,KAAK;IACd,MAAM,EAAE,iBAAiB;IACzB,UAAU,EAAE,WAAW;IACvB,KAAK,EAAE,IAAI;IACX,MAAM,EAAE,IAAI;IACZ,iBAAiB,EAAE,SAAS;IAC5B,eAAe,EAAE,UAAU;IAC3B,gBAAgB,EAAE,gCAAgC;IAClD,WAAW,EAAE,OAAO;EAGtB;6BACc;IACZ,qBAAqB,EAAE,KAAK;IAC5B,gBAAgB,EAAE,OAAO;IACzB,YAAY,EAAE,OAAO;IACrB,MAAM,EAAE,OAAO;EAEjB;wBACS;IACP,YAAY,EAAE,IAAI;IAClB,gBAAgB,EAAE,IAAI;IACtB,qBAAqB,EAAE,KAAK;IAC5B,eAAe,EAAE,IAAI;EAEvB,qBAAQ;IACN,KAAK,EAAE,IAAI;EAEb,mBAAQ;IACN,mBAAmB,EAAE,QAAQ;EAE/B,qBAAU;IACR,mBAAmB,EAAE,SAAS;EAEhC,mBAAQ;IACN,mBAAmB,EAAE,SAAS;EAEhC,oBAAS;IACP,mBAAmB,EAAE,SAAS;EAEhC,mBAAQ;IACN,mBAAmB,EAAE,SAAS;EAEhC,kBAAO;IACL,mBAAmB,EAAE,UAAU;EAEjC,iBAAM;IACJ,mBAAmB,EAAE,UAAU;EAEjC,iBAAM;IACJ,mBAAmB,EAAE,UAAU;EAEjC,oBAAS;IACP,mBAAmB,EAAE,UAAU;EAEjC,iBAAM;IACJ,mBAAmB,EAAE,UAAU;EAEjC,mBAAQ;IACN,mBAAmB,EAAE,UAAU;EAEjC,mBAAQ;IACN,mBAAmB,EAAE,UAAU;EAEjC,kBAAO;IACL,mBAAmB,EAAE,UAAU;EAEjC,oBAAS;IACP,mBAAmB,EAAE,UAAU;EAEjC,kBAAO;IACL,mBAAmB,EAAE,UAAU;EAEjC,mBAAQ;IACN,mBAAmB,EAAE,UAAU;EAEjC,oCAAuB;IACrB,MAAM,EAAE,OAAO;IACf,KAAK,EAAE,CAAC;IACR,WAAW,EAAE,OAAO;IACpB,MAAM,EAAE,IAAI;IACZ,YAAY,EAAE,CAAC;IACf,aAAa,EAAE,CAAC;IAChB,YAAY,EAAE,cAAc;EAE9B,mBAAQ;IACN,mBAAmB,EAAE,UAAU;EAEjC,mBAAQ;IACN,mBAAmB,EAAE,UAAU;EAEjC,sBAAW;IACT,mBAAmB,EAAE,UAAU;;AAKnC,YAAa;EACX,MAAM,EAAE,cAAc;EACtB,aAAa,EAAE,IAAI;EACnB,gBAAgB,EAAE,OAAmB;EACrC,SAAS,EAAE,IAAI;EACf,sBAAU;IACR,aAAa,EAAE,IAAI;IACnB,gBAAgB,EAAE,OAAO;EAE3B,sBAAU;IACR,MAAM,EAAE,CAAC;EAEX,0BAAc;IACZ,MAAM,EAAE,CAAC;IACT,OAAO,EAAE,QAAQ;IACjB,MAAM,EAAE,IAAI;IACZ,KAAK,EAAE,OAAO;IACd,aAAa,EAAE,CAAC;EAElB;kCACqB;IACnB,MAAM,EAAE,IAAI;IACZ,gBAAgB,EAAE,OAAmB;IACrC,KAAK,EAAE,OAAO;IACd,MAAM,EAAE,OAAO;EAEjB,iCAAqB;IACnB,WAAW,EAAE,IAAI;;AAGrB,oBAAqB;EACnB,OAAO,EAAE,IAAI;EACb,wBAAI;IACF,OAAO,EAAE,OAAO;IAChB,MAAM,EAAE,IAAI;IACZ,gBAAgB,EAAE,OAAO;IACzB,SAAS,EAAE,IAAI;EAEjB,yBAAK;IACH,WAAW,EAAE,MAAM;;AAKvB,oBAAqB;EACnB,UAAU,EAAE,OAAO;EACnB,UAAU,EAAE,cAAc;;AAG1B,mCAAqB;EACnB,UAAU,EAAE,IAAI;;AAIpB,WAAY;EACV,MAAM,EAAE,IAAI;EACZ,UAAU,EAAE,KAAK;EACjB,OAAO,EAAE,CAAC;EACV,8BAAmB;IACjB,MAAM,EAAE,IAAI;IACZ,UAAU,EAAE,KAAK;EAEnB,8BAAmB;IACjB,MAAM,EAAE,eAAe;;;AAO3B,uBAAwB;EAAC,KAAK,EAAE,IAAI;;AACpC,oBAAqB;EAAC,KAAK,EAAE,OAAO;;AACpC,sBAAuB;EAAC,KAAK,EAAE,OAAO;;AACtC,mBAAoB;EAAC,KAAK,EAAE,IAAI;;AAChC,wBAAyB;EAAC,KAAK,EAAE,KAAK;;AACtC,0BAA2B;EAAC,KAAK,EAAE,IAAI;;AACvC,0BAA2B;EAAC,KAAK,EAAE,IAAI;;AACvC,wBAAyB;EAAC,KAAK,EAAE,KAAK;;AACtC,wBAAyB;EAAC,KAAK,EAAE,KAAK;;AACtC,uBAAwB;EAAC,KAAK,EAAE,OAAO;;AACvC,sBAAuB;EAAC,KAAK,EAAE,OAAO;;AACtC,wBAAyB;EAAC,KAAK,EAAE,IAAI;;AACrC,oBAAqB;EAAC,KAAK,EAAE,IAAI;;AACjC,qBAAsB;EAAC,KAAK,EAAE,IAAI;;AAClC,yBAA0B;EAAC,KAAK,EAAE,IAAI;;AACtC,uBAAwB;EAAC,KAAK,EAAE,IAAI;;AACpC,uBAAwB;EAAC,KAAK,EAAE,IAAI;;AACpC,mBAAoB;EAAC,KAAK,EAAE,OAAO;;AACnC,yBAA0B;EAAC,KAAK,EAAE,OAAO;;AACzC,sBAAuB;EAAC,KAAK,EAAE,IAAI;;AACnC,qBAAsB;EAAC,KAAK,EAAE,IAAI;;AAClC,kBAAmB;EAAC,KAAK,EAAE,IAAI;;AAC/B,oBAAqB;EAAC,KAAK,EAAE,OAAO;;AAEpC,YAAa;EAAC,KAAK,EAAE,IAAI;;AACzB,YAAa;EAAC,KAAK,EAAE,IAAI;;AACzB,sBAAuB;EAAC,WAAW,EAAE,IAAI;;AACzC,MAAO;EAAC,UAAU,EAAE,MAAM;;AAC1B,QAAS;EAAC,eAAe,EAAE,SAAS;;AAEpC,eAAgB;EAAC,KAAK,EAAE,IAAI;;AAE5B,8CAA+C;EAAC,KAAK,EAAE,IAAI;;AAC3D,iDAAkD;EAAC,KAAK,EAAE,IAAI;;AAE9D,mBAAoB;EAElB,YAAY,EAAE,OAAO;EACrB,OAAO,EAAE,CAAC;EACV,UAAU,EAAE,oCAAgC;;AAG9C,oBAAqB;EACnB,UAAU,EAAE,OAAO;EACnB,OAAO,EAAE,SAAS;EAClB,KAAK,EAAE,IAAI;EACX,MAAM,EAAE,IAAI;;AAEd,iBAAkB;EAChB,OAAO,EAAE,SAAS;EAClB,UAAU,EAAE,OAAO;EACnB,KAAK,EAAE,IAAI;EACX,MAAM,EAAE,IAAI;;AAGd,eAAgB;EACd,QAAQ,EAAE,QAAQ;EAClB,OAAO,EAAE,IAAI;EACb,gBAAgB,EAAE,OAAO;EACzB,KAAK,EAAE,IAAI;EACX,MAAM,EAAE,IAAI;EACZ,GAAG,EAAE,CAAC;EACN,IAAI,EAAE,IAAI;EACV,OAAO,EAAE,GAAG;EACZ,QAAQ,EAAE,IAAI;EACd,UAAU,EAAE,MAAM;EAClB,kBAAkB,EAAE,cAAc;EAClC,eAAe,EAAE,cAAc;EAC/B,cAAc,EAAE,cAAc;EAC9B,UAAU,EAAE,cAAc;EAC1B,8DAAe;IACb,gBAAgB,EAAE,eAAe;;AAGrC,sBAAuB;EAErB,IAAI,EAAE,CAAC;;AAET,6BAA8B;EAC5B,IAAI,EAAE,GAAG;EACT,KAAK,EAAE,GAAG;;AAEZ,mBAAoB;EAClB,UAAU,EAAE,CAAC", 4 | "sources": ["editor.scss"], 5 | "names": [], 6 | "file": "editor.css" 7 | } 8 | -------------------------------------------------------------------------------- /src/config/editor/css/pygment_trac.css: -------------------------------------------------------------------------------- 1 | .highlight { background: #ffffff; } 2 | .highlight .c { color: #999988; font-style: italic } /* Comment */ 3 | .highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ 4 | .highlight .k { font-weight: bold } /* Keyword */ 5 | .highlight .o { font-weight: bold } /* Operator */ 6 | .highlight .cm { color: #999988; font-style: italic } /* Comment.Multiline */ 7 | .highlight .cp { color: #999999; font-weight: bold } /* Comment.Preproc */ 8 | .highlight .c1 { color: #999988; font-style: italic } /* Comment.Single */ 9 | .highlight .cs { color: #999999; font-weight: bold; font-style: italic } /* Comment.Special */ 10 | .highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ 11 | .highlight .gd .x { color: #000000; background-color: #ffaaaa } /* Generic.Deleted.Specific */ 12 | .highlight .ge { font-style: italic } /* Generic.Emph */ 13 | .highlight .gr { color: #aa0000 } /* Generic.Error */ 14 | .highlight .gh { color: #999999 } /* Generic.Heading */ 15 | .highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ 16 | .highlight .gi .x { color: #000000; background-color: #aaffaa } /* Generic.Inserted.Specific */ 17 | .highlight .go { color: #888888 } /* Generic.Output */ 18 | .highlight .gp { color: #555555 } /* Generic.Prompt */ 19 | .highlight .gs { font-weight: bold } /* Generic.Strong */ 20 | .highlight .gu { color: #800080; font-weight: bold; } /* Generic.Subheading */ 21 | .highlight .gt { color: #aa0000 } /* Generic.Traceback */ 22 | .highlight .kc { font-weight: bold } /* Keyword.Constant */ 23 | .highlight .kd { font-weight: bold } /* Keyword.Declaration */ 24 | .highlight .kn { font-weight: bold } /* Keyword.Namespace */ 25 | .highlight .kp { font-weight: bold } /* Keyword.Pseudo */ 26 | .highlight .kr { font-weight: bold } /* Keyword.Reserved */ 27 | .highlight .kt { color: #445588; font-weight: bold } /* Keyword.Type */ 28 | .highlight .m { color: #009999 } /* Literal.Number */ 29 | .highlight .s { color: #d14 } /* Literal.String */ 30 | .highlight .na { color: #008080 } /* Name.Attribute */ 31 | .highlight .nb { color: #0086B3 } /* Name.Builtin */ 32 | .highlight .nc { color: #445588; font-weight: bold } /* Name.Class */ 33 | .highlight .no { color: #008080 } /* Name.Constant */ 34 | .highlight .ni { color: #800080 } /* Name.Entity */ 35 | .highlight .ne { color: #990000; font-weight: bold } /* Name.Exception */ 36 | .highlight .nf { color: #990000; font-weight: bold } /* Name.Function */ 37 | .highlight .nn { color: #555555 } /* Name.Namespace */ 38 | .highlight .nt { color: #000080 } /* Name.Tag */ 39 | .highlight .nv { color: #008080 } /* Name.Variable */ 40 | .highlight .ow { font-weight: bold } /* Operator.Word */ 41 | .highlight .w { color: #bbbbbb } /* Text.Whitespace */ 42 | .highlight .mf { color: #009999 } /* Literal.Number.Float */ 43 | .highlight .mh { color: #009999 } /* Literal.Number.Hex */ 44 | .highlight .mi { color: #009999 } /* Literal.Number.Integer */ 45 | .highlight .mo { color: #009999 } /* Literal.Number.Oct */ 46 | .highlight .sb { color: #d14 } /* Literal.String.Backtick */ 47 | .highlight .sc { color: #d14 } /* Literal.String.Char */ 48 | .highlight .sd { color: #d14 } /* Literal.String.Doc */ 49 | .highlight .s2 { color: #d14 } /* Literal.String.Double */ 50 | .highlight .se { color: #d14 } /* Literal.String.Escape */ 51 | .highlight .sh { color: #d14 } /* Literal.String.Heredoc */ 52 | .highlight .si { color: #d14 } /* Literal.String.Interpol */ 53 | .highlight .sx { color: #d14 } /* Literal.String.Other */ 54 | .highlight .sr { color: #009926 } /* Literal.String.Regex */ 55 | .highlight .s1 { color: #d14 } /* Literal.String.Single */ 56 | .highlight .ss { color: #990073 } /* Literal.String.Symbol */ 57 | .highlight .bp { color: #999999 } /* Name.Builtin.Pseudo */ 58 | .highlight .vc { color: #008080 } /* Name.Variable.Class */ 59 | .highlight .vg { color: #008080 } /* Name.Variable.Global */ 60 | .highlight .vi { color: #008080 } /* Name.Variable.Instance */ 61 | .highlight .il { color: #009999 } /* Literal.Number.Integer.Long */ 62 | 63 | .type-csharp .highlight .k { color: #0000FF } 64 | .type-csharp .highlight .kt { color: #0000FF } 65 | .type-csharp .highlight .nf { color: #000000; font-weight: normal } 66 | .type-csharp .highlight .nc { color: #2B91AF } 67 | .type-csharp .highlight .nn { color: #000000 } 68 | .type-csharp .highlight .s { color: #A31515 } 69 | .type-csharp .highlight .sc { color: #A31515 } 70 | -------------------------------------------------------------------------------- /src/config/editor/css/stylesheet.css: -------------------------------------------------------------------------------- 1 | /*! normalize.css v3.0.0 | MIT License | git.io/normalize */ 2 | 3 | /** 4 | * 1. Set default font family to sans-serif. 5 | * 2. Prevent iOS text size adjust after orientation change, without disabling 6 | * user zoom. 7 | */ 8 | 9 | html { 10 | font-family: sans-serif; /* 1 */ 11 | -ms-text-size-adjust: 100%; /* 2 */ 12 | -webkit-text-size-adjust: 100%; /* 2 */ 13 | } 14 | 15 | /** 16 | * Remove default margin. 17 | */ 18 | 19 | body { 20 | margin: 0; 21 | } 22 | 23 | /* HTML5 display definitions 24 | ========================================================================== */ 25 | 26 | /** 27 | * Correct `block` display not defined for any HTML5 element in IE 8/9. 28 | * Correct `block` display not defined for `details` or `summary` in IE 10/11 and Firefox. 29 | * Correct `block` display not defined for `main` in IE 11. 30 | */ 31 | 32 | article, 33 | aside, 34 | details, 35 | figcaption, 36 | figure, 37 | footer, 38 | header, 39 | hgroup, 40 | main, 41 | nav, 42 | section, 43 | summary { 44 | display: block; 45 | } 46 | 47 | /** 48 | * 1. Correct `inline-block` display not defined in IE 8/9. 49 | * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera. 50 | */ 51 | 52 | audio, 53 | canvas, 54 | progress, 55 | video { 56 | display: inline-block; /* 1 */ 57 | vertical-align: baseline; /* 2 */ 58 | } 59 | 60 | /** 61 | * Prevent modern browsers from displaying `audio` without controls. 62 | * Remove excess height in iOS 5 devices. 63 | */ 64 | 65 | audio:not([controls]) { 66 | display: none; 67 | height: 0; 68 | } 69 | 70 | /** 71 | * Address `[hidden]` styling not present in IE 8/9/10. 72 | * Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22. 73 | */ 74 | 75 | [hidden], 76 | template { 77 | display: none; 78 | } 79 | 80 | /* Links 81 | ========================================================================== */ 82 | 83 | /** 84 | * Remove the gray background color from active links in IE 10. 85 | */ 86 | 87 | a { 88 | background: transparent; 89 | } 90 | 91 | /** 92 | * Improve readability when focused and also mouse hovered in all browsers. 93 | */ 94 | 95 | a:active, 96 | a:hover { 97 | outline: 0; 98 | } 99 | 100 | /* Text-level semantics 101 | ========================================================================== */ 102 | 103 | /** 104 | * Address styling not present in IE 8/9/10/11, Safari, and Chrome. 105 | */ 106 | 107 | abbr[title] { 108 | border-bottom: 1px dotted; 109 | } 110 | 111 | /** 112 | * Address style set to `bolder` in Firefox 4+, Safari, and Chrome. 113 | */ 114 | 115 | b, 116 | strong { 117 | font-weight: bold; 118 | } 119 | 120 | /** 121 | * Address styling not present in Safari and Chrome. 122 | */ 123 | 124 | dfn { 125 | font-style: italic; 126 | } 127 | 128 | /** 129 | * Address variable `h1` font-size and margin within `section` and `article` 130 | * contexts in Firefox 4+, Safari, and Chrome. 131 | */ 132 | 133 | h1 { 134 | font-size: 2em; 135 | margin: 0.67em 0; 136 | } 137 | 138 | /** 139 | * Address styling not present in IE 8/9. 140 | */ 141 | 142 | mark { 143 | background: #ff0; 144 | color: #000; 145 | } 146 | 147 | /** 148 | * Address inconsistent and variable font size in all browsers. 149 | */ 150 | 151 | small { 152 | font-size: 80%; 153 | } 154 | 155 | /** 156 | * Prevent `sub` and `sup` affecting `line-height` in all browsers. 157 | */ 158 | 159 | sub, 160 | sup { 161 | font-size: 75%; 162 | line-height: 0; 163 | position: relative; 164 | vertical-align: baseline; 165 | } 166 | 167 | sup { 168 | top: -0.5em; 169 | } 170 | 171 | sub { 172 | bottom: -0.25em; 173 | } 174 | 175 | /* Embedded content 176 | ========================================================================== */ 177 | 178 | /** 179 | * Remove border when inside `a` element in IE 8/9/10. 180 | */ 181 | 182 | img { 183 | border: 0; 184 | } 185 | 186 | /** 187 | * Correct overflow not hidden in IE 9/10/11. 188 | */ 189 | 190 | svg:not(:root) { 191 | overflow: hidden; 192 | } 193 | 194 | /* Grouping content 195 | ========================================================================== */ 196 | 197 | /** 198 | * Address margin not present in IE 8/9 and Safari. 199 | */ 200 | 201 | figure { 202 | margin: 1em 40px; 203 | } 204 | 205 | /** 206 | * Address differences between Firefox and other browsers. 207 | */ 208 | 209 | hr { 210 | -moz-box-sizing: content-box; 211 | box-sizing: content-box; 212 | height: 0; 213 | } 214 | 215 | /** 216 | * Contain overflow in all browsers. 217 | */ 218 | 219 | pre { 220 | overflow: auto; 221 | } 222 | 223 | /** 224 | * Address odd `em`-unit font size rendering in all browsers. 225 | */ 226 | 227 | code, 228 | kbd, 229 | pre, 230 | samp { 231 | font-family: monospace, monospace; 232 | font-size: 1em; 233 | } 234 | 235 | /* Forms 236 | ========================================================================== */ 237 | 238 | /** 239 | * Known limitation: by default, Chrome and Safari on OS X allow very limited 240 | * styling of `select`, unless a `border` property is set. 241 | */ 242 | 243 | /** 244 | * 1. Correct color not being inherited. 245 | * Known issue: affects color of disabled elements. 246 | * 2. Correct font properties not being inherited. 247 | * 3. Address margins set differently in Firefox 4+, Safari, and Chrome. 248 | */ 249 | 250 | button, 251 | input, 252 | optgroup, 253 | select, 254 | textarea { 255 | color: inherit; /* 1 */ 256 | font: inherit; /* 2 */ 257 | margin: 0; /* 3 */ 258 | } 259 | 260 | /** 261 | * Address `overflow` set to `hidden` in IE 8/9/10/11. 262 | */ 263 | 264 | button { 265 | overflow: visible; 266 | } 267 | 268 | /** 269 | * Address inconsistent `text-transform` inheritance for `button` and `select`. 270 | * All other form control elements do not inherit `text-transform` values. 271 | * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera. 272 | * Correct `select` style inheritance in Firefox. 273 | */ 274 | 275 | button, 276 | select { 277 | text-transform: none; 278 | } 279 | 280 | /** 281 | * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` 282 | * and `video` controls. 283 | * 2. Correct inability to style clickable `input` types in iOS. 284 | * 3. Improve usability and consistency of cursor style between image-type 285 | * `input` and others. 286 | */ 287 | 288 | button, 289 | html input[type="button"], /* 1 */ 290 | input[type="reset"], 291 | input[type="submit"] { 292 | -webkit-appearance: button; /* 2 */ 293 | cursor: pointer; /* 3 */ 294 | } 295 | 296 | /** 297 | * Re-set default cursor for disabled elements. 298 | */ 299 | 300 | button[disabled], 301 | html input[disabled] { 302 | cursor: default; 303 | } 304 | 305 | /** 306 | * Remove inner padding and border in Firefox 4+. 307 | */ 308 | 309 | button::-moz-focus-inner, 310 | input::-moz-focus-inner { 311 | border: 0; 312 | padding: 0; 313 | } 314 | 315 | /** 316 | * Address Firefox 4+ setting `line-height` on `input` using `!important` in 317 | * the UA stylesheet. 318 | */ 319 | 320 | input { 321 | line-height: normal; 322 | } 323 | 324 | /** 325 | * It's recommended that you don't attempt to style these elements. 326 | * Firefox's implementation doesn't respect box-sizing, padding, or width. 327 | * 328 | * 1. Address box sizing set to `content-box` in IE 8/9/10. 329 | * 2. Remove excess padding in IE 8/9/10. 330 | */ 331 | 332 | input[type="checkbox"], 333 | input[type="radio"] { 334 | box-sizing: border-box; /* 1 */ 335 | padding: 0; /* 2 */ 336 | } 337 | 338 | /** 339 | * Fix the cursor style for Chrome's increment/decrement buttons. For certain 340 | * `font-size` values of the `input`, it causes the cursor style of the 341 | * decrement button to change from `default` to `text`. 342 | */ 343 | 344 | input[type="number"]::-webkit-inner-spin-button, 345 | input[type="number"]::-webkit-outer-spin-button { 346 | height: auto; 347 | } 348 | 349 | /** 350 | * 1. Address `appearance` set to `searchfield` in Safari and Chrome. 351 | * 2. Address `box-sizing` set to `border-box` in Safari and Chrome 352 | * (include `-moz` to future-proof). 353 | */ 354 | 355 | input[type="search"] { 356 | -webkit-appearance: textfield; /* 1 */ 357 | -moz-box-sizing: content-box; 358 | -webkit-box-sizing: content-box; /* 2 */ 359 | box-sizing: content-box; 360 | } 361 | 362 | /** 363 | * Remove inner padding and search cancel button in Safari and Chrome on OS X. 364 | * Safari (but not Chrome) clips the cancel button when the search input has 365 | * padding (and `textfield` appearance). 366 | */ 367 | 368 | input[type="search"]::-webkit-search-cancel-button, 369 | input[type="search"]::-webkit-search-decoration { 370 | -webkit-appearance: none; 371 | } 372 | 373 | /** 374 | * Define consistent border, margin, and padding. 375 | */ 376 | 377 | fieldset { 378 | border: 1px solid #c0c0c0; 379 | margin: 0 2px; 380 | padding: 0.35em 0.625em 0.75em; 381 | } 382 | 383 | /** 384 | * 1. Correct `color` not being inherited in IE 8/9/10/11. 385 | * 2. Remove padding so people aren't caught out if they zero out fieldsets. 386 | */ 387 | 388 | legend { 389 | border: 0; /* 1 */ 390 | padding: 0; /* 2 */ 391 | } 392 | 393 | /** 394 | * Remove default vertical scrollbar in IE 8/9/10/11. 395 | */ 396 | 397 | textarea { 398 | overflow: auto; 399 | } 400 | 401 | /** 402 | * Don't inherit the `font-weight` (applied by a rule above). 403 | * NOTE: the default cannot safely be changed in Chrome and Safari on OS X. 404 | */ 405 | 406 | optgroup { 407 | font-weight: bold; 408 | } 409 | 410 | /* Tables 411 | ========================================================================== */ 412 | 413 | /** 414 | * Remove most spacing between table cells. 415 | */ 416 | 417 | table { 418 | border-collapse: collapse; 419 | border-spacing: 0; 420 | } 421 | 422 | td, 423 | th { 424 | padding: 0; 425 | } 426 | 427 | 428 | /* Style */ 429 | 430 | body { 431 | font-size: 15px; 432 | font-family: Arial, Arial, Helvetica, sans-serif; 433 | line-height: 1.5; 434 | background: #D1D1D1; 435 | } 436 | 437 | a { 438 | color: #63a52a; 439 | text-decoration: none; 440 | transition: opacity ease-in-out 0.3s; 441 | -webkit-transition: opacity ease-in-out 0.3s; /* Safari <=6.1, Android <= 4.3 */ 442 | } 443 | 444 | a:hover { 445 | text-decoration: underline; 446 | color: #90D355; 447 | } 448 | 449 | h1.title { 450 | margin: 30px 20px 10px; 451 | font-size: 60px; 452 | font-weight: bold; 453 | font-style: italic; 454 | font-family:Georgia, serif; 455 | text-align: center; 456 | } 457 | 458 | .wrapper { 459 | width: 675px; 460 | margin: 0 auto; 461 | } 462 | 463 | #container { 464 | border: 1px solid #2a2a2a; 465 | background: #ddd url(../images/pattern.png); 466 | box-shadow: 0 0 5px #b1b1b1; 467 | } 468 | 469 | p.tagline { 470 | padding: 20px 20px 0; 471 | color: #fff; 472 | font-size: 17px; 473 | } 474 | 475 | #main { 476 | margin-top: 20px; 477 | padding: 0 20px 90px; 478 | background-color: #fff; 479 | } 480 | 481 | .download-bar { 482 | background: #222; 483 | border: 5px solid #444; 484 | padding: 10px; 485 | margin: 0 -35px 20px; 486 | position: relative; 487 | } 488 | 489 | .download-bar .inner { 490 | overflow: hidden; 491 | } 492 | 493 | .download-bar .watch-fork iframe { 494 | display: block; 495 | float: left; 496 | border-right: 1px solid #ddd; 497 | padding-right: 5px; 498 | } 499 | .download-bar .watch-fork iframe.last { 500 | border-right: 0 none; 501 | padding-right: 0; 502 | padding-left: 5px; 503 | border-left: 1px solid #fff; 504 | } 505 | .download-bar .watch-fork { 506 | overflow: hidden; 507 | float: right; 508 | background-color: #eee; 509 | padding: 5px; 510 | border-radius: 3px; 511 | } 512 | 513 | .download-bar .blc { 514 | border: 10px solid black; 515 | border-color: transparent transparent black; 516 | width: 0; 517 | height: 0; 518 | display: block; 519 | position: absolute; 520 | bottom: -15px; 521 | left: 0; 522 | transform: rotate(45deg); 523 | -ms-transform: rotate(45deg); /* IE9 */ 524 | -webkit-transform: rotate(45deg); /* 2014 current */ 525 | } 526 | 527 | .download-bar .trc { 528 | border: 10px solid black; 529 | border-color: black transparent transparent; 530 | width: 0; 531 | height: 0; 532 | display: block; 533 | position: absolute; 534 | top: -15px; 535 | right: 0; 536 | transform: rotate(45deg); 537 | -ms-transform: rotate(45deg); /* IE9 */ 538 | -webkit-transform: rotate(45deg); /* 2014 current */ 539 | } 540 | 541 | .download-bar .avatar { 542 | border: 1px solid black; 543 | display: block; 544 | padding: 4px; 545 | float: left; 546 | } 547 | 548 | .download-bar .avatar img { 549 | display: block; 550 | } 551 | 552 | .download-bar a.code { 553 | background: transparent url(../images/code.png) no-repeat 0 2px; 554 | padding-left: 35px; 555 | margin-top: 8px; 556 | display: block; 557 | float: left; 558 | text-indent: 0; 559 | width: auto; 560 | height: auto; 561 | opacity: 1; 562 | filter:alpha(opacity=100); /* IE 5-7 */ 563 | } 564 | 565 | .current-section { 566 | position: fixed; 567 | top: 0; 568 | left: 50%; 569 | width: 693px; 570 | margin-left: -352px; 571 | background: #222; 572 | border: 5px solid #444; 573 | color: #fff; 574 | opacity: 0; 575 | visibility: hidden; 576 | transition: opacity ease-in-out 0.3s; 577 | -webkit-transition: opacity ease-in-out 0.3s; /* Safari <=6.1, Android <= 4.3 */ 578 | } 579 | 580 | .current-section p { 581 | padding: 5px 27px; 582 | font-size: 24px; 583 | font-weight: bold; 584 | } 585 | 586 | .current-section a { 587 | float: right; 588 | text-indent: -10000px; 589 | background: transparent url(../images/top.png) no-repeat 0 0; 590 | width: 20px; 591 | height: 20px; 592 | opacity: 0.8; 593 | margin-right: 12px; 594 | margin-top: 12px; 595 | opacity: 0.8; 596 | filter:alpha(opacity=80); /* IE 5-7 */ 597 | transition: opacity ease-in-out 0.3s; 598 | -webkit-transition: opacity ease-in-out 0.3s; /* Safari <=6.1, Android <= 4.3 */ 599 | } 600 | 601 | .current-section a:hover { 602 | opacity: 1; 603 | filter:alpha(opacity=100); /* IE 5-7 */ 604 | } 605 | 606 | .current-section a.zip { 607 | margin-right: 8px; 608 | } 609 | 610 | a.zip, 611 | a.zip span { 612 | background: transparent url(../images/zip.png) no-repeat 0 0; 613 | width: 30px; 614 | height: 21px; 615 | display: inline-block; 616 | text-indent: -10000px; 617 | opacity: 0.8; 618 | filter:alpha(opacity=80); /* IE 5-7 */ 619 | transition: opacity ease-in-out 0.3s; 620 | -webkit-transition: opacity ease-in-out 0.3s; /* Safari <=6.1, Android <= 4.3 */ 621 | } 622 | 623 | a.tar, 624 | a.tar span { 625 | background: transparent url(../images/tar.png) no-repeat 0 0; 626 | width: 30px; 627 | height: 21px; 628 | display: inline-block; 629 | text-indent: -10000px; 630 | opacity: 0.8; 631 | filter:alpha(opacity=80); /* IE 5-7 */ 632 | transition: opacity ease-in-out 0.3s; 633 | -webkit-transition: opacity ease-in-out 0.3s; /* Safari <=6.1, Android <= 4.3 */ 634 | } 635 | 636 | a.code { 637 | background: transparent url(../images/code.png) no-repeat 0 2px; 638 | width: 30px; 639 | height: 21px; 640 | display: block; 641 | display: inline-block; 642 | text-indent: -10000px; 643 | opacity: 0.8; 644 | filter:alpha(opacity=80); /* IE 5-7 */ 645 | transition: opacity ease-in-out 0.3s; 646 | -webkit-transition: opacity ease-in-out 0.3s; /* Safari <=6.1, Android <= 4.3 */ 647 | } 648 | 649 | a.zip:hover, 650 | a.tar:hover, 651 | a.code:hover { 652 | opacity: 1; 653 | filter:alpha(opacity=100); 654 | } 655 | 656 | a.download-button { 657 | border: 1px solid black; 658 | border-radius: 3px; 659 | display: inline-block; 660 | text-indent: 0!important; 661 | width: auto; 662 | float: right; 663 | background: #999; /* for non-css3 browsers */ 664 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#37ADD4', endColorstr='#1B657E'); /* IE <= 9 */ 665 | background: -webkit-gradient(linear, left top, left bottom, from(#37ADD4), to(#1B657E)); /* ancient webkit browsers */ 666 | background: -webkit-linear-gradient(top, #37ADD4, #1B657E); /* Safari <=6.1, Android <= 4.3 */ 667 | background: linear-gradient(to bottom, #37ADD4, #1B657E); 668 | height: auto; 669 | margin-left: 10px; 670 | } 671 | 672 | a.download-button span { 673 | background-position: 10px 5px; 674 | width: auto; 675 | height: auto; 676 | padding: 5px 10px; 677 | padding-left: 45px; 678 | display: inline-block; 679 | text-indent: 0!important; 680 | color: #fff; 681 | } 682 | 683 | footer { 684 | margin-bottom: 60px; 685 | padding-bottom: 60px; 686 | } 687 | 688 | footer .owner { 689 | background: #222; 690 | border: 5px solid #444; 691 | padding: 5px 15px; 692 | margin: -67px -10px 35px; 693 | color: #d6d6d6; 694 | } 695 | 696 | footer .creds small { 697 | float: right; 698 | font-size: 10px; 699 | text-align: right; 700 | margin-left: 15px; 701 | } 702 | 703 | footer .owner .avatar { 704 | background-color: #666; 705 | display: block; 706 | margin: -19px 10px 0 0; 707 | width: 60px; 708 | float: left; 709 | } 710 | 711 | footer .owner img { 712 | display: block; 713 | border: 1px solid #2a2a2a; 714 | margin: 5px; 715 | } 716 | 717 | footer .owner p { 718 | font-family:Georgia, serif; 719 | } 720 | 721 | footer .owner p a { 722 | font-size: 16px; 723 | font-style: italic; 724 | } 725 | 726 | /* Markdown */ 727 | .markdown-body h1, 728 | .markdown-body h2, 729 | .markdown-body h3, 730 | .markdown-body h4, 731 | .markdown-body h5, 732 | .markdown-body h6, 733 | .markdown-body p, 734 | .markdown-body pre, 735 | .markdown-body ul, 736 | .markdown-body ol, 737 | .markdown-body dl, 738 | .markdown-body table, 739 | .markdown-body blockquote { 740 | margin-bottom: 20px; 741 | } 742 | 743 | .markdown-body h1, 744 | .markdown-body h2, 745 | .markdown-body h3, 746 | .markdown-body h4, 747 | .markdown-body h5, 748 | .markdown-body h6 { 749 | font-weight: bold; 750 | } 751 | 752 | .markdown-body h1 { 753 | font-size: 28px; 754 | } 755 | 756 | .markdown-body h2 { 757 | font-size: 24px; 758 | color: #557398; 759 | } 760 | 761 | .markdown-body h3 { 762 | font-size: 20px; 763 | } 764 | 765 | .markdown-body h4 { 766 | font-size: 18px; 767 | } 768 | 769 | .markdown-body h5 { 770 | font-size: 16px; 771 | } 772 | 773 | .markdown-body pre { 774 | padding: 10px 70px 10px 0; 775 | margin-left: -20px; 776 | margin-right: -20px; 777 | font-family: 'Monaco', 'Lucida Console', monospace; 778 | font-size: 13px; 779 | line-height: 20px; 780 | box-shadow: inset 0 0 5px #000; 781 | word-wrap: break-word; 782 | background-color:#3b3b3b; 783 | color: #d6d6d6; 784 | } 785 | 786 | .markdown-body pre.lines { 787 | font-size: 12px; 788 | margin:0 10px 0 -20px; 789 | padding: 10px; 790 | float: left; 791 | display: block; 792 | text-align: right; 793 | box-shadow: none; 794 | background-color:#2a2a2a; 795 | color: #d6d6d6; 796 | } 797 | 798 | .markdown-body ul, 799 | .markdown-body ol { 800 | padding-left: 30px; 801 | } 802 | 803 | .markdown-body ul { 804 | list-style-type: disc; 805 | } 806 | 807 | .markdown-body ol { 808 | list-style-type: decimal; 809 | } 810 | 811 | .markdown-body li, 812 | .markdown-body li p, 813 | .markdown-body dd, 814 | .markdown-body dd p { 815 | margin-bottom: 10px; 816 | } 817 | 818 | .markdown-body li pre, 819 | .markdown-body li pre.lines, 820 | .markdown-body dd pre, 821 | .markdown-body dd pre.lines { 822 | margin-left: -35px; 823 | } 824 | 825 | .markdown-body dt { 826 | font-weight: bold; 827 | font-style: italic; 828 | } 829 | 830 | .markdown-body dd { 831 | margin-left: 15px; 832 | } 833 | 834 | .markdown-body table { 835 | width: 673px; 836 | margin-left: -20px; 837 | margin-right: -20px; 838 | } 839 | 840 | .markdown-body tbody { 841 | border-top: 2px solid #557398; 842 | border-bottom: 2px solid #557398; 843 | background-color: #EBEFF4; 844 | } 845 | 846 | .markdown-body table td * { 847 | margin: 0; 848 | } 849 | 850 | .markdown-body td { 851 | border-right: 1px solid #557398; 852 | border-bottom: 1px solid #557398; 853 | padding: 5px; 854 | } 855 | 856 | .markdown-body td:first-child, 857 | .markdown-body th:first-child { 858 | width: 30%; 859 | padding-left: 20px; 860 | } 861 | 862 | .markdown-body td:last-child { 863 | border-right: 0 none; 864 | } 865 | 866 | .markdown-body th { 867 | font-size: 18px; 868 | font-weight: bold; 869 | text-align: left; 870 | padding: 5px; 871 | } 872 | 873 | .markdown-body tt { 874 | background-color:#3b3b3b; 875 | color: #d6d6d6; 876 | padding: 2px 3px; 877 | } 878 | 879 | .markdown-body blockquote { 880 | font-style: italic; 881 | font-family:Georgia, serif; 882 | font-size: 17px; 883 | border-top: 3px solid #333; 884 | border-bottom: 3px solid #333; 885 | padding: 10px 20px; 886 | padding-left: 50px; 887 | } 888 | 889 | .markdown-body blockquote:before { 890 | font-style: italic; 891 | font-family: Georgia, serif; 892 | font-size: 90px; 893 | height: 90px; 894 | margin-left: -60px; 895 | margin-top: -25px; 896 | content: "‟"; 897 | display: block; 898 | float: left; 899 | } 900 | 901 | .markdown-body img { 902 | max-width: 100%; 903 | box-sizing: border-box; 904 | } 905 | 906 | .highlight { background: #ffffff; } 907 | .highlight .c { color: #999988; font-style: italic } /* Comment */ 908 | .highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ 909 | .highlight .k { font-weight: bold } /* Keyword */ 910 | .highlight .o { font-weight: bold } /* Operator */ 911 | .highlight .cm { color: #999988; font-style: italic } /* Comment.Multiline */ 912 | .highlight .cp { color: #999999; font-weight: bold } /* Comment.Preproc */ 913 | .highlight .c1 { color: #999988; font-style: italic } /* Comment.Single */ 914 | .highlight .cs { color: #999999; font-weight: bold; font-style: italic } /* Comment.Special */ 915 | .highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ 916 | .highlight .gd .x { color: #000000; background-color: #ffaaaa } /* Generic.Deleted.Specific */ 917 | .highlight .ge { font-style: italic } /* Generic.Emph */ 918 | .highlight .gr { color: #aa0000 } /* Generic.Error */ 919 | .highlight .gh { color: #999999 } /* Generic.Heading */ 920 | .highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ 921 | .highlight .gi .x { color: #000000; background-color: #aaffaa } /* Generic.Inserted.Specific */ 922 | .highlight .go { color: #888888 } /* Generic.Output */ 923 | .highlight .gp { color: #555555 } /* Generic.Prompt */ 924 | .highlight .gs { font-weight: bold } /* Generic.Strong */ 925 | .highlight .gu { color: #800080; font-weight: bold; } /* Generic.Subheading */ 926 | .highlight .gt { color: #aa0000 } /* Generic.Traceback */ 927 | .highlight .kc { font-weight: bold } /* Keyword.Constant */ 928 | .highlight .kd { font-weight: bold } /* Keyword.Declaration */ 929 | .highlight .kn { font-weight: bold } /* Keyword.Namespace */ 930 | .highlight .kp { font-weight: bold } /* Keyword.Pseudo */ 931 | .highlight .kr { font-weight: bold } /* Keyword.Reserved */ 932 | .highlight .kt { color: #445588; font-weight: bold } /* Keyword.Type */ 933 | .highlight .m { color: #009999 } /* Literal.Number */ 934 | .highlight .s { color: #d14 } /* Literal.String */ 935 | .highlight .na { color: #008080 } /* Name.Attribute */ 936 | .highlight .nb { color: #0086B3 } /* Name.Builtin */ 937 | .highlight .nc { color: #445588; font-weight: bold } /* Name.Class */ 938 | .highlight .no { color: #008080 } /* Name.Constant */ 939 | .highlight .ni { color: #800080 } /* Name.Entity */ 940 | .highlight .ne { color: #990000; font-weight: bold } /* Name.Exception */ 941 | .highlight .nf { color: #990000; font-weight: bold } /* Name.Function */ 942 | .highlight .nn { color: #555555 } /* Name.Namespace */ 943 | .highlight .nt { color: #000080 } /* Name.Tag */ 944 | .highlight .nv { color: #008080 } /* Name.Variable */ 945 | .highlight .ow { font-weight: bold } /* Operator.Word */ 946 | .highlight .w { color: #bbbbbb } /* Text.Whitespace */ 947 | .highlight .mf { color: #009999 } /* Literal.Number.Float */ 948 | .highlight .mh { color: #009999 } /* Literal.Number.Hex */ 949 | .highlight .mi { color: #009999 } /* Literal.Number.Integer */ 950 | .highlight .mo { color: #009999 } /* Literal.Number.Oct */ 951 | .highlight .sb { color: #d14 } /* Literal.String.Backtick */ 952 | .highlight .sc { color: #d14 } /* Literal.String.Char */ 953 | .highlight .sd { color: #d14 } /* Literal.String.Doc */ 954 | .highlight .s2 { color: #d14 } /* Literal.String.Double */ 955 | .highlight .se { color: #d14 } /* Literal.String.Escape */ 956 | .highlight .sh { color: #d14 } /* Literal.String.Heredoc */ 957 | .highlight .si { color: #d14 } /* Literal.String.Interpol */ 958 | .highlight .sx { color: #d14 } /* Literal.String.Other */ 959 | .highlight .sr { color: #009926 } /* Literal.String.Regex */ 960 | .highlight .s1 { color: #d14 } /* Literal.String.Single */ 961 | .highlight .ss { color: #990073 } /* Literal.String.Symbol */ 962 | .highlight .bp { color: #999999 } /* Name.Builtin.Pseudo */ 963 | .highlight .vc { color: #008080 } /* Name.Variable.Class */ 964 | .highlight .vg { color: #008080 } /* Name.Variable.Global */ 965 | .highlight .vi { color: #008080 } /* Name.Variable.Instance */ 966 | .highlight .il { color: #009999 } /* Literal.Number.Integer.Long */ -------------------------------------------------------------------------------- /src/config/editor/css/zoom.css: -------------------------------------------------------------------------------- 1 | img[data-action="zoom"] { 2 | cursor: pointer; 3 | cursor: -webkit-zoom-in; 4 | cursor: -moz-zoom-in; 5 | } 6 | .zoom-img, 7 | .zoom-img-wrap { 8 | position: relative; 9 | z-index: 666; 10 | -webkit-transition: all 300ms; 11 | -o-transition: all 300ms; 12 | transition: all 300ms; 13 | } 14 | img.zoom-img { 15 | cursor: pointer; 16 | cursor: -webkit-zoom-out; 17 | cursor: -moz-zoom-out; 18 | } 19 | .zoom-overlay { 20 | z-index: 420; 21 | background: #fff; 22 | position: fixed; 23 | top: 0; 24 | left: 0; 25 | right: 0; 26 | bottom: 0; 27 | pointer-events: none; 28 | filter: "alpha(opacity=0)"; 29 | opacity: 0; 30 | -webkit-transition: opacity 300ms; 31 | -o-transition: opacity 300ms; 32 | transition: opacity 300ms; 33 | } 34 | .zoom-overlay-open .zoom-overlay { 35 | filter: "alpha(opacity=100)"; 36 | opacity: 1; 37 | } 38 | .zoom-overlay-open, 39 | .zoom-overlay-transitioning { 40 | cursor: default; 41 | } 42 | -------------------------------------------------------------------------------- /src/config/editor/images/code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/endachao/laravel-5-markdown-editor/420f93671d19b6edff7bd045ed728704c4e083c2/src/config/editor/images/code.png -------------------------------------------------------------------------------- /src/config/editor/images/editor@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/endachao/laravel-5-markdown-editor/420f93671d19b6edff7bd045ed728704c4e083c2/src/config/editor/images/editor@2x.png -------------------------------------------------------------------------------- /src/config/editor/images/loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/endachao/laravel-5-markdown-editor/420f93671d19b6edff7bd045ed728704c4e083c2/src/config/editor/images/loader.gif -------------------------------------------------------------------------------- /src/config/editor/images/pattern.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/endachao/laravel-5-markdown-editor/420f93671d19b6edff7bd045ed728704c4e083c2/src/config/editor/images/pattern.png -------------------------------------------------------------------------------- /src/config/editor/images/tar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/endachao/laravel-5-markdown-editor/420f93671d19b6edff7bd045ed728704c4e083c2/src/config/editor/images/tar.png -------------------------------------------------------------------------------- /src/config/editor/images/top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/endachao/laravel-5-markdown-editor/420f93671d19b6edff7bd045ed728704c4e083c2/src/config/editor/images/top.png -------------------------------------------------------------------------------- /src/config/editor/images/zip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/endachao/laravel-5-markdown-editor/420f93671d19b6edff7bd045ed728704c4e083c2/src/config/editor/images/zip.png -------------------------------------------------------------------------------- /src/config/editor/js/MIDI.js: -------------------------------------------------------------------------------- 1 | if(typeof MIDI==="undefined")var MIDI={};(function(){"use strict";var e={};var t=0;var n=function(n){t++;var r=new Audio;var i=n.split(";")[0];r.id="audio";r.setAttribute("preload","auto");r.setAttribute("audiobuffer",true);r.addEventListener("error",function(){e[i]=false;t--},false);r.addEventListener("canplaythrough",function(){e[i]=true;t--},false);r.src="data:"+n;document.body.appendChild(r)};MIDI.audioDetect=function(r){if(typeof Audio==="undefined")return r({});var i=new Audio;if(typeof i.canPlayType==="undefined")return r(e);var s=i.canPlayType('audio/ogg; codecs="vorbis"');s=s==="probably"||s==="maybe";var o=i.canPlayType("audio/mpeg");o=o==="probably"||o==="maybe";if(!s&&!o){r(e);return}if(s)n("audio/ogg;base64,T2dnUwACAAAAAAAAAADqnjMlAAAAAOyyzPIBHgF2b3JiaXMAAAAAAUAfAABAHwAAQB8AAEAfAACZAU9nZ1MAAAAAAAAAAAAA6p4zJQEAAAANJGeqCj3//////////5ADdm9yYmlzLQAAAFhpcGguT3JnIGxpYlZvcmJpcyBJIDIwMTAxMTAxIChTY2hhdWZlbnVnZ2V0KQAAAAABBXZvcmJpcw9CQ1YBAAABAAxSFCElGVNKYwiVUlIpBR1jUFtHHWPUOUYhZBBTiEkZpXtPKpVYSsgRUlgpRR1TTFNJlVKWKUUdYxRTSCFT1jFloXMUS4ZJCSVsTa50FkvomWOWMUYdY85aSp1j1jFFHWNSUkmhcxg6ZiVkFDpGxehifDA6laJCKL7H3lLpLYWKW4q91xpT6y2EGEtpwQhhc+211dxKasUYY4wxxsXiUyiC0JBVAAABAABABAFCQ1YBAAoAAMJQDEVRgNCQVQBABgCAABRFcRTHcRxHkiTLAkJDVgEAQAAAAgAAKI7hKJIjSZJkWZZlWZameZaouaov+64u667t6roOhIasBACAAAAYRqF1TCqDEEPKQ4QUY9AzoxBDDEzGHGNONKQMMogzxZAyiFssLqgQBKEhKwKAKAAAwBjEGGIMOeekZFIi55iUTkoDnaPUUcoolRRLjBmlEluJMYLOUeooZZRCjKXFjFKJscRUAABAgAMAQICFUGjIigAgCgCAMAYphZRCjCnmFHOIMeUcgwwxxiBkzinoGJNOSuWck85JiRhjzjEHlXNOSuekctBJyaQTAAAQ4AAAEGAhFBqyIgCIEwAwSJKmWZomipamiaJniqrqiaKqWp5nmp5pqqpnmqpqqqrrmqrqypbnmaZnmqrqmaaqiqbquqaquq6nqrZsuqoum65q267s+rZru77uqapsm6or66bqyrrqyrbuurbtS56nqqKquq5nqq6ruq5uq65r25pqyq6purJtuq4tu7Js664s67pmqq5suqotm64s667s2rYqy7ovuq5uq7Ks+6os+75s67ru2rrwi65r66os674qy74x27bwy7ouHJMnqqqnqq7rmarrqq5r26rr2rqmmq5suq4tm6or26os67Yry7aumaosm64r26bryrIqy77vyrJui67r66Ys67oqy8Lu6roxzLat+6Lr6roqy7qvyrKuu7ru+7JuC7umqrpuyrKvm7Ks+7auC8us27oxuq7vq7It/KosC7+u+8Iy6z5jdF1fV21ZGFbZ9n3d95Vj1nVhWW1b+V1bZ7y+bgy7bvzKrQvLstq2scy6rSyvrxvDLux8W/iVmqratum6um7Ksq/Lui60dd1XRtf1fdW2fV+VZd+3hV9pG8OwjK6r+6os68Jry8ov67qw7MIvLKttK7+r68ow27qw3L6wLL/uC8uq277v6rrStXVluX2fsSu38QsAABhwAAAIMKEMFBqyIgCIEwBAEHIOKQahYgpCCKGkEEIqFWNSMuakZM5JKaWUFEpJrWJMSuaclMwxKaGUlkopqYRSWiqlxBRKaS2l1mJKqcVQSmulpNZKSa2llGJMrcUYMSYlc05K5pyUklJrJZXWMucoZQ5K6iCklEoqraTUYuacpA46Kx2E1EoqMZWUYgupxFZKaq2kFGMrMdXUWo4hpRhLSrGVlFptMdXWWqs1YkxK5pyUzDkqJaXWSiqtZc5J6iC01DkoqaTUYiopxco5SR2ElDLIqJSUWiupxBJSia20FGMpqcXUYq4pxRZDSS2WlFosqcTWYoy1tVRTJ6XFklKMJZUYW6y5ttZqDKXEVkqLsaSUW2sx1xZjjqGkFksrsZWUWmy15dhayzW1VGNKrdYWY40x5ZRrrT2n1mJNMdXaWqy51ZZbzLXnTkprpZQWS0oxttZijTHmHEppraQUWykpxtZara3FXEMpsZXSWiypxNhirLXFVmNqrcYWW62ltVprrb3GVlsurdXcYqw9tZRrrLXmWFNtBQAADDgAAASYUAYKDVkJAEQBAADGMMYYhEYpx5yT0ijlnHNSKucghJBS5hyEEFLKnINQSkuZcxBKSSmUklJqrYVSUmqttQIAAAocAAACbNCUWByg0JCVAEAqAIDBcTRNFFXVdX1fsSxRVFXXlW3jVyxNFFVVdm1b+DVRVFXXtW3bFn5NFFVVdmXZtoWiqrqybduybgvDqKqua9uybeuorqvbuq3bui9UXVmWbVu3dR3XtnXd9nVd+Bmzbeu2buu+8CMMR9/4IeTj+3RCCAAAT3AAACqwYXWEk6KxwEJDVgIAGQAAgDFKGYUYM0gxphhjTDHGmAAAgAEHAIAAE8pAoSErAoAoAADAOeecc84555xzzjnnnHPOOeecc44xxhhjjDHGGGOMMcYYY4wxxhhjjDHGGGOMMcYYY0wAwE6EA8BOhIVQaMhKACAcAABACCEpKaWUUkoRU85BSSmllFKqFIOMSkoppZRSpBR1lFJKKaWUIqWgpJJSSimllElJKaWUUkoppYw6SimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaVUSimllFJKKaWUUkoppRQAYPLgAACVYOMMK0lnhaPBhYasBAByAwAAhRiDEEJpraRUUkolVc5BKCWUlEpKKZWUUqqYgxBKKqmlklJKKbXSQSihlFBKKSWUUkooJYQQSgmhlFRCK6mEUkoHoYQSQimhhFRKKSWUzkEoIYUOQkmllNRCSB10VFIpIZVSSiklpZQ6CKGUklJLLZVSWkqpdBJSKamV1FJqqbWSUgmhpFZKSSWl0lpJJbUSSkklpZRSSymFVFJJJYSSUioltZZaSqm11lJIqZWUUkqppdRSSiWlkEpKqZSSUmollZRSaiGVlEpJKaTUSimlpFRCSamlUlpKLbWUSkmptFRSSaWUlEpJKaVSSksppRJKSqmllFpJKYWSUkoplZJSSyW1VEoKJaWUUkmptJRSSymVklIBAEAHDgAAAUZUWoidZlx5BI4oZJiAAgAAQABAgAkgMEBQMApBgDACAQAAAADAAAAfAABHARAR0ZzBAUKCwgJDg8MDAAAAAAAAAAAAAACAT2dnUwAEAAAAAAAAAADqnjMlAgAAADzQPmcBAQA=");if(o)n("audio/mpeg;base64,/+MYxAAAAANIAUAAAASEEB/jwOFM/0MM/90b/+RhST//w4NFwOjf///PZu////9lns5GFDv//l9GlUIEEIAAAgIg8Ir/JGq3/+MYxDsLIj5QMYcoAP0dv9HIjUcH//yYSg+CIbkGP//8w0bLVjUP///3Z0x5QCAv/yLjwtGKTEFNRTMuOTeqqqqqqqqqqqqq/+MYxEkNmdJkUYc4AKqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq");var u=(new Date).getTime();var a=window.setInterval(function(){var n=(new Date).getTime();var i=n-u>5e3;if(!t||i){window.clearInterval(a);r(e)}},1)}})();if(typeof MIDI==="undefined")var MIDI={};if(typeof MIDI.Soundfont==="undefined")MIDI.Soundfont={};(function(){"use strict";var e=false;MIDI.loadPlugin=function(r){if(typeof r==="function")r={callback:r};var i=r.instruments||r.instrument||"acoustic_grand_piano";if(typeof i!=="object")i=[i];for(var s=0;sProcessing: "+(n/87*100>>0)+"%
"+l)}r.id=f;i[n]=r;if(i.length===t.length){while(i.length){r=i.pop();if(!r)continue;var c=MIDI.keyToNote[r.id];o[a+""+c]=r}s(e)}})};n.setVolume=function(e,t){s=t};n.programChange=function(e,t){MIDI.channels[e].instrument=t};n.noteOn=function(e,t,n,u){if(!MIDI.channels[e])return;var a=MIDI.channels[e].instrument;if(!o[a+""+t])return;if(u>0;var s=n[r%12]+i;MIDI.keyToNote[s]=r;MIDI.noteToKey[r]=s}})()})();if(typeof MIDI==="undefined")var MIDI={};if(typeof MIDI.Player==="undefined")MIDI.Player={};(function(){"use strict";var e=MIDI.Player;e.callback=undefined;e.currentTime=0;e.endTime=0;e.restart=0;e.playing=false;e.timeWarp=1;e.start=e.resume=function(){if(e.currentTime<-1)e.currentTime=-1;f(e.currentTime)};e.pause=function(){var t=e.restart;l();e.restart=t};e.stop=function(){l();e.restart=0;e.currentTime=0};e.addListener=function(e){s=e};e.removeListener=function(){s=undefined};e.clearAnimation=function(){if(e.interval){window.clearInterval(e.interval)}};e.setAnimation=function(t){var n=typeof t==="function"?t:t.callback;var r=t.interval||30;var s=0;var o=0;var u=0;e.clearAnimation();e.interval=window.setInterval(function(){if(e.endTime===0)return;if(e.playing){s=u===e.currentTime?o-(new Date).getTime():0;if(e.currentTime===0){s=0}else{s=e.currentTime-s}if(u!==e.currentTime){o=(new Date).getTime();u=e.currentTime}}else{s=e.currentTime}var t=e.endTime;var r=s/t;var a=s/1e3;var f=a/60;var l=a-f*60;var c=f*60+l;var h=t/1e3;if(h-c<-1)return;n({now:c,end:h,events:i})},r)};e.loadMidiFile=function(){e.replayer=new Replayer(MidiFile(e.currentData),e.timeWarp);e.data=e.replayer.getData();e.endTime=a()};e.loadFile=function(t,n){e.stop();if(t.indexOf("base64,")!==-1){var r=window.atob(t.split(",")[1]);e.currentData=r;e.loadMidiFile();if(n)n(r);return}var i=new XMLHttpRequest;i.open("GET",t);i.overrideMimeType("text/plain; charset=x-user-defined");i.onreadystatechange=function(){if(this.readyState===4&&this.status===200){var t=this.responseText||"";var r=[];var i=t.length;var s=String.fromCharCode;for(var o=0;o\r\n"+"Function IEBinaryToArray_ByteStr(Binary)\r\n"+" IEBinaryToArray_ByteStr = CStr(Binary)\r\n"+"End Function\r\n"+"Function IEBinaryToArray_ByteStr_Last(Binary)\r\n"+" Dim lastIndex\r\n"+" lastIndex = LenB(Binary)\r\n"+" if lastIndex mod 2 Then\r\n"+" IEBinaryToArray_ByteStr_Last = Chr( AscB( MidB( Binary, lastIndex, 1 ) ) )\r\n"+" Else\r\n"+" IEBinaryToArray_ByteStr_Last = "+'""'+"\r\n"+" End If\r\n"+"End Function\r\n"+"\r\n";document.write(IEBinaryToArray_ByteStr_Script);DOMLoader.sendRequest=function(e){function t(e){var t={};for(var n=0;n<256;n++){for(var r=0;r<256;r++){t[String.fromCharCode(n+r*256)]=String.fromCharCode(n)+String.fromCharCode(r)}}var i=IEBinaryToArray_ByteStr(e);var s=IEBinaryToArray_ByteStr_Last(e);return i.replace(/[\s\S]/g,function(e){return t[e]})+s}var n=XMLHttpRequest();n.open("GET",e.url,true);if(e.responseType)n.responseType=e.responseType;if(e.onerror)n.onerror=e.onerror;if(e.onprogress)n.onprogress=e.onprogress;n.onreadystatechange=function(r){if(n.readyState===4){if(n.status===200){n.responseText=t(n.responseBody)}else{n=false}if(e.onload)e.onload(n)}};n.setRequestHeader("Accept-Charset","x-user-defined");n.send(null);return n}}else{DOMLoader.sendRequest=function(e){var t=new XMLHttpRequest;t.open(e.data?"POST":"GET",e.url,true);if(t.overrideMimeType)t.overrideMimeType("text/plain; charset=x-user-defined");if(e.data)t.setRequestHeader("Content-type","application/x-www-form-urlencoded");if(e.responseType)t.responseType=e.responseType;if(e.onerror)t.onerror=e.onerror;if(e.onprogress)t.onprogress=e.onprogress;t.onreadystatechange=function(n){if(t.readyState===4){if(t.status!==200&&t.status!=304){if(e.onerror)e.onerror(n,false);return}if(e.onload){e.onload(t)}}};t.send(e.data);return t}}var Base64Binary={_keyStr:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",decodeArrayBuffer:function(e){var t=Math.ceil(3*e.length/4);var n=new ArrayBuffer(t);this.decode(e,n);return n},decode:function(e,t){var n=this._keyStr.indexOf(e.charAt(e.length-1));var r=this._keyStr.indexOf(e.charAt(e.length-1));var i=Math.ceil(3*e.length/4);if(n==64)i--;if(r==64)i--;var s;var o,u,a;var f,l,c,h;var p=0;var d=0;if(t)s=new Uint8Array(t);else s=new Uint8Array(i);e=e.replace(/[^A-Za-z0-9\+\/\=]/g,"");for(p=0;p>4;u=(l&15)<<4|c>>2;a=(c&3)<<6|h;s[p]=o;if(c!=64)s[p+1]=u;if(h!=64)s[p+2]=a}return s}} 2 | -------------------------------------------------------------------------------- /src/config/editor/js/bootstrap3-typeahead.js: -------------------------------------------------------------------------------- 1 | /* ============================================================= 2 | * bootstrap3-typeahead.js v3.1.0 3 | * https://github.com/bassjobsen/Bootstrap-3-Typeahead 4 | * ============================================================= 5 | * Original written by @mdo and @fat 6 | * ============================================================= 7 | * Copyright 2014 Bass Jobsen @bassjobsen 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the 'License'); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | * 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an 'AS IS' BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | * ============================================================ */ 21 | 22 | 23 | (function (root, factory) { 24 | 25 | 'use strict'; 26 | 27 | // CommonJS module is defined 28 | if (typeof module !== 'undefined' && module.exports) { 29 | module.exports = factory(require('jquery')); 30 | } 31 | // AMD module is defined 32 | else if (typeof define === 'function' && define.amd) { 33 | define(['jquery'], function ($) { 34 | return factory ($); 35 | }); 36 | } else { 37 | factory(root.jQuery); 38 | } 39 | 40 | }(this, function ($) { 41 | 42 | 'use strict'; 43 | // jshint laxcomma: true 44 | 45 | 46 | /* TYPEAHEAD PUBLIC CLASS DEFINITION 47 | * ================================= */ 48 | 49 | var Typeahead = function (element, options) { 50 | this.$element = $(element); 51 | this.options = $.extend({}, $.fn.typeahead.defaults, options); 52 | this.matcher = this.options.matcher || this.matcher; 53 | this.sorter = this.options.sorter || this.sorter; 54 | this.select = this.options.select || this.select; 55 | this.autoSelect = typeof this.options.autoSelect == 'boolean' ? this.options.autoSelect : true; 56 | this.highlighter = this.options.highlighter || this.highlighter; 57 | this.render = this.options.render || this.render; 58 | this.updater = this.options.updater || this.updater; 59 | this.displayText = this.options.displayText || this.displayText; 60 | this.source = this.options.source; 61 | this.delay = this.options.delay; 62 | this.$menu = $(this.options.menu); 63 | this.$appendTo = this.options.appendTo ? $(this.options.appendTo) : null; 64 | this.shown = false; 65 | this.listen(); 66 | this.showHintOnFocus = typeof this.options.showHintOnFocus == 'boolean' ? this.options.showHintOnFocus : false; 67 | this.afterSelect = this.options.afterSelect; 68 | this.addItem = false; 69 | }; 70 | 71 | Typeahead.prototype = { 72 | 73 | constructor: Typeahead, 74 | 75 | select: function () { 76 | var val = this.$menu.find('.active').data('value'); 77 | this.$element.data('active', val); 78 | if(this.autoSelect || val) { 79 | var newVal = this.updater(val); 80 | // Updater can be set to any random functions via "options" parameter in constructor above. 81 | // Add null check for cases when updater returns void or undefined. 82 | if (!newVal) { 83 | newVal = ""; 84 | } 85 | this.$element 86 | .val(this.displayText(newVal) || newVal) 87 | .change(); 88 | this.afterSelect(newVal); 89 | } 90 | return this.hide(); 91 | }, 92 | 93 | updater: function (item) { 94 | return item; 95 | }, 96 | 97 | setSource: function (source) { 98 | this.source = source; 99 | }, 100 | 101 | show: function () { 102 | var pos = $.extend({}, this.$element.position(), { 103 | height: this.$element[0].offsetHeight 104 | }), scrollHeight; 105 | 106 | scrollHeight = typeof this.options.scrollHeight == 'function' ? 107 | this.options.scrollHeight.call() : 108 | this.options.scrollHeight; 109 | 110 | var element; 111 | if (this.shown) { 112 | element = this.$menu; 113 | } else if (this.$appendTo) { 114 | element = this.$menu.appendTo(this.$appendTo); 115 | } else { 116 | element = this.$menu.insertAfter(this.$element); 117 | } 118 | element.css({ 119 | top: pos.top + pos.height + scrollHeight 120 | , left: pos.left 121 | }) 122 | .show(); 123 | 124 | this.shown = true; 125 | return this; 126 | }, 127 | 128 | hide: function () { 129 | this.$menu.hide(); 130 | this.shown = false; 131 | return this; 132 | }, 133 | 134 | lookup: function (query) { 135 | var items; 136 | if (typeof(query) != 'undefined' && query !== null) { 137 | this.query = query; 138 | } else { 139 | this.query = this.$element.val() || ''; 140 | } 141 | 142 | if (this.query.length < this.options.minLength && !this.options.showHintOnFocus) { 143 | return this.shown ? this.hide() : this; 144 | } 145 | 146 | var worker = $.proxy(function() { 147 | 148 | if($.isFunction(this.source)) this.source(this.query, $.proxy(this.process, this)); 149 | else if (this.source) { 150 | this.process(this.source); 151 | } 152 | }, this); 153 | 154 | clearTimeout(this.lookupWorker); 155 | this.lookupWorker = setTimeout(worker, this.delay); 156 | }, 157 | 158 | process: function (items) { 159 | var that = this; 160 | 161 | items = $.grep(items, function (item) { 162 | return that.matcher(item); 163 | }); 164 | 165 | items = this.sorter(items); 166 | 167 | if (!items.length && !this.options.addItem) { 168 | return this.shown ? this.hide() : this; 169 | } 170 | 171 | if (items.length > 0) { 172 | this.$element.data('active', items[0]); 173 | } else { 174 | this.$element.data('active', null); 175 | } 176 | 177 | // Add item 178 | if (this.options.addItem){ 179 | items.push(this.options.addItem); 180 | } 181 | 182 | if (this.options.items == 'all') { 183 | return this.render(items).show(); 184 | } else { 185 | return this.render(items.slice(0, this.options.items)).show(); 186 | } 187 | }, 188 | 189 | matcher: function (item) { 190 | var it = this.displayText(item); 191 | return ~it.toLowerCase().indexOf(this.query.toLowerCase()); 192 | }, 193 | 194 | sorter: function (items) { 195 | var beginswith = [] 196 | , caseSensitive = [] 197 | , caseInsensitive = [] 198 | , item; 199 | 200 | while ((item = items.shift())) { 201 | var it = this.displayText(item); 202 | if (!it.toLowerCase().indexOf(this.query.toLowerCase())) beginswith.push(item); 203 | else if (~it.indexOf(this.query)) caseSensitive.push(item); 204 | else caseInsensitive.push(item); 205 | } 206 | 207 | return beginswith.concat(caseSensitive, caseInsensitive); 208 | }, 209 | 210 | highlighter: function (item) { 211 | var html = $('
'); 212 | var query = this.query; 213 | var i = item.toLowerCase().indexOf(query.toLowerCase()); 214 | var len, leftPart, middlePart, rightPart, strong; 215 | len = query.length; 216 | if(len === 0){ 217 | return html.text(item).html(); 218 | } 219 | while (i > -1) { 220 | leftPart = item.substr(0, i); 221 | middlePart = item.substr(i, len); 222 | rightPart = item.substr(i + len); 223 | strong = $('').text(middlePart); 224 | html 225 | .append(document.createTextNode(leftPart)) 226 | .append(strong); 227 | item = rightPart; 228 | i = item.toLowerCase().indexOf(query.toLowerCase()); 229 | } 230 | return html.append(document.createTextNode(item)).html(); 231 | }, 232 | 233 | render: function (items) { 234 | var that = this; 235 | var self = this; 236 | var activeFound = false; 237 | var data = []; 238 | var _category = that.options.separator; 239 | 240 | $.each(items, function (key,value) { 241 | // inject separator 242 | if (key > 0 && value[_category] !== items[key - 1][_category]){ 243 | data.push({ 244 | __type: 'divider' 245 | }); 246 | } 247 | 248 | // inject category header 249 | if (value[_category] && (key === 0 || value[_category] !== items[key - 1][_category])){ 250 | data.push({ 251 | __type: 'category', 252 | name: value[_category] 253 | }); 254 | } 255 | data.push(value); 256 | }); 257 | 258 | items = $(data).map(function (i, item) { 259 | 260 | if ((item.__type || false) == 'category'){ 261 | return $(that.options.headerHtml).text(item.name)[0]; 262 | } 263 | 264 | if ((item.__type || false) == 'divider'){ 265 | return $(that.options.headerDivider)[0]; 266 | } 267 | 268 | var text = self.displayText(item); 269 | i = $(that.options.item).data('value', item); 270 | i.find('a').html(that.highlighter(text, item)); 271 | if (text == self.$element.val()) { 272 | i.addClass('active'); 273 | self.$element.data('active', item); 274 | activeFound = true; 275 | } 276 | return i[0]; 277 | }); 278 | 279 | if (this.autoSelect && !activeFound) { 280 | items.filter(':not(.dropdown-header)').first().addClass('active'); 281 | this.$element.data('active', items.first().data('value')); 282 | } 283 | this.$menu.html(items); 284 | return this; 285 | }, 286 | 287 | displayText: function(item) { 288 | return typeof item !== 'undefined' && typeof item.name != 'undefined' && item.name || item; 289 | }, 290 | 291 | next: function (event) { 292 | var active = this.$menu.find('.active').removeClass('active') 293 | , next = active.next(); 294 | 295 | if (!next.length) { 296 | next = $(this.$menu.find('li')[0]); 297 | } 298 | 299 | next.addClass('active'); 300 | }, 301 | 302 | prev: function (event) { 303 | var active = this.$menu.find('.active').removeClass('active') 304 | , prev = active.prev(); 305 | 306 | if (!prev.length) { 307 | prev = this.$menu.find('li').last(); 308 | } 309 | 310 | prev.addClass('active'); 311 | }, 312 | 313 | listen: function () { 314 | this.$element 315 | .on('focus', $.proxy(this.focus, this)) 316 | .on('blur', $.proxy(this.blur, this)) 317 | .on('keypress', $.proxy(this.keypress, this)) 318 | .on('input', $.proxy(this.input, this)) 319 | .on('keyup', $.proxy(this.keyup, this)); 320 | 321 | if (this.eventSupported('keydown')) { 322 | this.$element.on('keydown', $.proxy(this.keydown, this)); 323 | } 324 | 325 | this.$menu 326 | .on('click', $.proxy(this.click, this)) 327 | .on('mouseenter', 'li', $.proxy(this.mouseenter, this)) 328 | .on('mouseleave', 'li', $.proxy(this.mouseleave, this)) 329 | .on('mousedown', $.proxy(this.mousedown,this)); 330 | }, 331 | 332 | mousedown: function(e) { 333 | this.mouseddown=true; 334 | e.stopPropagation(); 335 | e.preventDefault(); 336 | }, 337 | 338 | destroy : function () { 339 | this.$element.data('typeahead',null); 340 | this.$element.data('active',null); 341 | this.$element 342 | .off('focus') 343 | .off('blur') 344 | .off('keypress') 345 | .off('input') 346 | .off('keyup'); 347 | 348 | if (this.eventSupported('keydown')) { 349 | this.$element.off('keydown'); 350 | } 351 | 352 | this.$menu.remove(); 353 | }, 354 | 355 | eventSupported: function(eventName) { 356 | var isSupported = eventName in this.$element; 357 | if (!isSupported) { 358 | this.$element.setAttribute(eventName, 'return;'); 359 | isSupported = typeof this.$element[eventName] === 'function'; 360 | } 361 | return isSupported; 362 | }, 363 | 364 | move: function (e) { 365 | if (!this.shown) return; 366 | 367 | switch(e.keyCode) { 368 | case 9: // tab 369 | case 13: // enter 370 | case 27: // escape 371 | e.preventDefault(); 372 | break; 373 | 374 | case 38: // up arrow 375 | // with the shiftKey (this is actually the left parenthesis) 376 | if (e.shiftKey) return; 377 | e.preventDefault(); 378 | this.prev(); 379 | break; 380 | 381 | case 40: // down arrow 382 | // with the shiftKey (this is actually the right parenthesis) 383 | if (e.shiftKey) return; 384 | e.preventDefault(); 385 | this.next(); 386 | break; 387 | } 388 | }, 389 | 390 | keydown: function (e) { 391 | this.suppressKeyPressRepeat = ~$.inArray(e.keyCode, [40,38,9,13,27]); 392 | if (!this.shown && e.keyCode == 40) { 393 | this.lookup(); 394 | } else { 395 | this.move(e); 396 | } 397 | }, 398 | 399 | keypress: function (e) { 400 | if (this.suppressKeyPressRepeat) return; 401 | this.move(e); 402 | }, 403 | 404 | input: function (e) { 405 | this.lookup(); 406 | e.preventDefault(); 407 | }, 408 | 409 | keyup: function (e) { 410 | switch(e.keyCode) { 411 | case 40: // down arrow 412 | case 38: // up arrow 413 | case 16: // shift 414 | case 17: // ctrl 415 | case 18: // alt 416 | break; 417 | 418 | case 9: // tab 419 | case 13: // enter 420 | if (!this.shown) return; 421 | this.select(); 422 | break; 423 | 424 | case 27: // escape 425 | if (!this.shown) return; 426 | this.hide(); 427 | break; 428 | } 429 | 430 | e.preventDefault(); 431 | }, 432 | 433 | focus: function (e) { 434 | if (!this.focused) { 435 | this.focused = true; 436 | if (this.options.showHintOnFocus) { 437 | this.lookup(); 438 | } 439 | } 440 | }, 441 | 442 | blur: function (e) { 443 | this.focused = false; 444 | if (!this.mousedover && this.shown) { 445 | if(this.mouseddown && e.originalEvent){ 446 | this.mouseddown=false; 447 | }else{ 448 | this.hide(); 449 | } 450 | 451 | } 452 | 453 | }, 454 | 455 | click: function (e) { 456 | e.preventDefault(); 457 | this.select(); 458 | this.$element.focus(); 459 | this.hide(); 460 | }, 461 | 462 | mouseenter: function (e) { 463 | this.mousedover = true; 464 | this.$menu.find('.active').removeClass('active'); 465 | $(e.currentTarget).addClass('active'); 466 | }, 467 | 468 | mouseleave: function (e) { 469 | this.mousedover = false; 470 | /*if (!this.focused && this.shown) this.hide();*/ 471 | } 472 | 473 | }; 474 | 475 | 476 | /* TYPEAHEAD PLUGIN DEFINITION 477 | * =========================== */ 478 | 479 | var old = $.fn.typeahead; 480 | 481 | $.fn.typeahead = function (option) { 482 | var arg = arguments; 483 | if (typeof option == 'string' && option == 'getActive') { 484 | return this.data('active'); 485 | } 486 | return this.each(function () { 487 | var $this = $(this) 488 | , data = $this.data('typeahead') 489 | , options = typeof option == 'object' && option; 490 | if (!data) $this.data('typeahead', (data = new Typeahead(this, options))); 491 | if (typeof option == 'string' && data[option]) { 492 | if (arg.length > 1) { 493 | data[option].apply(data, Array.prototype.slice.call(arg ,1)); 494 | } else { 495 | data[option](); 496 | } 497 | } 498 | }); 499 | }; 500 | 501 | $.fn.typeahead.defaults = { 502 | source: [], 503 | items: 8, 504 | menu: '', 505 | item: '
  • ', 506 | minLength: 1, 507 | scrollHeight: 0, 508 | autoSelect: true, 509 | afterSelect: $.noop, 510 | addItem: false, 511 | delay: 0, 512 | separator: 'category', 513 | headerHtml: '', 514 | headerDivider: '' 515 | }; 516 | 517 | $.fn.typeahead.Constructor = Typeahead; 518 | 519 | 520 | /* TYPEAHEAD NO CONFLICT 521 | * =================== */ 522 | 523 | $.fn.typeahead.noConflict = function () { 524 | $.fn.typeahead = old; 525 | return this; 526 | }; 527 | 528 | 529 | /* TYPEAHEAD DATA-API 530 | * ================== */ 531 | 532 | $(document).on('focus.typeahead.data-api', '[data-provide="typeahead"]', function (e) { 533 | var $this = $(this); 534 | if ($this.data('typeahead')) return; 535 | $this.typeahead($this.data()); 536 | }); 537 | 538 | })); 539 | 540 | -------------------------------------------------------------------------------- /src/config/editor/js/fileupload.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery HTML5 File Upload 3 | * 4 | * Author: timdream at gmail.com 5 | * Web: http://timc.idv.tw/html5-file-upload/ 6 | * 7 | * Ajax File Upload that use real xhr, 8 | * built with getAsBinary, sendAsBinary, FormData, FileReader, ArrayBuffer, BlobBuilder and etc. 9 | * works in Firefox 3, Chrome 5, Safari 5 and higher 10 | * 11 | * Image resizing and uploading currently works in Fx 3 and up, and Chrome 9 (dev) and up only. 12 | * Extra settings will allow current Webkit users to upload the original image 13 | * or send the resized image in base64 form. 14 | * 15 | * Usage: 16 | * $.fileUploadSupported // a boolean value indicates if the browser is supported. 17 | * $.imageUploadSupported // a boolean value indicates if the browser could resize image and upload in binary form. 18 | * $.fileUploadAsBase64Supported // a boolean value indicate if the browser upload files in based64. 19 | * $.imageUploadAsBase64Supported // a boolean value indicate if the browser could resize image and upload in based64. 20 | * $('input[type=file]').fileUpload(ajaxSettings); //Make a input[type=file] select-and-send file upload widget 21 | * $('#any-element').fileUpload(ajaxSettings); //Make a element receive dropped file 22 | * //TBD $('form#fileupload').fileUpload(ajaxSettings); //Send a ajax form with file 23 | * //TBD $('canvas').fileUpload(ajaxSettings); //Upload given canvas as if it's an png image. 24 | * 25 | * ajaxSettings is the object contains $.ajax settings that will be passed to. 26 | * Available extended settings are: 27 | * fileType: 28 | * regexp check against filename extension; You should always checked it again on server-side. 29 | * e.g. /^(gif|jpe?g|png|tiff?)$/i for images 30 | * fileMaxSize: 31 | * Maxium file size allowed in bytes. Use scientific notation for converience. 32 | * e.g. 1E4 for 1KB, 1E8 for 1MB, 1E9 for 10MB. 33 | * If you really care the difference between 1024 and 1000, use Math.pow(2, 10) 34 | * fileError(info, textStatus, textDescription): 35 | * callback function when there is any error preventing file upload to start, 36 | * $.ajax and ajax events won't be called when error. 37 | * Use $.noop to overwrite default alert function. 38 | * imageMaxWidth, imageMaxHeight: 39 | * Use any of the two settings to enable client-size image resizing. 40 | * Image will be resized to fit into given rectangle. 41 | * File size and type limit checking will be ignored. 42 | * allowUploadOriginalImage: 43 | * Set to true if you accept original image to be uploaded as a fallback 44 | * when image resizing functionality is not available (such as Webkit browsers). 45 | * File size and type limit will be enforced. 46 | * allowDataInBase64: 47 | * Alternatively, you may wish to resize the image anyway and send the data 48 | * in base64. The data will be 133% larger and you will need to process it further with 49 | * server-side script. 50 | * This setting might work with browsers which could read file but cannot send it in original 51 | * binary (no known browser are designed this way though) 52 | * forceResize: 53 | * Set to true will cause the image being re-sampled even if the resized image 54 | * has the same demension as the original one. 55 | * imageType: 56 | * Acceptable values are: 'jpeg', 'png', or 'auto'. 57 | * 58 | * TBD: 59 | * ability to change settings after binding (you can unbind and bind again as a workaround) 60 | * multipole file handling 61 | * form intergation 62 | * 63 | */ 64 | 65 | (function() { 66 | // Don't do logging if window.log function does not exist. 67 | var log = window.log || $.noop; 68 | 69 | // jQuery.ajax config 70 | var config = { 71 | fileError: function (info, textStatus, textDescription) { 72 | window.alert(textDescription); 73 | } 74 | }; 75 | 76 | // Feature detection 77 | 78 | // Read as binary string: FileReader API || Gecko-specific function (Fx3) 79 | var canReadAsBinaryString = (window.FileReader || (window.File && window.File.prototype.getAsBinary)); 80 | // Read file using FormData interface 81 | var canReadFormData = !!(window.FormData); 82 | // Read file into data: URL: FileReader API || Gecko-specific function (Fx3) 83 | var canReadAsBase64 = (window.FileReader || (window.File && window.File.prototype.getAsDataURL)); 84 | 85 | var canResizeImageToBase64 = !!(document.createElement('canvas').toDataURL); 86 | var canResizeImageToBinaryString = canResizeImageToBase64 && window.atob; 87 | var canResizeImageToFile = !!(document.createElement('canvas').mozGetAsFile); 88 | 89 | // Send file in multipart/form-data with binary xhr (Gecko-specific function) 90 | // || xhr.send(blob) that sends blob made with ArrayBuffer. 91 | var canSendBinaryString = ( 92 | (window.XMLHttpRequest && window.XMLHttpRequest.prototype.sendAsBinary) 93 | || (window.Blob && window.Uint8Array && window.ProgressEvent) 94 | || (window.ArrayBuffer && window.BlobBuilder) 95 | ); 96 | // Send file as in FormData object 97 | var canSendFormData = !!(window.FormData); 98 | // Send image base64 data by extracting data: URL 99 | var canSendImageInBase64 = !!(document.createElement('canvas').toDataURL); 100 | 101 | var isSupported = ( 102 | (canReadAsBinaryString && canSendBinaryString) 103 | || (canReadFormData && canSendFormData) 104 | ); 105 | var isImageSupported = ( 106 | canReadAsBase64 && ( 107 | (canResizeImageToBinaryString && canSendBinaryString) 108 | || (canResizeImageToFile && canSendFormData) 109 | ) 110 | ); 111 | var isSupportedInBase64 = canReadAsBase64; 112 | var isImageSupportedInBase64 = canReadAsBase64 && canResizeImageToBase64; 113 | 114 | var dataURLtoBase64 = function (dataurl) { 115 | return dataurl.substring(dataurl.indexOf(',')+1, dataurl.length); 116 | } 117 | 118 | // Step 1: check file info and attempt to read the file 119 | // paramaters: Ajax settings, File object 120 | var handleFile = function (settings, file) { 121 | var info = { 122 | // properties of standard File object || Gecko 1.9 properties 123 | type: file.type || '', // MIME type 124 | size: file.size || file.fileSize, 125 | name: file.name || file.fileName 126 | }; 127 | 128 | // settings.resizeImage = !!(settings.imageMaxWidth || settings.imageMaxHeight); 129 | 130 | if (settings.resizeImage && !isImageSupported && settings.allowUploadOriginalImage) { 131 | log('WARN: Fall back to upload original un-resized image.'); 132 | settings.resizeImage = false; 133 | } 134 | 135 | /* 136 | if (settings.resizeImage) { 137 | settings.imageMaxWidth = settings.imageMaxWidth || Infinity; 138 | settings.imageMaxHeight = settings.imageMaxHeight || Infinity; 139 | } 140 | */ 141 | 142 | if (!settings.resizeImage) { 143 | if (settings.fileType && settings.fileType.test) { 144 | // Not using MIME types 145 | if (!settings.fileType.test(info.name.substr(info.name.lastIndexOf('.')+1))) { 146 | log('ERROR: Invalid Filetype.'); 147 | settings.fileError.call(this, info, 'INVALID_FILETYPE', 'Invalid filetype.'); 148 | return; 149 | } 150 | } 151 | 152 | if (settings.fileMaxSize && file.size > settings.fileMaxSize) { 153 | log('ERROR: File exceeds size limit.'); 154 | settings.fileError.call(this, info, 'FILE_EXCEEDS_SIZE_LIMIT', 'File exceeds size limit.'); 155 | return; 156 | } 157 | } 158 | 159 | if (!settings.resizeImage && canReadFormData) { 160 | log('INFO: Bypass file reading, insert file object into FormData object directly.'); 161 | handleForm(settings, 'file', file, info); 162 | } else if (window.FileReader) { 163 | log('INFO: Using FileReader to do asynchronously file reading.'); 164 | var reader = new FileReader(); 165 | reader.onerror = function (ev) { 166 | if (ev.target.error) { 167 | switch (ev.target.error) { 168 | case 8: 169 | log('ERROR: File not found.'); 170 | settings.fileError.call(this, info, 'FILE_NOT_FOUND', 'File not found.'); 171 | break; 172 | case 24: 173 | log('ERROR: File not readable.'); 174 | settings.fileError.call(this, info, 'IO_ERROR', 'File not readable.'); 175 | break; 176 | case 18: 177 | log('ERROR: File cannot be access due to security constrant.'); 178 | settings.fileError.call(this, info, 'SECURITY_ERROR', 'File cannot be access due to security constrant.'); 179 | break; 180 | case 20: //User Abort 181 | break; 182 | } 183 | } 184 | } 185 | if (!settings.resizeImage) { 186 | if (canSendBinaryString) { 187 | reader.onloadend = function (ev) { 188 | var bin = ev.target.result; 189 | handleForm(settings, 'bin', bin, info); 190 | }; 191 | reader.readAsBinaryString(file); 192 | } else if (settings.allowDataInBase64) { 193 | reader.onloadend = function (ev) { 194 | handleForm( 195 | settings, 196 | 'base64', 197 | dataURLtoBase64(ev.target.result), 198 | info 199 | ); 200 | }; 201 | reader.readAsDataURL(file); 202 | } else { 203 | log('ERROR: No available method to extract file; allowDataInBase64 not set.'); 204 | settings.fileError.call(this, info, 'NO_BIN_SUPPORT_AND_BASE64_NOT_SET', 'No available method to extract file; allowDataInBase64 not set.'); 205 | } 206 | } else { 207 | reader.onloadend = function (ev) { 208 | var dataurl = ev.target.result; 209 | handleImage(settings, dataurl, info, file); 210 | }; 211 | reader.readAsDataURL(file); 212 | } 213 | } else if (window.File && window.File.prototype.getAsBinary) { 214 | log('WARN: FileReader does not exist, UI will be blocked when reading big file.'); 215 | if (!settings.resizeImage) { 216 | try { 217 | var bin = file.getAsBinary(); 218 | } catch (e) { 219 | log('ERROR: File not readable.'); 220 | settings.fileError.call(this, info, 'IO_ERROR', 'File not readable.'); 221 | return; 222 | } 223 | handleForm(settings, 'bin', bin, info); 224 | } else { 225 | try { 226 | var bin = file.getAsDataURL(); 227 | } catch (e) { 228 | log('ERROR: File not readable.'); 229 | settings.fileError.call(this, info, 'IO_ERROR', 'File not readable.'); 230 | return; 231 | } 232 | handleImage(settings, dataurl, info, file); 233 | } 234 | } else { 235 | // log('ERROR: No available method to extract file; this browser is not supported.'); 236 | if (settings.fallback) { 237 | settings.fallback(); 238 | } else { 239 | settings.fileError.call(this, info, 'NOT_SUPPORT', 'ERROR: No available method to extract file; this browser is not supported.'); 240 | } 241 | } 242 | }; 243 | 244 | // step 1.5: inject file into , paste the pixels into , 245 | // read the final image 246 | var handleImage = function (settings, dataurl, info, file) { 247 | var img = new Image(); 248 | img.onerror = function () { 249 | log('ERROR: failed to load, file is not a supported image format.'); 250 | settings.fileError.call(this, info, 'FILE_NOT_IMAGE', 'File is not a supported image format.'); 251 | }; 252 | img.onload = function () { 253 | 254 | /* 255 | var ratio = Math.max( 256 | img.width/settings.imageMaxWidth, 257 | img.height/settings.imageMaxHeight, 258 | 1 259 | ); 260 | var d = { 261 | w: Math.floor(Math.max(img.width/ratio, 1)), 262 | h: Math.floor(Math.max(img.height/ratio, 1)) 263 | } 264 | log( 265 | 'INFO: Original image size: ' + img.width.toString(10) + 'x' + img.height.toString(10) 266 | + ', resized image size: ' + d.w + 'x' + d.h + '.' 267 | ); 268 | 269 | if (!settings.forceResize && img.width === d.w && img.height === d.h) { 270 | log('INFO: Image demension is the same, send the original file.'); 271 | if (canResizeImageToBinaryString) { 272 | handleForm( 273 | settings, 274 | 'bin', 275 | window.atob(dataURLtoBase64(dataurl)), 276 | info 277 | ); 278 | } else if (settings.allowDataInBase64) { 279 | handleForm( 280 | settings, 281 | 'base64', 282 | dataURLtoBase64(dataurl), 283 | info 284 | ); 285 | } else { 286 | log('ERROR: No available method to send the original file; allowDataInBase64 not set.'); 287 | settings.fileError.call(this, info, 'NO_BIN_SUPPORT_AND_BASE64_NOT_SET', 'No available method to extract file; allowDataInBase64 not set.'); 288 | } 289 | return; 290 | } 291 | */ 292 | 293 | var canvas = document.createElement('canvas'); 294 | 295 | /* 296 | canvas.setAttribute('width', d.w); 297 | canvas.setAttribute('height', d.h); 298 | canvas.getContext('2d').drawImage( 299 | img, 300 | 0, 301 | 0, 302 | img.width, 303 | img.height, 304 | 0, 305 | 0, 306 | d.w, 307 | d.h 308 | ); 309 | */ 310 | 311 | var cb = function (canvas) { 312 | if (!settings.imageType || settings.imageType === 'auto') { 313 | if (info.type === 'image/jpeg') settings.imageType = 'jpeg'; 314 | else settings.imageType = 'png'; 315 | } 316 | 317 | var ninfo = { 318 | type: 'image/' + settings.imageType, 319 | name: info.name.substr(0, info.name.indexOf('.')) + '.resized.' + settings.imageType 320 | }; 321 | 322 | if (canResizeImageToFile && canSendFormData) { 323 | // Gecko 2 (Fx4) non-standard function 324 | var nfile = canvas.mozGetAsFile( 325 | ninfo.name, 326 | 'image/' + settings.imageType 327 | ); 328 | ninfo.size = file.size || file.fileSize; 329 | handleForm( 330 | settings, 331 | 'file', 332 | nfile, 333 | ninfo 334 | ); 335 | } else if (canResizeImageToBinaryString && canSendBinaryString) { 336 | // Read the image as DataURL, convert it back to binary string. 337 | var bin = window.atob(dataURLtoBase64(canvas.toDataURL('image/' + settings.imageType))); 338 | ninfo.size = bin.length; 339 | handleForm( 340 | settings, 341 | 'bin', 342 | bin, 343 | ninfo 344 | ); 345 | } else if (settings.allowDataInBase64 && canResizeImageToBase64 && canSendImageInBase64) { 346 | handleForm( 347 | settings, 348 | 'base64', 349 | dataURLtoBase64(canvas.toDataURL('image/' + settings.imageType)), 350 | ninfo 351 | ); 352 | } else { 353 | log('ERROR: No available method to extract image; allowDataInBase64 not set.'); 354 | settings.fileError.call(this, info, 'NO_BIN_SUPPORT_AND_BASE64_NOT_SET', 'No available method to extract file; allowDataInBase64 not set.'); 355 | } 356 | } 357 | 358 | settings.resizeImage(img, canvas, cb); 359 | } 360 | img.src = dataurl; 361 | } 362 | // Step 2: construct form data and send the file 363 | // paramaters: Ajax settings, File object, binary string of file || null, file info assoc array 364 | var handleForm = function (settings, type, data, info) { 365 | if (canSendFormData && type === 'file') { 366 | // FormData API saves the day 367 | log('INFO: Using FormData to construct form.'); 368 | var formdata = new FormData(); 369 | formdata.append(settings.name, data); 370 | // Prevent jQuery form convert FormData object into string. 371 | settings.processData = false; 372 | // Prevent jQuery from overwrite automatically generated xhr content-Type header 373 | // by unsetting the default contentType and inject data only right before xhr.send() 374 | settings.contentType = false; 375 | settings.__beforeSend = settings.beforeSend; 376 | settings.beforeSend = function (xhr, s) { 377 | s.data = formdata; 378 | if (s.__beforeSend) return s.__beforeSend.call(this, xhr, s); 379 | } 380 | //settings.data = formdata; 381 | } else if (canSendBinaryString && type === 'bin') { 382 | log('INFO: Concat our own multipart/form-data data string.'); 383 | 384 | // A placeholder MIME type 385 | if (!info.type) info.type = 'application/octet-stream'; 386 | 387 | if (/[^\x20-\x7E]/.test(info.name)) { 388 | log('INFO: Filename contains non-ASCII code, do UTF8-binary string conversion.'); 389 | info.name_bin = unescape(encodeURIComponent(info.name)); 390 | } 391 | 392 | //filtered out non-ASCII chars in filenames 393 | // info.name = info.name.replace(/[^\x20-\x7E]/g, '_'); 394 | 395 | // multipart/form-data boundary 396 | var bd = 'xhrupload-' + parseInt(Math.random()*(2 << 16)); 397 | settings.contentType = 'multipart/form-data; boundary=' + bd; 398 | var formdata = '--' + bd + '\n' // RFC 1867 Format, simulate form file upload 399 | + 'content-disposition: form-data; name="' + settings.name + '";' 400 | + ' filename="' + (info.name_bin || info.name) + '"\n' 401 | + 'Content-Type: ' + info.type + '\n\n' 402 | + data + '\n\n' 403 | + '--' + bd + '--'; 404 | 405 | if (window.XMLHttpRequest && window.XMLHttpRequest.prototype.sendAsBinary) { 406 | // Use xhr.sendAsBinary that takes binary string 407 | log('INFO: Pass binary string to xhr.'); 408 | settings.data = formdata; 409 | } else if (window.Blob && window.Uint8Array && window.ProgressEvent) { 410 | // send through xh2 411 | log('INFO: Make XH2 blob string'); 412 | var view = new Uint8Array(formdata.length); 413 | // jquery的each 不支持字符串了 414 | // $.each( 415 | // formdata, 416 | // function (i, o) { 417 | // view[i] = o.charCodeAt(0); 418 | // } 419 | // ); 420 | for(var i = 0; i < formdata.length; i++) { 421 | view[i] = formdata.charCodeAt(i); 422 | } 423 | 424 | var blob = view.buffer; 425 | settings.processData = false; 426 | settings.__beforeSend = settings.beforeSend; 427 | settings.beforeSend = function (xhr, s) { 428 | s.data = blob; 429 | if (s.__beforeSend) return s.__beforeSend.call(this, xhr, s); 430 | }; 431 | } else { 432 | // make a blob 433 | log('INFO: Convert binary string into Blob.'); 434 | var buf = new ArrayBuffer(formdata.length); 435 | var view = new Uint8Array(buf); 436 | $.each( 437 | formdata, 438 | function (i, o) { 439 | view[i] = o.charCodeAt(0); 440 | } 441 | ); 442 | var bb = new BlobBuilder(); 443 | bb.append(buf); 444 | var blob = bb.getBlob(); 445 | 446 | settings.processData = false; 447 | settings.__beforeSend = settings.beforeSend; 448 | settings.beforeSend = function (xhr, s) { 449 | s.data = blob; 450 | if (s.__beforeSend) return s.__beforeSend.call(this, xhr, s); 451 | }; 452 | } 453 | 454 | } else if (settings.allowDataInBase64 && type === 'base64') { 455 | log('INFO: Concat our own multipart/form-data data string; send the file in base64 because binary xhr is not supported.'); 456 | 457 | // A placeholder MIME type 458 | if (!info.type) info.type = 'application/octet-stream'; 459 | 460 | settings.url += '?enc=base64'; 461 | 462 | // multipart/form-data boundary 463 | var bd = 'xhrupload-' + parseInt(Math.random()*(2 << 16)); 464 | settings.contentType = 'multipart/form-data; boundary=' + bd; 465 | settings.data = '--' + bd + '\n' // RFC 1867 Format, simulate form file upload 466 | + 'content-disposition: form-data; name="' + settings.name + '";' 467 | + ' filename="' + encodeURIComponent(info.name) + '.base64"\n' 468 | + 'Content-Transfer-Encoding: base64\n' // Vaild MIME header, but won't work with PHP file upload handling. 469 | + 'Content-Type: ' + info.type + '\n\n' 470 | + data + '\n\n' 471 | + '--' + bd + '--'; 472 | } else { 473 | log('ERROR: Data is not given in processable form.'); 474 | settings.fileError.call(this, info, 'INTERNAL_ERROR', 'Data is not given in processable form.'); 475 | return; 476 | } 477 | xhrupload(settings); 478 | }; 479 | 480 | // Step 3: start sending out file 481 | var xhrupload = function (settings) { 482 | log('INFO: Sending file.'); 483 | if (typeof settings.data === 'string' && canSendBinaryString) { 484 | log('INFO: Using xhr.sendAsBinary.'); 485 | settings.___beforeSend = settings.beforeSend; 486 | settings.beforeSend = function (xhr, s) { 487 | if (window.XMLHttpRequest.prototype.sendAsBinary) { 488 | xhr.send = xhr.sendAsBinary; 489 | } 490 | 491 | if (s.___beforeSend) return s.___beforeSend.call(this, xhr, s); 492 | } 493 | } 494 | $.ajax(settings); 495 | }; 496 | 497 | $.fn.fileUpload = function(settings) { 498 | this.each(function(i, el) { 499 | if ($(el).is('input[type=file]')) { 500 | log('INFO: binding onchange event to a input[type=file].'); 501 | $(el).bind( 502 | 'change', 503 | function () { 504 | if (!this.files) { 505 | if (settings.fallback) { 506 | settings.fallback(); 507 | } 508 | return; 509 | } else if (!this.files.length) { 510 | log('ERROR: no file selected.'); 511 | return; 512 | } else if (this.files.length > 1) { 513 | log('WARN: Multiple file upload not implemented yet, only first file will be uploaded.'); 514 | } 515 | 516 | settings.name = $(this).attr('name'); 517 | handleFile($.extend({}, config, settings), this.files[0]); 518 | 519 | if (this.form) { 520 | this.form.reset(); 521 | } else { 522 | log('WARN: Unable to reset file selection, upload won\'t be triggered again if user selects the same file.'); 523 | } 524 | return; 525 | } 526 | ); 527 | } 528 | 529 | if ($(el).is('form')) { 530 | log('ERROR:
    not implemented yet.'); 531 | } else { 532 | log('INFO: binding ondrop event.'); 533 | $(el).bind( 534 | 'dragover', // dragover behavior should be blocked for drop to invoke. 535 | function(ev) { 536 | return false; 537 | } 538 | ).bind( 539 | 'drop', 540 | function (ev) { 541 | if (!ev.originalEvent.dataTransfer.files) { 542 | log('ERROR: No FileList object present; user might had dropped text.'); 543 | return false; 544 | } 545 | if (!ev.originalEvent.dataTransfer.files.length) { 546 | log('ERROR: User had dropped a virual file (e.g. "My Computer")'); 547 | return false; 548 | } 549 | if (!ev.originalEvent.dataTransfer.files.length > 1) { 550 | log('WARN: Multiple file upload not implemented yet, only first file will be uploaded.'); 551 | } 552 | handleFile($.extend({}, config, settings), ev.originalEvent.dataTransfer.files[0]); 553 | return false; 554 | } 555 | ); 556 | } 557 | }); 558 | 559 | return this; 560 | }; 561 | 562 | $.fileUploadSupported = isSupported; 563 | $.imageUploadSupported = isImageSupported; 564 | $.fileUploadAsBase64Supported = isSupportedInBase64; 565 | $.imageUploadAsBase64Supported = isImageSupportedInBase64; 566 | 567 | })(); 568 | -------------------------------------------------------------------------------- /src/config/editor/js/highlight.js: -------------------------------------------------------------------------------- 1 | /** 2 | * highlight.js 3 | * @Author integ@segmentfault.com 4 | * $wrap为空时对所有pre标签执行高亮 5 | **/ 6 | 7 | //define(['jquery', 'highlightjs', 'ZeroClipboard', 'math'], 8 | //function($, hljs, ZeroClipboard, math){ 9 | $(function() { 10 | 'use strict'; 11 | 12 | window.highLight = function($wrap) { 13 | //highlight 14 | // detect highlight.js 15 | if ('undefined' === typeof(hljs)) { 16 | return; 17 | } 18 | // 自动载入highlight 19 | var hlNames = { 20 | actionscript : /^as[1-3]$/i, 21 | cmake : /^(make|makefile)$/i, 22 | cs : /^csharp$/i, 23 | css : /^css[1-3]$/i, 24 | delphi : /^pascal$/i, 25 | javascript : /^js$/i, 26 | markdown : /^md$/i, 27 | objectivec : /^(oc|objective-c)$/i, 28 | php : /^php[1-6]$/i, 29 | sql : /^mysql$/i, 30 | xml : /^(html|html5|xhtml)$/i 31 | }; 32 | var hlLangs = hljs.listLanguages(); 33 | 34 | function myHighLight($this) { 35 | var t = $this, children = t.children(), highlighted = false; 36 | 37 | if (children.length > 0 && 'code' === children.get(0).nodeName.toLowerCase()) { 38 | var className = children.attr('class'); 39 | 40 | if (!!className) { 41 | var classes = className.split(/\s+/); 42 | for (var i = 0; i < classes.length; i ++) { 43 | if (0 === classes[i].indexOf('lang-')) { 44 | var lang = classes[i].substring(5).toLowerCase(), finalLang; 45 | 46 | if (hlLangs[lang]) { 47 | finalLang = lang; 48 | } else { 49 | for (var l in hlNames) { 50 | if (lang.match(hlNames[l])) { 51 | finalLang = l; 52 | } 53 | } 54 | } 55 | 56 | if (!!finalLang) { 57 | var result = hljs.highlight(finalLang, children.text(), true); 58 | children.html(result.value); 59 | highlighted = true; 60 | break; 61 | } 62 | } 63 | } 64 | } 65 | } 66 | 67 | if (!highlighted) { 68 | var html = t.html(); 69 | t.html(html.replace(/<\/?[a-z]+[^>]*>/ig, '')); 70 | hljs.highlightBlock($this[0], '', false); 71 | } 72 | 73 | //添加行号 74 | t.wrap('
    '); //包上table 75 | var _$wrap = t.parents('.widget-highlight tr'); // tr 76 | _$wrap.prepend(''); //插入行号的td 77 | var _totalLine = t.height() / 15; 78 | var _$lines = _$wrap.find('.widget-highlight--line'); 79 | // var _$code = _$wrap.find('.widget-highlight--code'); 80 | var _width = t.parents('.widget-highlight').parent().width(); 81 | if(_totalLine < 10) { 82 | _$lines.css('width', '16px'); 83 | // _$code.css('width', _width - 16 + 'px'); 84 | t.css('width', _width - 32 + 'px'); 85 | } else if(_totalLine < 100) { 86 | _$lines.css('width', '32px'); 87 | // _$code.css('width', _width - 32 + 'px'); 88 | t.css('width', _width - 40 + 'px'); 89 | } else { 90 | _$lines.css('width', '48px'); 91 | // _$code.css('width', _width - 48 + 'px'); 92 | t.css('width', _width - 51 + 'px'); 93 | } 94 | // 黑魔法 dangerous 95 | if(_totalLine < 17) { 96 | _totalLine = t.height() / 15; 97 | } else if(_totalLine < 27) { 98 | _totalLine = (t.height() - 10) / 15; 99 | } else if(_totalLine < 55) { 100 | _totalLine = (t.height() - 20) / 15; 101 | } else if(_totalLine < 55) { 102 | _totalLine = (t.height() - 40) / 15; 103 | } else { 104 | _totalLine = (t.height() + 15) / 16; 105 | } 106 | for(var line = 1; line < _totalLine; line++) { 107 | var _h = '

    ' + line + '

    '; 108 | _$lines.append(_h); 109 | } 110 | 111 | _$lines.attr('unselectable', 'on') //禁止选中行号 112 | .css('user-select', 'none') 113 | .on('selectstart', false); 114 | 115 | // 添加copy 116 | // var _$parent = _$wrap.parents('.widget-highlight'); 117 | if(navigator.plugins['Shockwave Flash'] || new ActiveXObject('ShockwaveFlash.shockwaveFlash')) { 118 | var _$clip = $(''); 119 | t.prepend(_$clip); 120 | ZeroClipboard.config({ swfPath: '//cdnjs.cloudflare.com/ajax/libs/zeroclipboard/2.1.6/ZeroClipboard.swf' }); 121 | var _client = new ZeroClipboard(_$clip); 122 | var _e = $('#global-zeroclipboard-html-bridge'); 123 | _client.on('load', function() { 124 | _e.data('placement', 'top').attr('title', 'Copy to clipboard').tooltip(); 125 | }); 126 | _client.on('copy', function (event) { 127 | var clipboard = event.clipboardData; 128 | clipboard.setData('text/plain', t.text()); 129 | clipboard.setData('text/html', t.html()); 130 | clipboard.setData('application/rtf', t.html()); 131 | }); 132 | _client.on('error', function() { 133 | _e.attr('title', 'Flash required').tooltip('fixTitle').tooltip('show'); 134 | }); 135 | _client.on('aftercopy', function() { 136 | _e.attr('title', 'Copied!').tooltip('fixTitle') 137 | .tooltip('show').attr('title', 'Copy to clipboard').tooltip('fixTitle'); 138 | }); 139 | t.hover(function() { 140 | _$clip.removeClass('hidden'); 141 | }); 142 | } 143 | } 144 | 145 | // mathJax 146 | var _hasMath = null; 147 | if(!$wrap) { 148 | _hasMath = $('.fmt').text().match(/\$\$/); 149 | if(_hasMath && _hasMath.length) { 150 | math(); 151 | } 152 | $('pre').each(function() { 153 | if (!this.parentNode || $(this).parents('.CodeMirror-scroll').length) { //codemirror不参加 154 | return; 155 | } else { 156 | myHighLight($(this)); 157 | } 158 | }); 159 | } else { 160 | _hasMath = $wrap.text().match(/\$\$/); 161 | if(_hasMath && _hasMath.length) { 162 | math($wrap); 163 | } 164 | $wrap.find('pre').each(function() { 165 | myHighLight($(this)); 166 | }); 167 | } 168 | }; 169 | }); 170 | -------------------------------------------------------------------------------- /src/config/editor/js/modal.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function temp(template, data) { 4 | var str = template || ''; 5 | // Convert the template into string 6 | $.each(data, function(key, val){ 7 | var _type = typeof val, 8 | re = new RegExp('{{\\s*' + key + '\\s*}}', 'g'); 9 | if (_type === 'object' && val !== null){ 10 | $.each(val, function(k, v){ 11 | var r = new RegExp('{{\\s*' + key + '.' + k + '\\s*}}', 'g'); 12 | str = str.replace(r, v); 13 | }); 14 | } else { 15 | str = str.replace(re, val); 16 | } 17 | }); 18 | return str; 19 | }; 20 | 21 | function sfModal(option) { 22 | if(typeof option !== 'object') { 23 | if(option === 'hide') { 24 | $('.sfmodal').modal('hide'); 25 | return; 26 | } else if(option === 'toggle') { 27 | $('.sfmodal').modal('toggle'); 28 | return; 29 | } else { 30 | option = { 31 | content : option, 32 | hideDone : true, 33 | }; 34 | } 35 | } 36 | 37 | var OPT = $.extend({ 38 | hideTitle : false, 39 | title : '警告:前方高能!', 40 | content : '玩脱了', 41 | wrapper : null, //编辑器全屏时不能显示modal 42 | $content : null, 43 | hideClose : false, 44 | closeText : '取消', 45 | // closeFn : function() {}, 46 | hideDone : false, 47 | doneText : '确认', 48 | doneFn : function() { 49 | $('.sfmodal').modal('hide'); 50 | }, 51 | show : function() {}, 52 | // 不明原因shown不触发(这个问题不知道这样解决是不是正确的,看下面×处) 53 | shown : function() {}, 54 | hide : function() {}, 55 | hidden : function() {}, 56 | loaded : function() {} 57 | }, option); 58 | 59 | var dom = ''; 74 | 75 | // 删掉已经存在的modal 76 | if ($('.sfmodal').length > 0) { 77 | $('.sfmodal').remove(); 78 | $('.modal-backdrop').remove(); 79 | } 80 | // 有$wrap时插到$wrap里面 81 | if(OPT.wrapper) { 82 | $(OPT.wrapper).append(temp(dom, OPT)); 83 | $(OPT.wrapper).append(''); 84 | } else { 85 | $('body').append(temp(dom, OPT)); 86 | } 87 | if(OPT.$content) { // 优先使用$content 88 | $('.sfmodal .sfModal-content').append(OPT.$content); 89 | } else { 90 | $('.sfmodal .sfModal-content').html(OPT.content); 91 | } 92 | //× 文档上面写的是.modal('show')会在触发shown.bs.modal之前返回 93 | //所以我直接在这一句绑定事件,shown就有效果了 94 | // 参考 http://v3.bootcss.com/javascript/#modalshow 95 | $('.sfmodal') 96 | .on('shown.bs.modal' , OPT.shown) 97 | .on('show.bs.modal' , OPT.show) 98 | .on('hide.bs.modal' , function(e) { 99 | OPT.hide(e); 100 | if(OPT.wrapper) { 101 | $('.modal-backdrop').remove(); 102 | } 103 | }) 104 | .on('hidden.bs.modal', OPT.hidden) 105 | .on('loaded.bs.modal', OPT.loaded) 106 | .modal({ 107 | keyboard: true, 108 | show:true, 109 | }); 110 | // $('.sfmodal') 111 | // .on('shown.bs.modal' , OPT.shown) 112 | // .on('show.bs.modal' , OPT.show) 113 | // .on('hide.bs.modal' , function(e) { 114 | // OPT.hide(e); 115 | // if(OPT.wrapper) { 116 | // $('.modal-backdrop').remove(); 117 | // } 118 | // }) 119 | // .on('hidden.bs.modal', OPT.hidden) 120 | // .on('loaded.bs.modal', OPT.loaded) 121 | // .modal('show'); // 一定要先绑事件,然后再show 122 | $('.sfmodal .done-btn').click(function(e) { 123 | OPT.doneFn(e); 124 | if(OPT.wrapper) { 125 | $('.modal-backdrop').remove(); 126 | } 127 | }); 128 | }; 129 | -------------------------------------------------------------------------------- /src/config/editor/js/piano.js: -------------------------------------------------------------------------------- 1 | $(function() { 2 | var keyMap = { 3 | 96 : 100, 49 : 102, 50 : 104, 51 : 106, 52 : 108, 53 : 110, 54 : 112, 55 : 114, 56 : 116, 57 : 118, 48: 120, 45: 122, 61: 124, 4 | 126: 101, 33 : 103, 64 : 105, 35 : 107, 36 : 109, 37 : 111, 94 : 113, 38 : 115, 42 : 117, 40 : 119, 41: 121, 95: 123, 43: 125, 5 | 6 | 113: 74 , 119: 76 , 101: 78 , 114: 80 , 116: 82 , 121: 84 , 117: 86 , 105: 88 , 111: 90 , 112: 92 , 91 : 94 , 93 : 96 , 92 : 98, 7 | 81 : 75 , 87 : 77 , 69 : 79 , 82 : 81 , 84 : 83 , 89 : 85 , 85 : 87 , 73 : 89 , 79 : 91 , 80 : 93 , 123: 95 , 125: 97 , 124: 99, 8 | 9 | 97: 52, 115: 54, 100: 56, 102: 58, 103: 60, 104: 62, 106: 64, 107: 66, 108: 68, 59: 70, 39: 72, 10 | 65: 53, 83 : 55, 68 : 57, 70 : 59, 71 : 61, 72 : 63, 74 : 65, 75 : 67, 76 : 69, 58: 71, 34: 73, 11 | 12 | 122: 32, 120: 34, 99: 36, 118: 38, 98: 40, 110: 42, 109: 44, 44: 46, 46: 48, 47: 50, 13 | 90 : 33, 88 : 35, 67: 37, 86 : 39, 66: 41, 78 : 43, 77 : 45, 60: 47, 62: 49, 63: 51, 14 | }; 15 | MIDI.loadPlugin({ 16 | soundfontUrl: "js/MIDI.js/soundfont/", //acoustic_grand_piano-ogg.js", 17 | //instrument: 1 // (default) 18 | callback: function() { 19 | var delay = 0; // play one note every quarter second 20 | var velocity = 127; // how hard the note hits play the note 21 | var count1 = 0; 22 | var count2 = 0; 23 | MIDI.setVolume(0, 127); 24 | $('textarea, input').on('keypress', function(e) { 25 | count1++; 26 | if(e.which === 32) { 27 | var tone = parseInt(Math.random()*(107 - 25) + 25); 28 | MIDI.noteOn(0, tone, velocity, delay); 29 | MIDI.noteOff(0, tone, delay + 0.75); 30 | } else { 31 | var tone = keyMap[e.which] - 13; 32 | //+ MIDI.pianoKeyOffset; 33 | MIDI.noteOn(0, tone, velocity, delay); 34 | MIDI.noteOff(0, tone, delay + 0.75); 35 | } 36 | }); 37 | 38 | $('textarea, input').on('input', function(e) { 39 | count2++; 40 | if(count1 !== count2) { 41 | var tone = parseInt(Math.random()*(107 - 25) + 25); 42 | MIDI.noteOn(0, tone, velocity, delay); 43 | MIDI.noteOff(0, tone, delay + 0.75); 44 | count1 = 0; 45 | count2 = 0; 46 | } 47 | }); 48 | } 49 | }); 50 | }); 51 | -------------------------------------------------------------------------------- /src/config/editor/js/template.js: -------------------------------------------------------------------------------- 1 | /** 2 | * temp.js 3 | * 一个简单的模板填充工具,使用twig的语法 4 | * @param {string}template 模板字符串 5 | * @param {json}data 填充的数据 6 | * @return {string} 返回拼接后的字符串 7 | * @author integ@segmentfault.com 8 | **/ 9 | 10 | define(['jquery'], function($){ 11 | 'use strict'; 12 | return function(template, data) { 13 | var str = template || ''; 14 | // Convert the template into string 15 | $.each(data, function(key, val){ 16 | var _type = typeof val, 17 | re = new RegExp('{{\\s*' + key + '\\s*}}', 'g'); 18 | if (_type === 'object' && val !== null){ 19 | $.each(val, function(k, v){ 20 | var r = new RegExp('{{\\s*' + key + '.' + k + '\\s*}}', 'g'); 21 | str = str.replace(r, v); 22 | }); 23 | } else { 24 | str = str.replace(re, val); 25 | } 26 | }); 27 | return str; 28 | }; 29 | }); 30 | -------------------------------------------------------------------------------- /src/config/editor/js/zoom.js: -------------------------------------------------------------------------------- 1 | /** 2 | * zoom.js - It's the best way to zoom an image 3 | * @version v0.0.2 4 | * @link https://github.com/fat/zoom.js 5 | * @license MIT 6 | */ 7 | 8 | +function ($) { "use strict"; 9 | 10 | /** 11 | * The zoom service 12 | */ 13 | function ZoomService () { 14 | this._activeZoom = 15 | this._initialScrollPosition = 16 | this._initialTouchPosition = 17 | this._touchMoveListener = null 18 | 19 | this._$document = $(document) 20 | this._$window = $(window) 21 | this._$body = $(document.body) 22 | 23 | this._boundClick = $.proxy(this._clickHandler, this) 24 | } 25 | 26 | ZoomService.prototype.listen = function () { 27 | this._$body.on('click', '[data-action="zoom"]', $.proxy(this._zoom, this)) 28 | } 29 | 30 | ZoomService.prototype._zoom = function (e) { 31 | var target = e.target 32 | 33 | if (!target || target.tagName != 'IMG') return 34 | 35 | if (this._$body.hasClass('zoom-overlay-open')) return 36 | 37 | if (e.metaKey || e.ctrlKey) { 38 | return window.open((e.target.getAttribute('data-original') || e.target.src), '_blank') 39 | } 40 | 41 | if (target.width >= ($(window).width() - Zoom.OFFSET)) return 42 | 43 | this._activeZoomClose(true) 44 | 45 | this._activeZoom = new Zoom(target) 46 | this._activeZoom.zoomImage() 47 | 48 | // todo(fat): probably worth throttling this 49 | this._$window.on('scroll.zoom', $.proxy(this._scrollHandler, this)) 50 | 51 | this._$document.on('keyup.zoom', $.proxy(this._keyHandler, this)) 52 | this._$document.on('touchstart.zoom', $.proxy(this._touchStart, this)) 53 | 54 | // we use a capturing phase here to prevent unintended js events 55 | // sadly no useCapture in jquery api (http://bugs.jquery.com/ticket/14953) 56 | if (document.addEventListener) { 57 | document.addEventListener('click', this._boundClick, true) 58 | } else { 59 | document.attachEvent('onclick', this._boundClick, true) 60 | } 61 | 62 | if ('bubbles' in e) { 63 | if (e.bubbles) e.stopPropagation() 64 | } else { 65 | // Internet Explorer before version 9 66 | e.cancelBubble = true 67 | } 68 | } 69 | 70 | ZoomService.prototype._activeZoomClose = function (forceDispose) { 71 | if (!this._activeZoom) return 72 | 73 | if (forceDispose) { 74 | this._activeZoom.dispose() 75 | } else { 76 | this._activeZoom.close() 77 | } 78 | 79 | this._$window.off('.zoom') 80 | this._$document.off('.zoom') 81 | 82 | document.removeEventListener('click', this._boundClick, true) 83 | 84 | this._activeZoom = null 85 | } 86 | 87 | ZoomService.prototype._scrollHandler = function (e) { 88 | if (this._initialScrollPosition === null) this._initialScrollPosition = $(window).scrollTop() 89 | var deltaY = this._initialScrollPosition - $(window).scrollTop() 90 | if (Math.abs(deltaY) >= 40) this._activeZoomClose() 91 | } 92 | 93 | ZoomService.prototype._keyHandler = function (e) { 94 | if (e.keyCode == 27) this._activeZoomClose() 95 | } 96 | 97 | ZoomService.prototype._clickHandler = function (e) { 98 | if (e.preventDefault) e.preventDefault() 99 | else event.returnValue = false 100 | 101 | if ('bubbles' in e) { 102 | if (e.bubbles) e.stopPropagation() 103 | } else { 104 | // Internet Explorer before version 9 105 | e.cancelBubble = true 106 | } 107 | 108 | this._activeZoomClose() 109 | } 110 | 111 | ZoomService.prototype._touchStart = function (e) { 112 | this._initialTouchPosition = e.touches[0].pageY 113 | $(e.target).on('touchmove.zoom', $.proxy(this._touchMove, this)) 114 | } 115 | 116 | ZoomService.prototype._touchMove = function (e) { 117 | if (Math.abs(e.touches[0].pageY - this._initialTouchPosition) > 10) { 118 | this._activeZoomClose() 119 | $(e.target).off('touchmove.zoom') 120 | } 121 | } 122 | 123 | 124 | /** 125 | * The zoom object 126 | */ 127 | function Zoom (img) { 128 | this._fullHeight = 129 | this._fullWidth = 130 | this._overlay = 131 | this._targetImageWrap = null 132 | 133 | this._targetImage = img 134 | 135 | this._$body = $(document.body) 136 | } 137 | 138 | Zoom.OFFSET = 80 139 | Zoom._MAX_WIDTH = 2560 140 | Zoom._MAX_HEIGHT = 4096 141 | 142 | Zoom.prototype.zoomImage = function () { 143 | var img = document.createElement('img') 144 | img.onload = $.proxy(function () { 145 | this._fullHeight = Number(img.height) 146 | this._fullWidth = Number(img.width) 147 | this._zoomOriginal() 148 | }, this) 149 | img.src = this._targetImage.src 150 | } 151 | 152 | Zoom.prototype._zoomOriginal = function () { 153 | this._targetImageWrap = document.createElement('div') 154 | this._targetImageWrap.className = 'zoom-img-wrap' 155 | 156 | this._targetImage.parentNode.insertBefore(this._targetImageWrap, this._targetImage) 157 | this._targetImageWrap.appendChild(this._targetImage) 158 | 159 | $(this._targetImage) 160 | .addClass('zoom-img') 161 | .attr('data-action', 'zoom-out') 162 | 163 | this._overlay = document.createElement('div') 164 | this._overlay.className = 'zoom-overlay' 165 | 166 | document.body.appendChild(this._overlay) 167 | 168 | this._calculateZoom() 169 | this._triggerAnimation() 170 | } 171 | 172 | Zoom.prototype._calculateZoom = function () { 173 | this._targetImage.offsetWidth // repaint before animating 174 | 175 | var originalFullImageWidth = this._fullWidth 176 | var originalFullImageHeight = this._fullHeight 177 | 178 | var scrollTop = $(window).scrollTop() 179 | 180 | var maxScaleFactor = originalFullImageWidth / this._targetImage.width 181 | 182 | var viewportHeight = ($(window).height() - Zoom.OFFSET) 183 | var viewportWidth = ($(window).width() - Zoom.OFFSET) 184 | 185 | var imageAspectRatio = originalFullImageWidth / originalFullImageHeight 186 | var viewportAspectRatio = viewportWidth / viewportHeight 187 | 188 | if (originalFullImageWidth < viewportWidth && originalFullImageHeight < viewportHeight) { 189 | this._imgScaleFactor = maxScaleFactor 190 | 191 | } else if (imageAspectRatio < viewportAspectRatio) { 192 | this._imgScaleFactor = (viewportHeight / originalFullImageHeight) * maxScaleFactor 193 | 194 | } else { 195 | this._imgScaleFactor = (viewportWidth / originalFullImageWidth) * maxScaleFactor 196 | } 197 | } 198 | 199 | Zoom.prototype._triggerAnimation = function () { 200 | this._targetImage.offsetWidth // repaint before animating 201 | 202 | var imageOffset = $(this._targetImage).offset() 203 | var scrollTop = $(window).scrollTop() 204 | 205 | var viewportY = scrollTop + ($(window).height() / 2) 206 | var viewportX = ($(window).width() / 2) 207 | 208 | var imageCenterY = imageOffset.top + (this._targetImage.height / 2) 209 | var imageCenterX = imageOffset.left + (this._targetImage.width / 2) 210 | 211 | this._translateY = viewportY - imageCenterY 212 | this._translateX = viewportX - imageCenterX 213 | 214 | var targetTransform = 'scale(' + this._imgScaleFactor + ')' 215 | var imageWrapTransform = 'translate(' + this._translateX + 'px, ' + this._translateY + 'px)' 216 | 217 | if ($.support.transition) { 218 | imageWrapTransform += ' translateZ(0)' 219 | } 220 | 221 | $(this._targetImage) 222 | .css({ 223 | '-webkit-transform': targetTransform, 224 | '-ms-transform': targetTransform, 225 | 'transform': targetTransform 226 | }) 227 | 228 | $(this._targetImageWrap) 229 | .css({ 230 | '-webkit-transform': imageWrapTransform, 231 | '-ms-transform': imageWrapTransform, 232 | 'transform': imageWrapTransform 233 | }) 234 | 235 | this._$body.addClass('zoom-overlay-open') 236 | } 237 | 238 | Zoom.prototype.close = function () { 239 | this._$body 240 | .removeClass('zoom-overlay-open') 241 | .addClass('zoom-overlay-transitioning') 242 | 243 | // we use setStyle here so that the correct vender prefix for transform is used 244 | $(this._targetImage) 245 | .css({ 246 | '-webkit-transform': '', 247 | '-ms-transform': '', 248 | 'transform': '' 249 | }) 250 | 251 | $(this._targetImageWrap) 252 | .css({ 253 | '-webkit-transform': '', 254 | '-ms-transform': '', 255 | 'transform': '' 256 | }) 257 | 258 | if (!$.support.transition) { 259 | return this.dispose() 260 | } 261 | 262 | $(this._targetImage) 263 | .one($.support.transition.end, $.proxy(this.dispose, this)) 264 | .emulateTransitionEnd(300) 265 | } 266 | 267 | Zoom.prototype.dispose = function () { 268 | if (this._targetImageWrap && this._targetImageWrap.parentNode) { 269 | $(this._targetImage) 270 | .removeClass('zoom-img') 271 | .attr('data-action', 'zoom') 272 | 273 | this._targetImageWrap.parentNode.replaceChild(this._targetImage, this._targetImageWrap) 274 | this._overlay.parentNode.removeChild(this._overlay) 275 | 276 | this._$body.removeClass('zoom-overlay-transitioning') 277 | } 278 | } 279 | 280 | // wait for dom ready (incase script included before body) 281 | $(function () { 282 | new ZoomService().listen() 283 | }) 284 | 285 | }(jQuery) 286 | -------------------------------------------------------------------------------- /src/config/views/decode.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/config/views/head.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 40 | 41 | --------------------------------------------------------------------------------