├── .eslintrc.json ├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── labeler.yml └── workflows │ ├── codeql-analysis.yml │ ├── labeler.yml │ └── node.js.yml ├── .gitignore ├── CHANGELOG.txt ├── Gruntfile.js ├── LICENSE.md ├── README.md ├── SECURITY.md ├── emoticons ├── alien.png ├── angel.png ├── angry.png ├── blink.png ├── blush.png ├── cheerful.png ├── cool.png ├── credits.txt ├── cwy.png ├── devil.png ├── dizzy.png ├── ermm.png ├── face.png ├── getlost.png ├── grin.png ├── happy.png ├── heart.png ├── kissing.png ├── laughing.png ├── ninja.png ├── pinch.png ├── pouty.png ├── sad.png ├── shocked.png ├── sick.png ├── sideways.png ├── silly.png ├── sleeping.png ├── smile.png ├── tongue.png ├── unsure.png ├── w00t.png ├── wassat.png ├── whistling.png ├── wink.png └── wub.png ├── example ├── emoticons │ ├── alien.png │ ├── angel.png │ ├── angry.png │ ├── blink.png │ ├── blush.png │ ├── cheerful.png │ ├── cool.png │ ├── credits.txt │ ├── cwy.png │ ├── devil.png │ ├── dizzy.png │ ├── ermm.png │ ├── face.png │ ├── getlost.png │ ├── grin.png │ ├── happy.png │ ├── heart.png │ ├── kissing.png │ ├── laughing.png │ ├── ninja.png │ ├── pinch.png │ ├── pouty.png │ ├── sad.png │ ├── shocked.png │ ├── sick.png │ ├── sideways.png │ ├── silly.png │ ├── sleeping.png │ ├── smile.png │ ├── tongue.png │ ├── unsure.png │ ├── w00t.png │ ├── wassat.png │ ├── whistling.png │ ├── wink.png │ └── wub.png └── example.html ├── languages ├── .eslintrc.json ├── ar.js ├── ca.js ├── cn.js ├── cs.js ├── de.js ├── el.js ├── en-US.js ├── en.js ├── es.js ├── et.js ├── fa.js ├── fi.js ├── fr.js ├── gl.js ├── hu.js ├── id.js ├── it.js ├── ja.js ├── lt.js ├── nb.js ├── nl.js ├── pl.js ├── pt-BR.js ├── pt.js ├── ru.js ├── sk.js ├── sv.js ├── template.js ├── tr.js ├── tw.js ├── uk.js └── vi.js ├── package-lock.json ├── package.json ├── preview.svg ├── src ├── formats │ ├── .eslintrc.json │ ├── bbcode.js │ └── xhtml.js ├── icons │ ├── .eslintrc.json │ ├── material.js │ └── monocons.js ├── jquery.sceditor.js ├── lib │ ├── PluginManager.js │ ├── RangeHelper.js │ ├── SCEditor.js │ ├── browser.js │ ├── defaultCommands.js │ ├── defaultOptions.js │ ├── dom.js │ ├── emoticons.js │ ├── escape.js │ ├── templates.js │ └── utils.js ├── plugins │ ├── .eslintrc.json │ ├── alternative-lists.js │ ├── autosave.js │ ├── autoyoutube.js │ ├── dragdrop.js │ ├── emojis.js │ ├── format.js │ ├── plaintext.js │ ├── undo.js │ └── v1compat.js ├── sceditor.js └── themes │ ├── content │ └── default.css │ ├── default.less │ ├── defaultdark.less │ ├── icons │ ├── famfamfam.less │ ├── famfamfam.png │ └── src │ │ └── famfamfam │ │ ├── bold.png │ │ ├── bulletlist.png │ │ ├── center.png │ │ ├── code.png │ │ ├── color.png │ │ ├── copy.png │ │ ├── cut.png │ │ ├── date.png │ │ ├── email.png │ │ ├── emoticon.png │ │ ├── font.png │ │ ├── format.png │ │ ├── grip-rtl.png │ │ ├── grip.png │ │ ├── horizontalrule.png │ │ ├── image.png │ │ ├── indent.png │ │ ├── italic.png │ │ ├── justify.png │ │ ├── left.png │ │ ├── ltr.png │ │ ├── maximize.png │ │ ├── orderedlist.png │ │ ├── outdent.png │ │ ├── paste.png │ │ ├── pastetext.png │ │ ├── print.png │ │ ├── quote.png │ │ ├── removeformat.png │ │ ├── right.png │ │ ├── rtl.png │ │ ├── size.png │ │ ├── source.png │ │ ├── strike.png │ │ ├── subscript.png │ │ ├── superscript.png │ │ ├── table.png │ │ ├── text_ltr.xcf │ │ ├── text_rtl.xcf │ │ ├── time.png │ │ ├── underline.png │ │ ├── unlink.png │ │ ├── url.png │ │ └── youtube.png │ ├── inc │ ├── defaultbase.less │ └── elements.less │ ├── modern.less │ ├── office-toolbar.less │ ├── office.less │ └── square.less └── tests ├── .eslintrc.json ├── dev-server.js ├── index.html ├── loader.js ├── manual ├── debug │ ├── index.html │ └── test.js ├── events │ ├── index.html │ └── tests.js ├── index.html ├── manualTestRunner.js ├── memory │ ├── index.html │ └── test.js ├── patchConsole.js ├── style.css └── valuechanged │ ├── index.html │ └── test.js ├── test-bridge.js └── unit ├── closeAssert.js ├── formats ├── bbcode.js ├── bbcode.parser.js ├── bbcode │ ├── matching.js │ └── nesting.js └── xhtml.js ├── htmlAssert.js ├── index.html ├── index.js ├── init.js ├── jquery.sceditor.js ├── lib ├── PluginManager.js ├── RangeHelper.js ├── SCEditor.js ├── dom.js ├── emoticons.js ├── escape.js └── utils.js ├── plugins └── autoyoutube.js └── utils.js /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "parserOptions": { 3 | "ecmaVersion": 6, 4 | "sourceType": "module" 5 | }, 6 | "env": { 7 | "browser": true, 8 | "jquery": true 9 | }, 10 | "globals": { 11 | "sceditor": false 12 | }, 13 | "rules": { 14 | "no-bitwise": "error", 15 | "camelcase": "error", 16 | "curly": "error", 17 | "eqeqeq": "error", 18 | "guard-for-in": "error", 19 | "wrap-iife": ["error", "any"], 20 | "indent": ["error", "tab", { "SwitchCase": 1 }], 21 | "no-use-before-define": ["error", { "functions": false }], 22 | "new-cap": ["error", { 23 | "capIsNewExceptions": ["Event"] 24 | }], 25 | "no-caller": "error", 26 | "no-empty": ["error", { "allowEmptyCatch": true }], 27 | "no-new": "error", 28 | "no-plusplus": "off", 29 | "quotes": ["error", "single"], 30 | "no-undef": "error", 31 | "no-unused-vars": "error", 32 | "strict": "error", 33 | "max-params": ["error", 4], 34 | "max-depth": ["error", 4], 35 | "max-len": ["error", { 36 | "code": 80, 37 | "ignoreUrls": true, 38 | "ignoreRegExpLiterals": true 39 | }], 40 | "semi": ["error", "always"], 41 | "no-cond-assign": ["error", "except-parens"], 42 | "no-debugger": "error", 43 | "no-eq-null": "error", 44 | "no-eval": "error", 45 | "no-unused-expressions": "error", 46 | "block-scoped-var": "error", 47 | "no-iterator": "error", 48 | "linebreak-style": ["error", "unix"], 49 | "comma-style": ["error", "last"], 50 | "no-loop-func": "error", 51 | "no-multi-str": "error", 52 | "no-proto": "error", 53 | "no-script-url": "error", 54 | "no-shadow": "off", 55 | "dot-notation": "error", 56 | "no-new-func": "error", 57 | "no-new-wrappers": "error", 58 | "no-invalid-this": "off", 59 | "no-with": "error", 60 | "brace-style": ["error", "1tbs", { 61 | "allowSingleLine": false 62 | }], 63 | "no-mixed-spaces-and-tabs": "error", 64 | "key-spacing": ["error",{ 65 | "beforeColon": false, 66 | "afterColon": true 67 | }], 68 | "space-unary-ops": "error", 69 | "space-before-function-paren": ["error", { 70 | "anonymous": "always", 71 | "named": "never", 72 | "asyncArrow": "never" 73 | }], 74 | "no-spaced-func": "error", 75 | "array-bracket-spacing": ["error", "never"], 76 | "keyword-spacing": ["error", { 77 | "before": true, 78 | "after": true 79 | }], 80 | "space-in-parens": ["error", "never"], 81 | "comma-dangle": ["error", "never"], 82 | "no-trailing-spaces": "error", 83 | "eol-last": "error", 84 | "space-infix-ops": "error", 85 | "space-before-blocks": ["error", "always"] 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.css text eol=lf 2 | *.html text eol=lf 3 | *.js text eol=lf 4 | *.json text eol=lf 5 | *.less text eol=lf 6 | *.md text eol=lf 7 | *.php text eol=lf 8 | *.txt text eol=lf 9 | *.yml text eol=lf 10 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Report a bug or regression 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | 18 | 19 | ### Steps to reproduce the problem 20 | 21 | 1. 22 | 2. 23 | 24 | 35 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/labeler.yml: -------------------------------------------------------------------------------- 1 | version: v1 2 | 3 | labels: 4 | - label: build 5 | sync: true 6 | matcher: 7 | title: ^build(?:\([\w-]+\))?:.* 8 | branch: ^build[/-].* 9 | commits: ^build(?:\([\w-]+\))?:.* 10 | 11 | - label: build 12 | sync: true 13 | matcher: 14 | title: ^chore(?:\([\w-]+\))?:.* 15 | branch: ^chore[/-].* 16 | commits: ^chore(?:\([\w-]+\))?:.* 17 | 18 | - label: ci 19 | sync: true 20 | matcher: 21 | branch: ^ci[/-].* 22 | commits: ^ci(?:\([\w-]+\))?:.* 23 | files: .github/**/* 24 | 25 | - label: docs 26 | sync: true 27 | matcher: 28 | branch: ^docs[/-].* 29 | commits: ^docs(?:\([\w-]+\))?:.* 30 | 31 | - label: feature 32 | sync: true 33 | matcher: 34 | title: ^feat(?:\([\w-]+\))?:.* 35 | branch: ^feat[/-].* 36 | commits: ^feat(?:\([\w-]+\))?:.* 37 | 38 | - label: icons 39 | sync: true 40 | matcher: 41 | files: src/icons/* 42 | 43 | - label: lib 44 | sync: true 45 | matcher: 46 | files: src/lib/* 47 | 48 | - label: languages 49 | sync: true 50 | matcher: 51 | files: src/languages/* 52 | 53 | - label: fix 54 | sync: true 55 | matcher: 56 | branch: ^fix[/-].* 57 | commits: ^fix(?:\([\w-]+\))?:.* 58 | 59 | - label: performance 60 | sync: true 61 | matcher: 62 | branch: ^perf[/-].* 63 | commits: ^perf(?:\([\w-]+\))?:.* 64 | 65 | - label: plugins 66 | sync: true 67 | matcher: 68 | files: src/plugins/* 69 | 70 | - label: refactor 71 | sync: true 72 | matcher: 73 | branch: ^refactor[/-].* 74 | commits: ^refactor(?:\([\w-]+\))?:.* 75 | 76 | - label: style 77 | sync: true 78 | matcher: 79 | branch: ^style[/-].* 80 | commits: ^style(?:\([\w-]+\))?:.* 81 | 82 | - label: test 83 | sync: true 84 | matcher: 85 | branch: ^test[/-].* 86 | commits: ^test(?:\([\w-]+\))?:.* 87 | files: test/**/* 88 | 89 | - label: themes 90 | sync: true 91 | matcher: 92 | files: src/themes/**/* 93 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ master ] 17 | pull_request: 18 | branches: [ master ] 19 | schedule: 20 | - cron: '26 15 * * 2' 21 | 22 | jobs: 23 | analyze: 24 | name: Analyze 25 | runs-on: ubuntu-latest 26 | timeout-minutes: 20 27 | permissions: 28 | actions: read 29 | contents: read 30 | security-events: write 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | language: [ 'javascript' ] 36 | 37 | steps: 38 | - name: Checkout repository 39 | uses: actions/checkout@v3 40 | 41 | - name: Initialize CodeQL 42 | uses: github/codeql-action/init@v2 43 | with: 44 | languages: ${{ matrix.language }} 45 | 46 | - name: Perform CodeQL Analysis 47 | uses: github/codeql-action/analyze@v2 48 | -------------------------------------------------------------------------------- /.github/workflows/labeler.yml: -------------------------------------------------------------------------------- 1 | on: 2 | pull_request_target: 3 | 4 | jobs: 5 | labeler: 6 | name: Labeler 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: fuxingloh/multi-labeler@v2 10 | -------------------------------------------------------------------------------- /.github/workflows/node.js.yml: -------------------------------------------------------------------------------- 1 | name: Node.js CI 2 | on: 3 | push: 4 | branches: 5 | - master 6 | pull_request: 7 | branches: 8 | - master 9 | 10 | env: 11 | FORCE_COLOR: 1 12 | 13 | jobs: 14 | build: 15 | runs-on: ubuntu-latest 16 | timeout-minutes: 10 17 | steps: 18 | - uses: actions/checkout@v3 19 | - uses: actions/setup-node@v3 20 | with: 21 | node-version: 18 22 | cache: 'npm' 23 | - run: npm -v 24 | - run: npm ci 25 | - run: npm t 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | sceditor.sublime-project 2 | sceditor.sublime-workspace 3 | /.vscode 4 | /node_modules 5 | /distributable 6 | /dist 7 | /minified 8 | /docs 9 | /coverage 10 | .DS_Store 11 | /codetests -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (C) 2011-2016 by Sam Clarke and contributors 4 | http://www.sceditor.com/ 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | The latest version is supported. 6 | 7 | ## Reporting a Vulnerability 8 | 9 | If you find or suspect a security vulnerability, please report by sending an email to sam@samclarke.com. 10 | 11 | If possible, please include "Security vulnerability report:" in the subject line. 12 | -------------------------------------------------------------------------------- /emoticons/alien.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/emoticons/alien.png -------------------------------------------------------------------------------- /emoticons/angel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/emoticons/angel.png -------------------------------------------------------------------------------- /emoticons/angry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/emoticons/angry.png -------------------------------------------------------------------------------- /emoticons/blink.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/emoticons/blink.png -------------------------------------------------------------------------------- /emoticons/blush.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/emoticons/blush.png -------------------------------------------------------------------------------- /emoticons/cheerful.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/emoticons/cheerful.png -------------------------------------------------------------------------------- /emoticons/cool.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/emoticons/cool.png -------------------------------------------------------------------------------- /emoticons/credits.txt: -------------------------------------------------------------------------------- 1 | Presenting, Nomicons: The Full Monty :o 2 | 3 | Credits: 4 | Oscar Gruno, aka Nominell v. 2.0 -> oscargruno@mac.com 5 | Andy Fedosjeenko, aka Nightwolf -> bobo@animevanguard.com 6 | 7 | Copyright (C) 2001-Infinity, Oscar Gruno & Andy Fedosjeenko 8 | 9 | You can redistribute these files as much as you like, as long as you keep this file with them and give us the proper credit. You may even rape them if you please, just give us credit for our work. -------------------------------------------------------------------------------- /emoticons/cwy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/emoticons/cwy.png -------------------------------------------------------------------------------- /emoticons/devil.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/emoticons/devil.png -------------------------------------------------------------------------------- /emoticons/dizzy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/emoticons/dizzy.png -------------------------------------------------------------------------------- /emoticons/ermm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/emoticons/ermm.png -------------------------------------------------------------------------------- /emoticons/face.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/emoticons/face.png -------------------------------------------------------------------------------- /emoticons/getlost.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/emoticons/getlost.png -------------------------------------------------------------------------------- /emoticons/grin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/emoticons/grin.png -------------------------------------------------------------------------------- /emoticons/happy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/emoticons/happy.png -------------------------------------------------------------------------------- /emoticons/heart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/emoticons/heart.png -------------------------------------------------------------------------------- /emoticons/kissing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/emoticons/kissing.png -------------------------------------------------------------------------------- /emoticons/laughing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/emoticons/laughing.png -------------------------------------------------------------------------------- /emoticons/ninja.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/emoticons/ninja.png -------------------------------------------------------------------------------- /emoticons/pinch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/emoticons/pinch.png -------------------------------------------------------------------------------- /emoticons/pouty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/emoticons/pouty.png -------------------------------------------------------------------------------- /emoticons/sad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/emoticons/sad.png -------------------------------------------------------------------------------- /emoticons/shocked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/emoticons/shocked.png -------------------------------------------------------------------------------- /emoticons/sick.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/emoticons/sick.png -------------------------------------------------------------------------------- /emoticons/sideways.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/emoticons/sideways.png -------------------------------------------------------------------------------- /emoticons/silly.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/emoticons/silly.png -------------------------------------------------------------------------------- /emoticons/sleeping.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/emoticons/sleeping.png -------------------------------------------------------------------------------- /emoticons/smile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/emoticons/smile.png -------------------------------------------------------------------------------- /emoticons/tongue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/emoticons/tongue.png -------------------------------------------------------------------------------- /emoticons/unsure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/emoticons/unsure.png -------------------------------------------------------------------------------- /emoticons/w00t.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/emoticons/w00t.png -------------------------------------------------------------------------------- /emoticons/wassat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/emoticons/wassat.png -------------------------------------------------------------------------------- /emoticons/whistling.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/emoticons/whistling.png -------------------------------------------------------------------------------- /emoticons/wink.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/emoticons/wink.png -------------------------------------------------------------------------------- /emoticons/wub.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/emoticons/wub.png -------------------------------------------------------------------------------- /example/emoticons/alien.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/example/emoticons/alien.png -------------------------------------------------------------------------------- /example/emoticons/angel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/example/emoticons/angel.png -------------------------------------------------------------------------------- /example/emoticons/angry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/example/emoticons/angry.png -------------------------------------------------------------------------------- /example/emoticons/blink.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/example/emoticons/blink.png -------------------------------------------------------------------------------- /example/emoticons/blush.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/example/emoticons/blush.png -------------------------------------------------------------------------------- /example/emoticons/cheerful.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/example/emoticons/cheerful.png -------------------------------------------------------------------------------- /example/emoticons/cool.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/example/emoticons/cool.png -------------------------------------------------------------------------------- /example/emoticons/credits.txt: -------------------------------------------------------------------------------- 1 | Presenting, Nomicons: The Full Monty :o 2 | 3 | Credits: 4 | Oscar Gruno, aka Nominell v. 2.0 -> oscargruno@mac.com 5 | Andy Fedosjeenko, aka Nightwolf -> bobo@animevanguard.com 6 | 7 | Copyright (C) 2001-Infinity, Oscar Gruno & Andy Fedosjeenko 8 | 9 | You can redistribute these files as much as you like, as long as you keep this file with them and give us the proper credit. You may even rape them if you please, just give us credit for our work. -------------------------------------------------------------------------------- /example/emoticons/cwy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/example/emoticons/cwy.png -------------------------------------------------------------------------------- /example/emoticons/devil.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/example/emoticons/devil.png -------------------------------------------------------------------------------- /example/emoticons/dizzy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/example/emoticons/dizzy.png -------------------------------------------------------------------------------- /example/emoticons/ermm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/example/emoticons/ermm.png -------------------------------------------------------------------------------- /example/emoticons/face.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/example/emoticons/face.png -------------------------------------------------------------------------------- /example/emoticons/getlost.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/example/emoticons/getlost.png -------------------------------------------------------------------------------- /example/emoticons/grin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/example/emoticons/grin.png -------------------------------------------------------------------------------- /example/emoticons/happy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/example/emoticons/happy.png -------------------------------------------------------------------------------- /example/emoticons/heart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/example/emoticons/heart.png -------------------------------------------------------------------------------- /example/emoticons/kissing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/example/emoticons/kissing.png -------------------------------------------------------------------------------- /example/emoticons/laughing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/example/emoticons/laughing.png -------------------------------------------------------------------------------- /example/emoticons/ninja.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/example/emoticons/ninja.png -------------------------------------------------------------------------------- /example/emoticons/pinch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/example/emoticons/pinch.png -------------------------------------------------------------------------------- /example/emoticons/pouty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/example/emoticons/pouty.png -------------------------------------------------------------------------------- /example/emoticons/sad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/example/emoticons/sad.png -------------------------------------------------------------------------------- /example/emoticons/shocked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/example/emoticons/shocked.png -------------------------------------------------------------------------------- /example/emoticons/sick.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/example/emoticons/sick.png -------------------------------------------------------------------------------- /example/emoticons/sideways.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/example/emoticons/sideways.png -------------------------------------------------------------------------------- /example/emoticons/silly.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/example/emoticons/silly.png -------------------------------------------------------------------------------- /example/emoticons/sleeping.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/example/emoticons/sleeping.png -------------------------------------------------------------------------------- /example/emoticons/smile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/example/emoticons/smile.png -------------------------------------------------------------------------------- /example/emoticons/tongue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/example/emoticons/tongue.png -------------------------------------------------------------------------------- /example/emoticons/unsure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/example/emoticons/unsure.png -------------------------------------------------------------------------------- /example/emoticons/w00t.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/example/emoticons/w00t.png -------------------------------------------------------------------------------- /example/emoticons/wassat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/example/emoticons/wassat.png -------------------------------------------------------------------------------- /example/emoticons/whistling.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/example/emoticons/whistling.png -------------------------------------------------------------------------------- /example/emoticons/wink.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/example/emoticons/wink.png -------------------------------------------------------------------------------- /example/emoticons/wub.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/example/emoticons/wub.png -------------------------------------------------------------------------------- /example/example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 |SCEditor is licensed under the MIT
90 | 91 | 92 | -------------------------------------------------------------------------------- /languages/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "parserOptions": { 3 | "sourceType": "script" 4 | }, 5 | "rules": { 6 | "dot-notation": "off", 7 | "max-len": ["error", { 8 | "code": 400, 9 | "ignoreUrls": true, 10 | "ignoreRegExpLiterals": true 11 | }] 12 | } 13 | } -------------------------------------------------------------------------------- /languages/ar.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Atramez_Zeton http://onyx-sy.net 3 | * @license [MIT](http://www.opensource.org/licenses/mit-license.php) 4 | */ 5 | (function () { 6 | 'use strict'; 7 | 8 | sceditor.locale['ar'] = { 9 | 'Bold': 'عريض', 10 | 'Italic': 'مائل', 11 | 'Underline': 'خط من الأسفل', 12 | 'Strikethrough': 'خط في المنتصف', 13 | 'Subscript': 'حرف منخفض', 14 | 'Superscript': 'حرف مرتفع', 15 | 'Align left': 'انحياز إلى اليسار', 16 | 'Center': 'توسط', 17 | 'Align right': 'انحياز إالى اليمين', 18 | 'Justify': 'ملأ السطر', 19 | 'Font Name': 'نوع الخط', 20 | 'Font Size': 'حجم الخط', 21 | 'Font Color': 'لون الخط', 22 | 'Remove Formatting': 'ازالة التعديلات', 23 | 'Cut': 'قص', 24 | 'Your browser does not allow the cut command. Please use the keyboard shortcut Ctrl/Cmd-X': 'Ctrl/Cmd-X متصفحك لا يدعم اوامر القص الرجاء استخدام اختصارات لوحة التحكم', 25 | 'Copy': 'نسخ', 26 | 'Your browser does not allow the copy command. Please use the keyboard shortcut Ctrl/Cmd-C': 'Ctrl/Cmd-C متصفحك لا يدعم اوامر النسخ الرجاء استخدام اختصارات لوحة التحكم', 27 | 'Paste': 'لصق', 28 | 'Your browser does not allow the paste command. Please use the keyboard shortcut Ctrl/Cmd-V': 'Ctrl/Cmd-V متصفحك لا يدعم اوامر اللصق الرجاء استخدام اختصارات لوحة التحكم', 29 | 'Paste your text inside the following box:': 'قم بلصق نصّك في المربع', 30 | 'Paste Text': 'الصق النص', 31 | 'Bullet list': 'قائمة نقطية', 32 | 'Numbered list': 'قائمة مرقمة', 33 | 'Undo': 'تراجع', 34 | 'Redo': 'تقدم', 35 | 'Rows:': 'اسطر', 36 | 'Cols:': 'اعمدة', 37 | 'Insert a table': 'ادرج جدول', 38 | 'Insert a horizontal rule': 'ادرج مسطرة افقية', 39 | 'Code': 'كود', 40 | 'Width (optional):': 'عرض (اختياري)', 41 | 'Height (optional):': 'ارتفاع (اختياري)', 42 | 'Insert an image': 'ادرج صورة', 43 | 'E-mail:': 'بريد الكتروني', 44 | 'Insert an email': 'ادرج بريدا الكترونيا', 45 | 'URL:': 'وصلة موقع', 46 | 'Insert a link': 'ادرج وصلة لموقع', 47 | 'Unlink': 'ازالة الوصلة', 48 | 'More': 'المزيد', 49 | 'Insert an emoticon': 'ادرج وجها', 50 | 'Video URL:': 'وصلة فيديو', 51 | 'Insert': 'ادرج', 52 | 'Insert a YouTube video': 'ادرج وصلة فيديو يوتيوب', 53 | 'Insert current date': 'ادرج التاريخ الحالي', 54 | 'Insert current time': 'ادرج الوقت الحالي', 55 | 'Print': 'اطبع', 56 | 'View source': 'اظهر المصدر', 57 | 'Description (optional):': 'الوصف (اختياري)', 58 | 'Enter the image URL:': 'ضع وصلة الصورة', 59 | 'Enter the e-mail address:': 'ضع عنوان البريد الإلكتروني', 60 | 'Enter the displayed text:': 'ضع النص الذي تريد اظهاره', 61 | 'Enter URL:': 'ضع وصلة موقع', 62 | 'Enter the YouTube video URL or ID:': 'ضع وصلة فيديو يوتيوب او رقم الفيديو', 63 | 'Insert a Quote': 'ادرج اقتباسا', 64 | 'Invalid YouTube video': 'هذا الفيديو غير صالح', 65 | 66 | dateFormat: 'day-month-year' 67 | }; 68 | })(); 69 | -------------------------------------------------------------------------------- /languages/ca.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Fran Sobrino 3 | * @license [MIT](http://www.opensource.org/licenses/mit-license.php) 4 | */ 5 | (function () { 6 | 'use strict'; 7 | 8 | sceditor.locale['ca'] = { 9 | 'Bold': 'Negrita', 10 | 'Italic': 'Cursiva', 11 | 'Underline': 'Subratlla', 12 | 'Strikethrough': 'Ratllar', 13 | 'Subscript': 'Sub\u00edndice', 14 | 'Superscript': 'Super\u00edndice', 15 | 'Align left': 'Alinear a l\'Esquerra', 16 | 'Center': 'Centrar', 17 | 'Align right': 'Alinear a la dreta', 18 | 'Justify': 'Justificar', 19 | 'Font Name': 'Tipus de Lletra', 20 | 'Font Size': 'Mida de Lletra', 21 | 'Font Color': 'Color de Font', 22 | 'Remove Formatting': 'Treure Formats', 23 | 'Cut': 'Tallar', 24 | 'Your browser does not allow the cut command. Please use the keyboard shortcut Ctrl/Cmd-X': 'O seu navegador non acepta o comando cortar. Por favor, empregue a combinaci\u00f3n Ctrl/Cmd-X', 25 | 'Copy': 'Copiar', 26 | 'Your browser does not allow the copy command. Please use the keyboard shortcut Ctrl/Cmd-C': 'O seu navegador non acepta o comando cortar. Por favor, empregue a combinaci\u00f3n Ctrl/Cmd-C', 27 | 'Paste': 'Pegar', 28 | 'Your browser does not allow the paste command. Please use the keyboard shortcut Ctrl/Cmd-V': 'O seu navegador non acepta o comando cortar. Por favor, empregue a combinaci\u00f3n Ctrl/Cmd-V', 29 | 'Paste your text inside the following box:': 'Pega o texto dentro do seguinte recadro', 30 | 'Paste Text': 'Pegar Texto', 31 | 'Bullet list': 'Llista d\'Vinyetes', 32 | 'Numbered list': 'Llista numerada', 33 | 'Undo': 'Desfer', 34 | 'Redo': 'Refer', 35 | 'Rows:': 'Files', 36 | 'Cols:': 'Columnes', 37 | 'Insert a table': 'Inserir una taula', 38 | 'Insert a horizontal rule': 'Insereix una Regla horitzontal', 39 | 'Code': 'C\u00f3digo', 40 | 'Width (optional):': 'Ample (Opcional)', 41 | 'Height (optional):': 'Alçada (Opcional)', 42 | 'Insert an image': 'Insereix una imatge', 43 | 'E-mail:': 'Correu electrònic', 44 | 'Insert an email': 'Insereix un Email', 45 | 'URL:': 'URL', 46 | 'Insert a link': 'Inserir un enllaç', 47 | 'Unlink': 'Treure un enllaç', 48 | 'More': 'Més', 49 | 'Insert an emoticon': 'Inserir un emoticon', 50 | 'Video URL:': 'URL del V\u00eddeo', 51 | 'Insert': 'Insereix', 52 | 'Insert a YouTube video': 'Insereix un v\u00eddeo de YouTube', 53 | 'Insert current date': 'Insereix data actual', 54 | 'Insert current time': 'Insereix hora actual', 55 | 'Print': 'Imprimir', 56 | 'View source': 'Veure C\u00f3digo', 57 | 'Description (optional):': 'Descripci\u00f3 (Opcional):', 58 | 'Enter the image URL:': 'Ingressar la URL de la imatge:', 59 | 'Enter the e-mail address:': 'Ingressar el correu electr\u00f3nico:', 60 | 'Enter the displayed text:': 'Ingressar el texto mostrat:', 61 | 'Enter URL:': 'Entrada URL:', 62 | 'Enter the YouTube video URL or ID:': 'Entrada URL ou ID de YouTube', 63 | 'Insert a Quote': 'v Insereix', 64 | 'Invalid YouTube video': 'V\u00eddeo de YouTube Inv\u00e1lido', 65 | 66 | dateFormat: 'day-month-year' 67 | }; 68 | })(); 69 | -------------------------------------------------------------------------------- /languages/cn.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author with the language code, e.g. no, fr, en, ect.
9 | sceditor.locale[''] = {
10 |
11 | // Original string is on the left, place the translation between
12 | // the quotes on the right
13 | 'Bold': '',
14 | 'Italic': '',
15 | 'Underline': '',
16 | 'Strikethrough': '',
17 | 'Subscript': '',
18 | 'Superscript': '',
19 | 'Align left': '',
20 | 'Center': '',
21 | 'Align right': '',
22 | 'Justify': '',
23 | 'Font Name': '',
24 | 'Font Size': '',
25 | 'Font Color': '',
26 | 'Remove Formatting': '',
27 | 'Cut': '',
28 | 'Your browser does not allow the cut command. Please use the keyboard shortcut Ctrl/Cmd-X': '',
29 | 'Copy': '',
30 | 'Your browser does not allow the copy command. Please use the keyboard shortcut Ctrl/Cmd-C': '',
31 | 'Paste': '',
32 | 'Your browser does not allow the paste command. Please use the keyboard shortcut Ctrl/Cmd-V': '',
33 | 'Paste your text inside the following box:': '',
34 | 'Paste Text': '',
35 | 'Bullet list': '',
36 | 'Numbered list': '',
37 | 'Add indent': '',
38 | 'Remove one indent': '',
39 | 'Undo': '',
40 | 'Redo': '',
41 | 'Rows:': '',
42 | 'Cols:': '',
43 | 'Insert a table': '',
44 | 'Insert a horizontal rule': '',
45 | 'Code': '',
46 | 'Width (optional):': '',
47 | 'Height (optional):': '',
48 | 'Insert an image': '',
49 | 'E-mail:': '',
50 | 'Insert an email': '',
51 | 'URL:': '',
52 | 'Insert a link': '',
53 | 'Unlink': '',
54 | 'More': '',
55 | 'Insert an emoticon': '',
56 | 'Video URL:': '',
57 | 'Insert': '',
58 | 'Insert a YouTube video': '',
59 | 'Insert current date': '',
60 | 'Insert current time': '',
61 | 'Print': '',
62 | 'Maximize': '',
63 | 'View source': '',
64 | 'Description (optional):': '',
65 | 'Enter the image URL:': '',
66 | 'Enter the e-mail address:': '',
67 | 'Enter the displayed text:': '',
68 | 'Enter URL:': '',
69 | 'Enter the YouTube video URL or ID:': '',
70 | 'Insert a Quote': '',
71 | 'Invalid YouTube video': '',
72 | 'Drop files here': '',
73 | 'Left-to-Right': '',
74 | 'Right-to-Left': '',
75 |
76 | // month format, replace - with the date format separator and order in the
77 | // order used
78 | dateFormat: 'day-month-year'
79 | };
80 | })();
81 |
--------------------------------------------------------------------------------
/languages/tr.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author Mahmut Yaman - iletisim@/m-yaman.com
3 | * @license [MIT](http://www.opensource.org/licenses/mit-license.php)
4 | */
5 | (function () {
6 | 'use strict';
7 | sceditor.locale['tr'] = {
8 | 'Bold': 'Kalın',
9 | 'Italic': 'İtalik',
10 | 'Underline': 'Altı çizgili',
11 | 'Strikethrough': 'Üstü çizgili',
12 | 'Subscript': 'Simge',
13 | 'Superscript': 'Üstsimge',
14 | 'Align left': 'Sola yasla',
15 | 'Center': 'Ortala',
16 | 'Align right': 'Sağa yasla',
17 | 'Justify': 'Satır uzunluğuna ayarla',
18 | 'Font Name': 'Yazı tipi',
19 | 'Font Size': 'Yazı boyutu',
20 | 'Font Color': 'Yazı rengi',
21 | 'Remove Formatting': 'Biçimlendirmeyi temizle',
22 | 'Cut': 'Kes',
23 | 'Your browser does not allow the cut command. Please use the keyboard shortcut Ctrl/Cmd-X': 'Tarayıcınız kesme komutuna izin vermiyor. Lütfen Ctrl/Cmd-X klavye kısayolunu kullanın.',
24 | 'Copy': 'Kopyala',
25 | 'Your browser does not allow the copy command. Please use the keyboard shortcut Ctrl/Cmd-C': 'Tarayıcınız kopyalama komutuna izin vermiyor. Lütfen Ctrl/Cmd-C klavye kısayolunu kullanın.',
26 | 'Paste': 'Yapıştır',
27 | 'Your browser does not allow the paste command. Please use the keyboard shortcut Ctrl/Cmd-V': 'Tarayıcınız yapıştırma komutuna izin vermiyor. Lütfen Ctrl/Cmd-V klavye kısayolunu kullanın.',
28 | 'Paste your text inside the following box:': 'Yazınızı bu kutucuğa yapıştırın:',
29 | 'Paste Text': 'Metin Yapıştır',
30 | 'Bullet list': 'Madde işaretli liste',
31 | 'Numbered list': 'Numaralı liste',
32 | 'Undo': 'Geri al',
33 | 'Redo': 'Yinele',
34 | 'Rows:': 'Sütun:',
35 | 'Cols:': 'Kolon:',
36 | 'Insert a table': 'Tablo ekle',
37 | 'Insert a horizontal rule': 'Yatay ayraç ekle',
38 | 'Code': 'Kod',
39 | 'Width (optional):': 'Genişlik (opsiyonel):',
40 | 'Height (optional):': 'Yükseklik (opsiyonel):',
41 | 'Insert an image': 'Resim ekle',
42 | 'E-mail:': 'E-posta:',
43 | 'Insert an email': 'E-posta ekle',
44 | 'URL:': 'URL:',
45 | 'Insert a link': 'Bağlantı ekle',
46 | 'Unlink': 'Bağlantıyı kaldır',
47 | 'More': 'Daha fazla',
48 | 'Insert an emoticon': 'Yüz ifadesi ekle',
49 | 'Video URL:': 'Video URL:',
50 | 'Insert': 'Ekle',
51 | 'Insert a YouTube video': 'YouTube videosu ekle',
52 | 'Insert current date': 'Şuanki tarihi ekle',
53 | 'Insert current time': 'Şuanki saati ekle',
54 | 'Print': 'Yazdır',
55 | 'View source': 'Kaynağı görüntüle',
56 | 'Description (optional):': 'Açıklama (opsiyonel):',
57 | 'Enter the image URL:': 'Resim URL\'sini girin:',
58 | 'Enter the e-mail address:': 'E-posta adresini girin:',
59 | 'Enter the displayed text:': 'Görünecek yazıyı girin:',
60 | 'Enter URL:': 'URL\'yi girin:',
61 | 'Enter the YouTube video URL or ID:': 'YouTube video URL\'sini yada ID\'sini girin:',
62 | 'Insert a Quote': 'Alıntı ekle',
63 | 'Invalid YouTube video': 'Geçersiz YouTube videosu',
64 | dateFormat: 'day-month-year'
65 | };
66 | })();
67 |
--------------------------------------------------------------------------------
/languages/tw.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author
3 | * @license [MIT](http://www.opensource.org/licenses/mit-license.php)
4 | */
5 | (function () {
6 | 'use strict';
7 |
8 | sceditor.locale['tw'] = {
9 | 'Bold': '粗體',
10 | 'Italic': '斜體',
11 | 'Underline': '底線',
12 | 'Strikethrough': '删除線',
13 | 'Subscript': '下標',
14 | 'Superscript': '上標',
15 | 'Align left': '靠左對齊',
16 | 'Center': '置中',
17 | 'Align right': '靠右對齊',
18 | 'Justify': '兩端對齊',
19 | 'Font Name': '字形',
20 | 'Font Size': '字體大小',
21 | 'Font Color': '文字顏色',
22 | 'Remove Formatting': '清除格式',
23 | 'Cut': '剪下',
24 | 'Your browser does not allow the cut command. Please use the keyboard shortcut Ctrl/Cmd-X': '您的瀏覽器不支持剪下命令,請使用快速键 Ctrl/Cmd-X',
25 | 'Copy': '拷貝',
26 | 'Your browser does not allow the copy command. Please use the keyboard shortcut Ctrl/Cmd-C': '您的瀏覽器不支持拷貝命令,請使用快速键 Ctrl/Cmd-C',
27 | 'Paste': '貼上',
28 | 'Your browser does not allow the paste command. Please use the keyboard shortcut Ctrl/Cmd-V': '您的瀏覽器不支持貼上命令,請使用快速键 Ctrl/Cmd-V',
29 | 'Paste your text inside the following box:': '請在下面貼上您的文字',
30 | 'Paste Text': '貼上纯文字',
31 | 'Bullet list': '符號列表',
32 | 'Numbered list': '编號列表',
33 | 'Undo': '復原',
34 | 'Redo': '重做',
35 | 'Rows:': '行數',
36 | 'Cols:': '列數',
37 | 'Insert a table': '插入表格',
38 | 'Insert a horizontal rule': '插入分隔線',
39 | 'Code': '原始碼',
40 | 'Width (optional):': '寬度(選填)',
41 | 'Height (optional):': '高度(選填)',
42 | 'Insert an image': '插入圖片',
43 | 'E-mail:': 'Email',
44 | 'Insert an email': '插入Email',
45 | 'URL:': '網址',
46 | 'Insert a link': '插入超鏈結',
47 | 'Unlink': '取消超鏈結',
48 | 'More': '更多',
49 | 'Insert an emoticon': '插入表情符號',
50 | 'Video URL:': '影片網址',
51 | 'Insert': '插入',
52 | 'Insert a YouTube video': '插入 YouTube 影片',
53 | 'Insert current date': '插入目前日期',
54 | 'Insert current time': '插入目前時間',
55 | 'Print': '列印',
56 | 'View source': '查看原始碼',
57 | 'Description (optional):': '描述(選填)',
58 | 'Enter the image URL:': '輸入圖片網址',
59 | 'Enter the e-mail address:': '輸入 Email',
60 | 'Enter the displayed text:': '輸入顯示文字',
61 | 'Enter URL:': '輸入網址',
62 | 'Enter the YouTube video URL or ID:': '輸入 YouTube 網址或影片编號',
63 | 'Insert a Quote': '插入引用',
64 | 'Invalid YouTube video': '無效的YouTube影片',
65 |
66 | dateFormat: 'year-month-day'
67 | };
68 | })();
69 |
--------------------------------------------------------------------------------
/languages/uk.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | 'use strict';
3 |
4 | sceditor.locale['uk'] = {
5 | 'Bold': 'Жирний',
6 | 'Italic': 'Курсив',
7 | 'Underline': 'Підкреслений',
8 | 'Strikethrough': 'Закреслений',
9 | 'Subscript': 'Нижній індекс',
10 | 'Superscript': 'Верхній індекс',
11 | 'Align left': 'Вирівняти по лівому краю',
12 | 'Center': 'Вирівняти по центру',
13 | 'Align right': 'Вирівняти по правому краю',
14 | 'Justify': 'Вирівняти по ширині',
15 | 'Font Name': 'Шрифт',
16 | 'Font Size': 'Розмір шрифту',
17 | 'Font Color': 'Колір шрифту',
18 | 'Remove Formatting': 'Видалити форматування',
19 | 'Cut': 'Вирізати',
20 | 'Your browser does not allow the cut command. Please use the keyboard shortcut Ctrl/Cmd-X': 'Ваш браузер не дозволяє виконати цю команду. Будь ласка, використовуйте комбінацію клавіш Ctrl/Cmd-X',
21 | 'Copy': 'Копіювати',
22 | 'Your browser does not allow the copy command. Please use the keyboard shortcut Ctrl/Cmd-C': 'Ваш браузер не дозволяє виконати цю команду. Будь ласка, використовуйте комбінацію клавіш Ctrl/Cmd-C',
23 | 'Paste': 'Вставити',
24 | 'Your browser does not allow the paste command. Please use the keyboard shortcut Ctrl/Cmd-V': 'Ваш браузер не дозволяє виконати цю команду. Будь ласка, використовуйте комбінацію клавіш Ctrl/Cmd-V',
25 | 'Paste your text inside the following box:': 'Вставте текст у наступне вікно:',
26 | 'Paste Text': 'Вставити текст',
27 | 'Bullet list': 'Маркований список',
28 | 'Numbered list': 'Нумерований список',
29 | 'Undo': 'Відмінити',
30 | 'Redo': 'Повторити',
31 | 'Rows:': 'Рядків:',
32 | 'Cols:': 'Cтовпців:',
33 | 'Insert a table': 'Додати таблицю',
34 | 'Insert a horizontal rule': 'Додати горизонтальну лінію',
35 | 'Code': 'Код',
36 | 'Insert a Quote': 'Додати цитату',
37 | 'Width (optional):': 'Ширина (необов\'язково):',
38 | 'Height (optional):': 'Висота (необов\'язково):',
39 | 'Insert an image': 'Додати зображення',
40 | 'E-mail:': 'E-mail:',
41 | 'Insert an email': 'Додати E-mail',
42 | 'URL:': 'URL:',
43 | 'Insert a link': 'Додати посилання',
44 | 'Unlink': 'Видалити посилання',
45 | 'More': 'Більше',
46 | 'Insert an emoticon': 'Додати смайлик',
47 | 'Video URL:': 'URL відео:',
48 | 'Insert': 'Вставити',
49 | 'Insert a YouTube video': 'Додати відео з YouTube',
50 | 'Insert current date': 'Додати дату',
51 | 'Insert current time': 'Додати час',
52 | 'Print': 'Надрукувати',
53 | 'View source': 'Показати код',
54 | 'Maximize': 'Розгорнути редактор',
55 | dateFormat: 'day.month.year'
56 | };
57 | })();
58 |
--------------------------------------------------------------------------------
/languages/vi.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author Chien
3 | * @license [MIT](http://www.opensource.org/licenses/mit-license.php)
4 | */
5 | (function () {
6 | 'use strict';
7 |
8 | sceditor.locale['vi'] = {
9 | 'Bold': 'Đậm',
10 | 'Italic': 'Nghiêng',
11 | 'Underline': 'Gạch chân',
12 | 'Strikethrough': 'Gạch giữa',
13 | 'Subscript': 'Hệ số',
14 | 'Superscript': 'Mũ',
15 | 'Align left': 'Căn trái',
16 | 'Center': 'Căn giữa',
17 | 'Align right': 'Căn phải',
18 | 'Justify': 'Căn đều',
19 | 'Font Name': 'Phông chữ',
20 | 'Font Size': 'Cỡ chữ',
21 | 'Font Color': 'Màu chữ',
22 | 'Remove Formatting': 'Xóa định dạng',
23 | 'Cut': 'Cắt',
24 | 'Your browser does not allow the cut command. Please use the keyboard shortcut Ctrl/Cmd-X': 'Trình duyệt không cho phép sử dụng lệnh Cut. Vui lòng sử dụng phím tắt Ctrl/Cmd-X',
25 | 'Copy': 'Sao chép',
26 | 'Your browser does not allow the copy command. Please use the keyboard shortcut Ctrl/Cmd-C': 'Trình duyệt không cho phép sử dụng lệnh Copy. Vui lòng sử dụng phím tắt Ctrl/Cmd-C',
27 | 'Paste': 'Chép vào',
28 | 'Your browser does not allow the paste command. Please use the keyboard shortcut Ctrl/Cmd-V': 'Trình duyệt không cho phép sử dụng lệnh Paste. Vui lòng sử dụng phím tắt Ctrl/Cmd-V',
29 | 'Paste your text inside the following box:': 'Chép nội dung text vào khung sau',
30 | 'Paste Text': 'Chép nội dung text',
31 | 'Bullet list': 'Danh sách kiểu nốt',
32 | 'Numbered list': 'Danh sách kiểu số',
33 | 'Undo': 'Hủy bỏ',
34 | 'Redo': 'Trở lại bước trước',
35 | 'Rows:': 'Số dòng',
36 | 'Cols:': 'Số cột',
37 | 'Insert a table': 'Thêm bảng',
38 | 'Insert a horizontal rule': 'Thêm thước ngang',
39 | 'Code': 'Mã code',
40 | 'Width (optional):': 'Dài (không bắt buộc)',
41 | 'Height (optional):': 'Rộng (không bắt buộc)',
42 | 'Insert an image': 'Chèn hình ảnh',
43 | 'E-mail:': 'E-mail',
44 | 'Insert an email': 'Chèn email',
45 | 'URL:': 'Liên kết',
46 | 'Insert a link': 'Chèn liên kết',
47 | 'Unlink': 'Bỏ liên kết',
48 | 'More': 'Xem thêm',
49 | 'Insert an emoticon': 'Chèn biểu tượng',
50 | 'Video URL:': 'Đường dẫn của Video',
51 | 'Insert': 'Thêm vào',
52 | 'Insert a YouTube video': 'Chèn Youtube',
53 | 'Insert current date': 'Chèn ngày hiện tại',
54 | 'Insert current time': 'Chèn thời gian hiện tại',
55 | 'Print': 'In ấn',
56 | 'View source': 'Xem mã nguồn',
57 | 'Description (optional):': 'Mô tả (không bắt buộc)',
58 | 'Enter the image URL:': 'Nhập vào đường dẫn của hình ảnh',
59 | 'Enter the e-mail address:': 'Nhập vào địa chỉ email',
60 | 'Enter the displayed text:': 'Nhập vào nội dung hiển thị',
61 | 'Enter URL:': 'Nhập vào liên kết',
62 | 'Enter the YouTube video URL or ID:': 'Nhập vào liên kết của video hoặc ID trên Youtube',
63 | 'Insert a Quote': 'Chèn trích dẫn',
64 | 'Invalid YouTube video': 'Video Youtube không chính xác',
65 |
66 | dateFormat: 'day/month/year'
67 | };
68 | })();
69 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "sceditor",
3 | "version": "3.2.0",
4 | "description": "A lightweight HTML and BBCode WYSIWYG editor.",
5 | "homepage": "http://www.sceditor.com/",
6 | "bugs": "https://github.com/samclarke/SCEditor/issues",
7 | "license": "MIT",
8 | "author": "Sam Clarke ",
9 | "contributors": [
10 | {
11 | "name": "brunoais"
12 | }
13 | ],
14 | "files": [
15 | "emoticons/",
16 | "languages/",
17 | "development/",
18 | "minified/",
19 | "src/",
20 | "CHANGELOG.txt",
21 | "LICENSE.md",
22 | "README.md"
23 | ],
24 | "repository": {
25 | "type": "git",
26 | "url": "https://github.com/samclarke/SCEditor.git"
27 | },
28 | "keywords": [
29 | "jquery-plugin",
30 | "WYSIWYG",
31 | "BBCode",
32 | "editor",
33 | "contenteditable",
34 | "jquery",
35 | "ui",
36 | "ecosystem:jquery"
37 | ],
38 | "engines": {
39 | "node": ">= 0.10.0"
40 | },
41 | "browserslist": [
42 | "last 4 versions",
43 | "ie 10"
44 | ],
45 | "scripts": {
46 | "test": "grunt test",
47 | "build": "grunt build",
48 | "release": "grunt release",
49 | "dev": "node ./tests/dev-server.js"
50 | },
51 | "devDependencies": {
52 | "@lodder/grunt-postcss": "^3.1.1",
53 | "@rollup/plugin-node-resolve": "^15.2.1",
54 | "autoprefixer": "^10.4.15",
55 | "cssnano": "^6.0.1",
56 | "grunt": "~1.6.1",
57 | "grunt-contrib-clean": "^2.0.1",
58 | "grunt-contrib-compress": "^2.0.0",
59 | "grunt-contrib-concat": "~2.1.0",
60 | "grunt-contrib-copy": "^1.0.0",
61 | "grunt-contrib-less": "^3.0.0",
62 | "grunt-contrib-qunit": "^7.0.1",
63 | "grunt-contrib-uglify": "^5.2.2",
64 | "grunt-eslint": "^24.3.0",
65 | "grunt-rollup": "^12.0.0",
66 | "istanbul-lib-coverage": "^3.2.0",
67 | "istanbul-lib-instrument": "^6.0.0",
68 | "istanbul-lib-report": "^3.0.1",
69 | "istanbul-reports": "^3.1.6",
70 | "jquery": "^3.7.0",
71 | "less": "^4.2.0",
72 | "loader-utils": "^3.2.1",
73 | "qunit": "^2.19.4",
74 | "rangy": "^1.3.1",
75 | "sinon": "^15.2.0",
76 | "time-grunt": "^2.0.0",
77 | "webpack": "^5.88.2",
78 | "webpack-dev-server": "^4.15.1"
79 | },
80 | "dependencies": {
81 | "dompurify": "^3.0.5"
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/src/formats/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "parserOptions": {
3 | "sourceType": "script"
4 | }
5 | }
--------------------------------------------------------------------------------
/src/icons/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "parserOptions": {
3 | "sourceType": "script"
4 | }
5 | }
--------------------------------------------------------------------------------
/src/jquery.sceditor.js:
--------------------------------------------------------------------------------
1 | /**
2 | * SCEditor
3 | * http://www.sceditor.com/
4 | *
5 | * Copyright (C) 2017, Sam Clarke (samclarke.com)
6 | *
7 | * SCEditor is licensed under the MIT license:
8 | * http://www.opensource.org/licenses/mit-license.php
9 | *
10 | * @fileoverview SCEditor - A lightweight WYSIWYG BBCode and HTML editor
11 | * @author Sam Clarke
12 | * @requires jQuery
13 | */
14 |
15 | import $ from 'jquery';
16 | import './sceditor.js';
17 |
18 |
19 | // For backwards compatibility
20 | $.sceditor = window.sceditor;
21 |
22 | /**
23 | * Creates an instance of sceditor on all textareas
24 | * matched by the jQuery selector.
25 | *
26 | * If options is set to "state" it will return bool value
27 | * indicating if the editor has been initialised on the
28 | * matched textarea(s). If there is only one textarea
29 | * it will return the bool value for that textarea.
30 | * If more than one textarea is matched it will
31 | * return an array of bool values for each textarea.
32 | *
33 | * If options is set to "instance" it will return the
34 | * current editor instance for the textarea(s). Like the
35 | * state option, if only one textarea is matched this will
36 | * return just the instance for that textarea. If more than
37 | * one textarea is matched it will return an array of
38 | * instances each textarea.
39 | *
40 | * @param {Object|string} [options] Should either be an Object of options or
41 | * the strings "state" or "instance"
42 | * @return {this|Array|Array|SCEditor|boolean}
43 | */
44 | $.fn.sceditor = function (options) {
45 | var instance;
46 | var ret = [];
47 |
48 | this.each(function () {
49 | instance = this._sceditor;
50 |
51 | // Add state of instance to ret if that is what options is set to
52 | if (options === 'state') {
53 | ret.push(!!instance);
54 | } else if (options === 'instance') {
55 | ret.push(instance);
56 | } else if (!instance) {
57 | $.sceditor.create(this, options);
58 | }
59 | });
60 |
61 | // If nothing in the ret array then must be init so return this
62 | if (!ret.length) {
63 | return this;
64 | }
65 |
66 | return ret.length === 1 ? ret[0] : ret;
67 | };
68 |
--------------------------------------------------------------------------------
/src/lib/browser.js:
--------------------------------------------------------------------------------
1 | var USER_AGENT = navigator.userAgent;
2 |
3 | /**
4 | * Detects if the browser is iOS
5 | *
6 | * Needed to fix iOS specific bugs
7 | *
8 | * @function
9 | * @name ios
10 | * @memberOf jQuery.sceditor
11 | * @type {boolean}
12 | */
13 | export var ios = /iPhone|iPod|iPad| wosbrowser\//i.test(USER_AGENT);
14 |
15 | /**
16 | * If the browser supports WYSIWYG editing (e.g. older mobile browsers).
17 | *
18 | * @function
19 | * @name isWysiwygSupported
20 | * @return {boolean}
21 | */
22 | export var isWysiwygSupported = (function () {
23 | var match, isUnsupported;
24 |
25 | // IE is the only browser to support documentMode
26 | var ie = !!window.document.documentMode;
27 | var legacyEdge = '-ms-ime-align' in document.documentElement.style;
28 |
29 | var div = document.createElement('div');
30 | div.contentEditable = true;
31 |
32 | // Check if the contentEditable attribute is supported
33 | if (!('contentEditable' in document.documentElement) ||
34 | div.contentEditable !== 'true') {
35 | return false;
36 | }
37 |
38 | // I think blackberry supports contentEditable or will at least
39 | // give a valid value for the contentEditable detection above
40 | // so it isn't included in the below tests.
41 |
42 | // I hate having to do UA sniffing but some mobile browsers say they
43 | // support contentediable when it isn't usable, i.e. you can't enter
44 | // text.
45 | // This is the only way I can think of to detect them which is also how
46 | // every other editor I've seen deals with this issue.
47 |
48 | // Exclude Opera mobile and mini
49 | isUnsupported = /Opera Mobi|Opera Mini/i.test(USER_AGENT);
50 |
51 | if (/Android/i.test(USER_AGENT)) {
52 | isUnsupported = true;
53 |
54 | if (/Safari/.test(USER_AGENT)) {
55 | // Android browser 534+ supports content editable
56 | // This also matches Chrome which supports content editable too
57 | match = /Safari\/(\d+)/.exec(USER_AGENT);
58 | isUnsupported = (!match || !match[1] ? true : match[1] < 534);
59 | }
60 | }
61 |
62 | // The current version of Amazon Silk supports it, older versions didn't
63 | // As it uses webkit like Android, assume it's the same and started
64 | // working at versions >= 534
65 | if (/ Silk\//i.test(USER_AGENT)) {
66 | match = /AppleWebKit\/(\d+)/.exec(USER_AGENT);
67 | isUnsupported = (!match || !match[1] ? true : match[1] < 534);
68 | }
69 |
70 | // iOS 5+ supports content editable
71 | if (ios) {
72 | // Block any version <= 4_x(_x)
73 | isUnsupported = /OS [0-4](_\d)+ like Mac/i.test(USER_AGENT);
74 | }
75 |
76 | // Firefox does support WYSIWYG on mobiles so override
77 | // any previous value if using FF
78 | if (/Firefox/i.test(USER_AGENT)) {
79 | isUnsupported = false;
80 | }
81 |
82 | if (/OneBrowser/i.test(USER_AGENT)) {
83 | isUnsupported = false;
84 | }
85 |
86 | // UCBrowser works but doesn't give a unique user agent
87 | if (navigator.vendor === 'UCWEB') {
88 | isUnsupported = false;
89 | }
90 |
91 | // IE and legacy edge are not supported any more
92 | if (ie || legacyEdge) {
93 | isUnsupported = true;
94 | }
95 |
96 | return !isUnsupported;
97 | }());
98 |
--------------------------------------------------------------------------------
/src/lib/escape.js:
--------------------------------------------------------------------------------
1 | // Must start with a valid scheme
2 | // ^
3 | // Schemes that are considered safe
4 | // (https?|s?ftp|mailto|spotify|skype|ssh|teamspeak|tel):|
5 | // Relative schemes (//:) are considered safe
6 | // (\\/\\/)|
7 | // Image data URI's are considered safe
8 | // data:image\\/(png|bmp|gif|p?jpe?g);
9 | var VALID_SCHEME_REGEX =
10 | /^(https?|s?ftp|mailto|spotify|skype|ssh|teamspeak|tel):|(\/\/)|data:image\/(png|bmp|gif|p?jpe?g);/i;
11 |
12 | /**
13 | * Escapes a string so it's safe to use in regex
14 | *
15 | * @param {string} str
16 | * @return {string}
17 | */
18 | export function regex(str) {
19 | return str.replace(/([\-.*+?^=!:${}()|\[\]\/\\])/g, '\\$1');
20 | };
21 |
22 | /**
23 | * Escapes all HTML entities in a string
24 | *
25 | * If noQuotes is set to false, all single and double
26 | * quotes will also be escaped
27 | *
28 | * @param {string} str
29 | * @param {boolean} [noQuotes=true]
30 | * @return {string}
31 | * @since 1.4.1
32 | */
33 | export function entities(str, noQuotes) {
34 | if (!str) {
35 | return str;
36 | }
37 |
38 | var replacements = {
39 | '&': '&',
40 | '<': '<',
41 | '>': '>',
42 | ' ': ' ',
43 | '\r\n': '
',
44 | '\r': '
',
45 | '\n': '
'
46 | };
47 |
48 | if (noQuotes !== false) {
49 | replacements['"'] = '"';
50 | replacements['\''] = ''';
51 | replacements['`'] = '`';
52 | }
53 |
54 | str = str.replace(/ {2}|\r\n|[&<>\r\n'"`]/g, function (match) {
55 | return replacements[match] || match;
56 | });
57 |
58 | return str;
59 | };
60 |
61 | /**
62 | * Escape URI scheme.
63 | *
64 | * Appends the current URL to a url if it has a scheme that is not:
65 | *
66 | * http
67 | * https
68 | * sftp
69 | * ftp
70 | * mailto
71 | * spotify
72 | * skype
73 | * ssh
74 | * teamspeak
75 | * tel
76 | * //
77 | * data:image/(png|jpeg|jpg|pjpeg|bmp|gif);
78 | *
79 | * **IMPORTANT**: This does not escape any HTML in a url, for
80 | * that use the escape.entities() method.
81 | *
82 | * @param {string} url
83 | * @return {string}
84 | * @since 1.4.5
85 | */
86 | export function uriScheme(url) {
87 | var path,
88 | // If there is a : before a / then it has a scheme
89 | hasScheme = /^[^\/]*:/i,
90 | location = window.location;
91 |
92 | // Has no scheme or a valid scheme
93 | if ((!url || !hasScheme.test(url)) || VALID_SCHEME_REGEX.test(url)) {
94 | return url;
95 | }
96 |
97 | path = location.pathname.split('/');
98 | path.pop();
99 |
100 | return location.protocol + '//' +
101 | location.host +
102 | path.join('/') + '/' +
103 | url;
104 | };
105 |
--------------------------------------------------------------------------------
/src/lib/templates.js:
--------------------------------------------------------------------------------
1 | import * as dom from './dom.js';
2 | import * as escape from './escape.js';
3 |
4 |
5 | /**
6 | * HTML templates used by the editor and default commands
7 | * @type {Object}
8 | * @private
9 | */
10 | var _templates = {
11 | html:
12 | '' +
13 | '' +
14 | '' +
15 | '' +
17 | '' +
18 | '' +
19 | '' +
20 | '',
21 |
22 | toolbarButton: '' +
24 | '{dispName}',
25 |
26 | emoticon: '
',
28 |
29 | fontOpt: '{font}',
31 |
32 | sizeOpt: '{size}',
34 |
35 | pastetext:
36 | ' ' +
37 | '' +
38 | '' +
39 | '',
40 |
41 | table:
42 | '' +
44 | '' +
46 | '',
48 |
49 | image:
50 | ' ' +
51 | '' +
52 | ' ' +
53 | '' +
54 | ' ' +
55 | '' +
56 | '' +
57 | '',
58 |
59 | email:
60 | ' ' +
61 | '' +
62 | ' ' +
63 | '' +
64 | '' +
65 | '',
66 |
67 | link:
68 | ' ' +
69 | '' +
70 | ' ' +
71 | '' +
72 | '',
73 |
74 | youtubeMenu:
75 | ' ' +
76 | '' +
77 | '' +
78 | '',
79 |
80 | youtube:
81 | ''
84 | };
85 |
86 | /**
87 | * Replaces any params in a template with the passed params.
88 | *
89 | * If createHtml is passed it will return a DocumentFragment
90 | * containing the parsed template.
91 | *
92 | * @param {string} name
93 | * @param {Object} [params]
94 | * @param {boolean} [createHtml]
95 | * @returns {string|DocumentFragment}
96 | * @private
97 | */
98 | export default function (name, params, createHtml) {
99 | var template = _templates[name];
100 |
101 | Object.keys(params).forEach(function (name) {
102 | template = template.replace(
103 | new RegExp(escape.regex('{' + name + '}'), 'g'), params[name]
104 | );
105 | });
106 |
107 | if (createHtml) {
108 | template = dom.parseHTML(template);
109 | }
110 |
111 | return template;
112 | };
113 |
--------------------------------------------------------------------------------
/src/lib/utils.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Check if the passed argument is the
3 | * the passed type.
4 | *
5 | * @param {string} type
6 | * @param {*} arg
7 | * @returns {boolean}
8 | */
9 | function isTypeof(type, arg) {
10 | return typeof arg === type;
11 | }
12 |
13 | /**
14 | * @type {function(*): boolean}
15 | */
16 | export var isString = isTypeof.bind(null, 'string');
17 |
18 | /**
19 | * @type {function(*): boolean}
20 | */
21 | export var isUndefined = isTypeof.bind(null, 'undefined');
22 |
23 | /**
24 | * @type {function(*): boolean}
25 | */
26 | export var isFunction = isTypeof.bind(null, 'function');
27 |
28 | /**
29 | * @type {function(*): boolean}
30 | */
31 | export var isNumber = isTypeof.bind(null, 'number');
32 |
33 |
34 | /**
35 | * Returns true if an object has no keys
36 | *
37 | * @param {!Object} obj
38 | * @returns {boolean}
39 | */
40 | export function isEmptyObject(obj) {
41 | return !Object.keys(obj).length;
42 | }
43 |
44 | /**
45 | * Extends the first object with any extra objects passed
46 | *
47 | * If the first argument is boolean and set to true
48 | * it will extend child arrays and objects recursively.
49 | *
50 | * @param {!Object|boolean} targetArg
51 | * @param {...Object} source
52 | * @return {Object}
53 | */
54 | export function extend(targetArg, sourceArg) {
55 | var isTargetBoolean = targetArg === !!targetArg;
56 | var i = isTargetBoolean ? 2 : 1;
57 | var target = isTargetBoolean ? sourceArg : targetArg;
58 | var isDeep = isTargetBoolean ? targetArg : false;
59 |
60 | function isObject(value) {
61 | return value !== null && typeof value === 'object' &&
62 | Object.getPrototypeOf(value) === Object.prototype;
63 | }
64 |
65 | for (; i < arguments.length; i++) {
66 | var source = arguments[i];
67 |
68 | // Copy all properties for jQuery compatibility
69 | /* eslint guard-for-in: off */
70 | for (var key in source) {
71 | var targetValue = target[key];
72 | var value = source[key];
73 |
74 | // Skip undefined values to match jQuery
75 | if (isUndefined(value)) {
76 | continue;
77 | }
78 |
79 | // Skip special keys to prevent prototype pollution
80 | if (key === '__proto__' || key === 'constructor') {
81 | continue;
82 | }
83 |
84 | var isValueObject = isObject(value);
85 | var isValueArray = Array.isArray(value);
86 |
87 | if (isDeep && (isValueObject || isValueArray)) {
88 | // Can only merge if target type matches otherwise create
89 | // new target to merge into
90 | var isSameType = isObject(targetValue) === isValueObject &&
91 | Array.isArray(targetValue) === isValueArray;
92 |
93 | target[key] = extend(
94 | true,
95 | isSameType ? targetValue : (isValueArray ? [] : {}),
96 | value
97 | );
98 | } else {
99 | target[key] = value;
100 | }
101 | }
102 | }
103 |
104 | return target;
105 | }
106 |
107 | /**
108 | * Removes an item from the passed array
109 | *
110 | * @param {!Array} arr
111 | * @param {*} item
112 | */
113 | export function arrayRemove(arr, item) {
114 | var i = arr.indexOf(item);
115 |
116 | if (i > -1) {
117 | arr.splice(i, 1);
118 | }
119 | }
120 |
121 | /**
122 | * Iterates over an array or object
123 | *
124 | * @param {!Object|Array} obj
125 | * @param {function(*, *)} fn
126 | */
127 | export function each(obj, fn) {
128 | if (Array.isArray(obj) || 'length' in obj && isNumber(obj.length)) {
129 | for (var i = 0; i < obj.length; i++) {
130 | fn(i, obj[i]);
131 | }
132 | } else {
133 | Object.keys(obj).forEach(function (key) {
134 | fn(key, obj[key]);
135 | });
136 | }
137 | }
138 |
--------------------------------------------------------------------------------
/src/plugins/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "parserOptions": {
3 | "sourceType": "script"
4 | }
5 | }
--------------------------------------------------------------------------------
/src/plugins/autosave.js:
--------------------------------------------------------------------------------
1 | /**
2 | * SCEditor AutoSave Plugin
3 | * http://www.sceditor.com/
4 | *
5 | * Copyright (C) 2017, Sam Clarke (samclarke.com)
6 | *
7 | * SCEditor is licensed under the MIT license:
8 | * http://www.opensource.org/licenses/mit-license.php
9 | *
10 | * @author Sam Clarke
11 | */
12 | (function (sceditor) {
13 | 'use strict';
14 |
15 | var defaultKey = 'sce-autodraft-' + location.pathname + location.search;
16 |
17 | function clear(key) {
18 | localStorage.removeItem(key || defaultKey);
19 | }
20 |
21 | sceditor.plugins.autosave = function () {
22 | var base = this;
23 | var editor;
24 | var isLoading = false;
25 | var storageKey = defaultKey;
26 | // 86400000 = 24 hrs (24 * 60 * 60 * 1000)
27 | var expires = 86400000;
28 | var saveHandler = function (value) {
29 | localStorage.setItem(storageKey, JSON.stringify(value));
30 | };
31 | var loadHandler = function () {
32 | return JSON.parse(localStorage.getItem(storageKey));
33 | };
34 |
35 | function gc() {
36 | for (var i = 0; i < localStorage.length; i++) {
37 | var key = localStorage.key(i);
38 |
39 | if (/^sce\-autodraft\-/.test(key)) {
40 | var item = JSON.parse(localStorage.getItem(storageKey));
41 | if (item && item.time < Date.now() - expires) {
42 | clear(key);
43 | }
44 | }
45 | }
46 | }
47 |
48 | base.init = function () {
49 | editor = this;
50 | var opts = editor.opts && editor.opts.autosave || {};
51 |
52 | saveHandler = opts.save || saveHandler;
53 | loadHandler = opts.load || loadHandler;
54 | storageKey = opts.storageKey || storageKey;
55 | expires = opts.expires || expires;
56 |
57 | gc();
58 | };
59 |
60 | base.signalReady = function () {
61 | // Add submit event listener to clear autosave
62 | var parent = editor.getContentAreaContainer();
63 | while (parent) {
64 | if (/form/i.test(parent.nodeName)) {
65 | parent.addEventListener(
66 | 'submit', clear.bind(null, storageKey), true
67 | );
68 | break;
69 | }
70 |
71 | parent = parent.parentNode;
72 | }
73 |
74 | var state = loadHandler();
75 | if (state) {
76 | isLoading = true;
77 | editor.sourceMode(state.sourceMode);
78 | editor.val(state.value, false);
79 | editor.focus();
80 |
81 | if (state.sourceMode) {
82 | editor.sourceEditorCaret(state.caret);
83 | } else {
84 | editor.getRangeHelper().restoreRange();
85 | }
86 | isLoading = false;
87 | } else {
88 | saveHandler({
89 | caret: this.sourceEditorCaret(),
90 | sourceMode: this.sourceMode(),
91 | value: editor.val(null, false),
92 | time: Date.now()
93 | });
94 | }
95 | };
96 |
97 | base.signalValuechangedEvent = function (e) {
98 | if (!isLoading) {
99 | saveHandler({
100 | caret: this.sourceEditorCaret(),
101 | sourceMode: this.sourceMode(),
102 | value: e.detail.rawValue,
103 | time: Date.now()
104 | });
105 | }
106 | };
107 | };
108 |
109 | sceditor.plugins.autosave.clear = clear;
110 | }(sceditor));
111 |
--------------------------------------------------------------------------------
/src/plugins/autoyoutube.js:
--------------------------------------------------------------------------------
1 | /**
2 | * SCEditor Auto Youtube Plugin
3 | * http://www.sceditor.com/
4 | *
5 | * Copyright (C) 2016, Sam Clarke (samclarke.com)
6 | *
7 | * SCEditor is licensed under the MIT license:
8 | * http://www.opensource.org/licenses/mit-license.php
9 | *
10 | * @author Sam Clarke
11 | */
12 | (function (document, sceditor) {
13 | 'use strict';
14 |
15 | var dom = sceditor.dom;
16 |
17 | /*
18 | (^|\s) Start of line or space
19 | (?:https?:\/\/)? Optional scheme like http://
20 | (?:www\.)? Optional www. prefix
21 | (?:
22 | youtu\.be\/ Ends with .be/ so whatever comes next is the ID
23 | |
24 | youtube\.com\/watch\?v= Matches the .com version
25 | )
26 | ([^"&?\/ ]{11}) The actual YT ID
27 | (?:\&[\&_\?0-9a-z\#]+)? Any extra URL params
28 | (\s|$) End of line or space
29 | */
30 | var ytUrlRegex = /(^|\s)(?:https?:\/\/)?(?:www\.)?(?:youtu\.be\/|youtube\.com\/watch\?v=)([^"&?\/ ]{11})(?:\&[\&_\?0-9a-z\#]+)?(\s|$)/i;
31 |
32 | function youtubeEmbedCode(id) {
33 | return '';
36 | }
37 |
38 | function convertYoutubeLinks(parent, isRoot) {
39 | var node = parent.firstChild;
40 | var wholeContent = (parent.textContent || '');
41 |
42 | // Don't care about whitespace if is the root node
43 | if (isRoot) {
44 | wholeContent = wholeContent.trim();
45 | }
46 |
47 | var match = wholeContent.match(ytUrlRegex);
48 | // Whole content match so only return URL embed
49 | if (wholeContent === wholeContent.trim() && match &&
50 | match[0].length === wholeContent.length) {
51 | dom.removeAttr(parent, 'style');
52 | dom.removeAttr(parent, 'class');
53 | parent.innerHTML = youtubeEmbedCode(match[2]);
54 | return;
55 | }
56 |
57 | while (node) {
58 | // 3 is TextNodes
59 | if (node.nodeType === 3) {
60 | var text = node.nodeValue;
61 | var nodeParent = node.parentNode;
62 |
63 | if ((match = text.match(ytUrlRegex))) {
64 | nodeParent.insertBefore(document.createTextNode(
65 | text.substr(0, match.index) + match[1]
66 | ), node);
67 |
68 | nodeParent.insertBefore(
69 | dom.parseHTML(youtubeEmbedCode(match[2])), node
70 | );
71 |
72 | node.nodeValue = match[3] +
73 | text.substr(match.index + match[0].length);
74 | }
75 | } else {
76 | // TODO: Make this tag configurable.
77 | if (!dom.is(node, 'code')) {
78 | convertYoutubeLinks(node);
79 | }
80 | }
81 |
82 | node = node.nextSibling;
83 | }
84 | };
85 |
86 | sceditor.plugins.autoyoutube = function () {
87 | this.signalPasteRaw = function (data) {
88 | // TODO: Make this tag configurable.
89 | // Skip code tags
90 | if (dom.closest(this.currentNode(), 'code')) {
91 | return;
92 | }
93 |
94 | if (data.html || data.text) {
95 | var node = document.createElement('div');
96 |
97 | node.innerHTML = data.html ||
98 | sceditor.escapeEntities(data.text);
99 |
100 | convertYoutubeLinks(node, true);
101 |
102 | data.html = node.innerHTML;
103 | }
104 | };
105 | };
106 | })(document, sceditor);
107 |
--------------------------------------------------------------------------------
/src/plugins/emojis.js:
--------------------------------------------------------------------------------
1 | /**
2 | * SCEditor Paragraph Formatting Plugin
3 | * http://www.sceditor.com/
4 | *
5 | * Copyright (C) 2011-2024, Sam Clarke (samclarke.com)
6 | *
7 | * SCEditor is licensed under the MIT license:
8 | * http://www.opensource.org/licenses/mit-license.php
9 | *
10 | * @fileoverview SCEditor Paragraph Formatting Plugin
11 | * @author Sam Clarke
12 | */
13 | /*global EmojiMart*/
14 | (function (sceditor) {
15 | 'use strict';
16 |
17 | sceditor.plugins.emojis = function () {
18 | const base = this;
19 |
20 | /**
21 | * Function for the exec and txtExec properties
22 | *
23 | * @param {node} caller
24 | * @private
25 | */
26 | var emojisCmd = function (caller) {
27 | const editor = this,
28 | content = document.createElement('div'),
29 | emojis = editor.opts.emojis || [],
30 | perLine = Math.sqrt(Object.keys(emojis).length);
31 |
32 | if (!emojis.length) {
33 | const pickerOptions = { onEmojiSelect: handleSelect };
34 | const picker = new EmojiMart.Picker(pickerOptions);
35 |
36 | content.appendChild(picker);
37 | } else {
38 | var line = document.createElement('div');
39 |
40 | sceditor.utils.each(emojis,
41 | function (_, emoji) {
42 | const emojiElem = document.createElement('span');
43 |
44 | emojiElem.className = 'sceditor-option';
45 | emojiElem.style = 'cursor:pointer';
46 |
47 | emojiElem.appendChild(document.createTextNode(emoji));
48 |
49 | emojiElem.addEventListener('click',
50 | function (e) {
51 | editor.closeDropDown(true);
52 |
53 | editor.insert(e.target.innerHTML);
54 |
55 | e.preventDefault();
56 | });
57 |
58 | if (line.children.length >= perLine) {
59 | line = document.createElement('div');
60 | }
61 |
62 | content.appendChild(line);
63 |
64 | line.appendChild(emojiElem);
65 | });
66 | }
67 |
68 | editor.createDropDown(caller, 'emojis', content);
69 |
70 | function handleSelect(emoji) {
71 | editor.insert(emoji.native);
72 |
73 | editor.closeDropDown(true);
74 | }
75 | };
76 |
77 | base.init = function () {
78 | this.commands.emojis = {
79 | exec: emojisCmd,
80 | txtExec: emojisCmd,
81 | tooltip: 'Insert emoji',
82 | shortcut: 'Ctrl+E'
83 | };
84 | };
85 | };
86 | })(sceditor);
87 |
--------------------------------------------------------------------------------
/src/plugins/format.js:
--------------------------------------------------------------------------------
1 | /**
2 | * SCEditor Paragraph Formatting Plugin
3 | * http://www.sceditor.com/
4 | *
5 | * Copyright (C) 2011-2013, Sam Clarke (samclarke.com)
6 | *
7 | * SCEditor is licensed under the MIT license:
8 | * http://www.opensource.org/licenses/mit-license.php
9 | *
10 | * @fileoverview SCEditor Paragraph Formatting Plugin
11 | * @author Sam Clarke
12 | */
13 | (function (sceditor) {
14 | 'use strict';
15 |
16 | sceditor.plugins.format = function () {
17 | var base = this;
18 |
19 | /**
20 | * Default tags
21 | * @type {Object}
22 | * @private
23 | */
24 | var tags = {
25 | p: 'Paragraph',
26 | h1: 'Heading 1',
27 | h2: 'Heading 2',
28 | h3: 'Heading 3',
29 | h4: 'Heading 4',
30 | h5: 'Heading 5',
31 | h6: 'Heading 6',
32 | address: 'Address',
33 | pre: 'Preformatted Text'
34 | };
35 |
36 | /**
37 | * Private functions
38 | * @private
39 | */
40 | var insertTag,
41 | formatCmd;
42 |
43 |
44 | base.init = function () {
45 | var opts = this.opts,
46 | pOpts = opts.paragraphformat;
47 |
48 | // Don't enable if the BBCode plugin is enabled.
49 | if (opts.format && opts.format === 'bbcode') {
50 | return;
51 | }
52 |
53 | if (pOpts) {
54 | if (pOpts.tags) {
55 | tags = pOpts.tags;
56 | }
57 |
58 | if (pOpts.excludeTags) {
59 | pOpts.excludeTags.forEach(function (val) {
60 | delete tags[val];
61 | });
62 | }
63 | }
64 |
65 | if (!this.commands.format) {
66 | this.commands.format = {
67 | exec: formatCmd,
68 | txtExec: formatCmd,
69 | tooltip: 'Format Paragraph'
70 | };
71 | }
72 |
73 | if (opts.toolbar === sceditor.defaultOptions.toolbar) {
74 | opts.toolbar = opts.toolbar.replace(',color,',
75 | ',color,format,');
76 | }
77 | };
78 |
79 | /**
80 | * Inserts the specified tag into the editor
81 | *
82 | * @param {sceditor} editor
83 | * @param {string} tag
84 | * @private
85 | */
86 | insertTag = function (editor, tag) {
87 | if (editor.sourceMode()) {
88 | editor.insert('<' + tag + '>', '' + tag + '>');
89 | } else {
90 | editor.execCommand('formatblock', '<' + tag + '>');
91 | }
92 |
93 | };
94 |
95 | /**
96 | * Function for the exec and txtExec properties
97 | *
98 | * @param {node} caller
99 | * @private
100 | */
101 | formatCmd = function (caller) {
102 | var editor = this,
103 | content = document.createElement('div');
104 |
105 | sceditor.utils.each(tags, function (tag, val) {
106 | var link = document.createElement('a');
107 | link.className = 'sceditor-option';
108 | link.textContent = val.name || val;
109 | link.addEventListener('click', function (e) {
110 | editor.closeDropDown(true);
111 |
112 | if (val.exec) {
113 | val.exec(editor);
114 | } else {
115 | insertTag(editor, tag);
116 | }
117 |
118 | e.preventDefault();
119 | });
120 |
121 | content.appendChild(link);
122 | });
123 |
124 | editor.createDropDown(caller, 'format', content);
125 | };
126 | };
127 | })(sceditor);
128 |
--------------------------------------------------------------------------------
/src/plugins/plaintext.js:
--------------------------------------------------------------------------------
1 | /**
2 | * SCEditor Plain Text Plugin
3 | * http://www.sceditor.com/
4 | *
5 | * Copyright (C) 2016, Sam Clarke (samclarke.com)
6 | *
7 | * SCEditor is licensed under the MIT license:
8 | * http://www.opensource.org/licenses/mit-license.php
9 | *
10 | * @author Sam Clarke
11 | */
12 | (function (sceditor) {
13 | 'use strict';
14 |
15 | var utils = sceditor.utils;
16 | var dom = sceditor.dom;
17 |
18 | /**
19 | * Options:
20 | *
21 | * pastetext.addButton - If to replace the plaintext button with a toggle
22 | * button that enables and disables plain text mode.
23 | *
24 | * pastetext.enabled - If the plain text button should be enabled at start
25 | * up. Only applies if addButton is enabled.
26 | */
27 | sceditor.plugins.plaintext = function () {
28 | var plainTextEnabled = true;
29 |
30 | this.init = function () {
31 | var commands = this.commands;
32 | var opts = this.opts;
33 |
34 | if (opts && opts.plaintext && opts.plaintext.addButton) {
35 | plainTextEnabled = opts.plaintext.enabled;
36 |
37 | commands.pastetext = utils.extend(commands.pastetext || {}, {
38 | state: function () {
39 | return plainTextEnabled ? 1 : 0;
40 | },
41 | exec: function () {
42 | plainTextEnabled = !plainTextEnabled;
43 | }
44 | });
45 | }
46 | };
47 |
48 | this.signalPasteRaw = function (data) {
49 | if (plainTextEnabled) {
50 | if (data.html && !data.text) {
51 | var div = document.createElement('div');
52 | div.innerHTML = data.html;
53 |
54 | // TODO: Refactor into private shared module with editor
55 | // innerText adds two newlines after tags so convert
56 | // them to
tags
57 | utils.each(div.querySelectorAll('p'), function (_, elm) {
58 | dom.convertElement(elm, 'div');
59 | });
60 | // Remove collapsed
tags as innerText converts them to
61 | // newlines
62 | utils.each(div.querySelectorAll('br'), function (_, elm) {
63 | if (!elm.nextSibling ||
64 | !dom.isInline(elm.nextSibling, true)) {
65 | elm.parentNode.removeChild(elm);
66 | }
67 | });
68 |
69 | document.body.appendChild(div);
70 | data.text = div.innerText;
71 | document.body.removeChild(div);
72 | }
73 |
74 | data.html = null;
75 | }
76 | };
77 | };
78 | }(sceditor));
79 |
--------------------------------------------------------------------------------
/src/plugins/v1compat.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Version 1 compatibility plugin
3 | *
4 | * Patches commands and BBCodes set with
5 | * command.set and bbcode.set to wrap DOM
6 | * node arguments in jQuery objects.
7 | *
8 | * Should only be used to ease migrating.
9 | */
10 | (function (sceditor, $) {
11 | 'use strict';
12 |
13 | var plugins = sceditor.plugins;
14 |
15 | /**
16 | * Patches a method to wrap and DOM nodes in a jQuery object
17 | * @private
18 | */
19 | function patchMethodArguments(fn) {
20 | if (fn._scePatched) {
21 | return fn;
22 | }
23 |
24 | var patch = function () {
25 | var args = [];
26 |
27 | for (var i = 0; i < arguments.length; i++) {
28 | var arg = arguments[i];
29 |
30 | if (arg && arg.nodeType) {
31 | args.push($(arg));
32 | } else {
33 | args.push(arg);
34 | }
35 | }
36 |
37 | return fn.apply(this, args);
38 | };
39 |
40 | patch._scePatched = true;
41 | return patch;
42 | }
43 |
44 | /**
45 | * Patches a method to wrap any return value in a jQuery object
46 | * @private
47 | */
48 | function patchMethodReturn(fn) {
49 | if (fn._scePatched) {
50 | return fn;
51 | }
52 |
53 | var patch = function () {
54 | return $(fn.apply(this, arguments));
55 | };
56 |
57 | patch._scePatched = true;
58 | return patch;
59 | }
60 |
61 | var oldSet = sceditor.command.set;
62 | sceditor.command.set = function (name, cmd) {
63 | if (cmd && typeof cmd.exec === 'function') {
64 | cmd.exec = patchMethodArguments(cmd.exec);
65 | }
66 |
67 | if (cmd && typeof cmd.txtExec === 'function') {
68 | cmd.txtExec = patchMethodArguments(cmd.txtExec);
69 | }
70 |
71 | return oldSet.call(this, name, cmd);
72 | };
73 |
74 | if (plugins.bbcode) {
75 | var oldBBCodeSet = plugins.bbcode.bbcode.set;
76 | plugins.bbcode.bbcode.set = function (name, bbcode) {
77 | if (bbcode && typeof bbcode.format === 'function') {
78 | bbcode.format = patchMethodArguments(bbcode.format);
79 | }
80 |
81 | return oldBBCodeSet.call(this, name, bbcode);
82 | };
83 | };
84 |
85 | var oldCreate = sceditor.create;
86 | sceditor.create = function (textarea, options) {
87 | oldCreate.call(this, textarea, options);
88 |
89 | if (textarea && textarea._sceditor) {
90 | var editor = textarea._sceditor;
91 |
92 | editor.getBody = patchMethodReturn(editor.getBody);
93 | editor.getContentAreaContainer =
94 | patchMethodReturn(editor.getContentAreaContainer);
95 | }
96 | };
97 | }(sceditor, jQuery));
98 |
--------------------------------------------------------------------------------
/src/sceditor.js:
--------------------------------------------------------------------------------
1 | /**
2 | * SCEditor
3 | * http://www.sceditor.com/
4 | *
5 | * Copyright (C) 2017, Sam Clarke (samclarke.com)
6 | *
7 | * SCEditor is licensed under the MIT license:
8 | * http://www.opensource.org/licenses/mit-license.php
9 | *
10 | * @fileoverview SCEditor - A lightweight WYSIWYG BBCode and HTML editor
11 | * @author Sam Clarke
12 | */
13 |
14 | import SCEditor from './lib/SCEditor.js';
15 | import PluginManager from './lib/PluginManager.js';
16 | import * as escape from './lib/escape.js';
17 | import * as browser from './lib/browser.js';
18 | import * as dom from './lib/dom.js';
19 | import * as utils from './lib/utils.js';
20 | import defaultCommands from './lib/defaultCommands.js';
21 | import defaultOptions from './lib/defaultOptions.js';
22 |
23 |
24 | window.sceditor = {
25 | command: SCEditor.command,
26 | commands: defaultCommands,
27 | defaultOptions: defaultOptions,
28 |
29 | ios: browser.ios,
30 | isWysiwygSupported: browser.isWysiwygSupported,
31 |
32 | regexEscape: escape.regex,
33 | escapeEntities: escape.entities,
34 | escapeUriScheme: escape.uriScheme,
35 |
36 | dom: {
37 | css: dom.css,
38 | attr: dom.attr,
39 | removeAttr: dom.removeAttr,
40 | is: dom.is,
41 | closest: dom.closest,
42 | width: dom.width,
43 | height: dom.height,
44 | traverse: dom.traverse,
45 | rTraverse: dom.rTraverse,
46 | parseHTML: dom.parseHTML,
47 | hasStyling: dom.hasStyling,
48 | convertElement: dom.convertElement,
49 | blockLevelList: dom.blockLevelList,
50 | canHaveChildren: dom.canHaveChildren,
51 | isInline: dom.isInline,
52 | copyCSS: dom.copyCSS,
53 | fixNesting: dom.fixNesting,
54 | findCommonAncestor: dom.findCommonAncestor,
55 | getSibling: dom.getSibling,
56 | removeWhiteSpace: dom.removeWhiteSpace,
57 | extractContents: dom.extractContents,
58 | getOffset: dom.getOffset,
59 | getStyle: dom.getStyle,
60 | hasStyle: dom.hasStyle
61 | },
62 | locale: SCEditor.locale,
63 | icons: SCEditor.icons,
64 | utils: {
65 | each: utils.each,
66 | isEmptyObject: utils.isEmptyObject,
67 | extend: utils.extend
68 | },
69 | plugins: PluginManager.plugins,
70 | formats: SCEditor.formats,
71 | create: function (textarea, options) {
72 | options = options || {};
73 |
74 | // Don't allow the editor to be initialised
75 | // on it's own source editor
76 | if (dom.parent(textarea, '.sceditor-container')) {
77 | return;
78 | }
79 |
80 | if (options.runWithoutWysiwygSupport || browser.isWysiwygSupported) {
81 | /*eslint no-new: off*/
82 | (new SCEditor(textarea, options));
83 | }
84 | },
85 | instance: function (textarea) {
86 | return textarea._sceditor;
87 | }
88 | };
89 |
--------------------------------------------------------------------------------
/src/themes/content/default.css:
--------------------------------------------------------------------------------
1 | /*! SCEditor | (C) 2011-2013, Sam Clarke | sceditor.com/license */
2 | html, body, p, code:before, table {
3 | margin: 0;
4 | padding: 0;
5 | font-family: Verdana, Arial, Helvetica, sans-serif;
6 | font-size: 14px;
7 | color: #111;
8 | line-height: 1.25;
9 | overflow: visible;
10 | }
11 | html {
12 | height: 100%;
13 | }
14 | .ios {
15 | /* Needed for iOS scrolling bug fix */
16 | overflow: auto;
17 | -webkit-overflow-scrolling: touch;
18 | }
19 | .ios body {
20 | /* Needed for iOS scrolling bug fix */
21 | position: relative;
22 | overflow: auto;
23 | }
24 | body {
25 | /* Needed to make sure body covers the whole editor and that
26 | long lines don't cause horizontal scrolling */
27 | min-height: 100%;
28 | word-wrap: break-word;
29 | }
30 |
31 | body.placeholder::before {
32 | content: attr(placeholder);
33 | color: #555;
34 | font-style: italic;
35 | }
36 |
37 | ul, ol {
38 | margin-top: 0;
39 | margin-bottom: 0;
40 | padding-top: 0;
41 | padding-bottom: 0;
42 | }
43 |
44 | table, td {
45 | border: 1px dotted #000;
46 | empty-cells: show;
47 | }
48 |
49 | table td {
50 | min-width: 5px;
51 | }
52 |
53 | code {
54 | display: block;
55 | background: #f1f1f1;
56 | white-space: pre;
57 | padding: 1em;
58 | text-align: left;
59 | margin: .25em 0;
60 | direction: ltr;
61 | }
62 |
63 | blockquote {
64 | background: #fff7d9;
65 | margin: .25em 0;
66 | border-left: .3em solid #f4e59f;
67 | padding: .5em .5em .5em .75em;
68 | }
69 | blockquote cite {
70 | font-weight: bold;
71 | display: block;
72 | font-size: 1em;
73 | margin: 0 -.5em .25em -.75em;
74 | padding: 0 .5em .15em .75em;
75 | border-bottom: 1px solid #f4e59f;
76 | }
77 |
78 | h1, h2, h3, h4, h5, h6 {
79 | padding: 0; margin: 0;
80 | }
81 |
82 | /* Prevent empty paragraphs from collapsing */
83 | div, p {
84 | min-height: 1.25em;
85 | }
86 |
--------------------------------------------------------------------------------
/src/themes/default.less:
--------------------------------------------------------------------------------
1 | /*! SCEditor | (C) 2011-2016, Sam Clarke | sceditor.com/license */
2 | /**
3 | * Default SCEditor
4 | * http://www.sceditor.com/
5 | *
6 | * Copyright (C) 2011-16, Sam Clarke
7 | *
8 | * SCEditor is licensed under the MIT license:
9 | * http://www.opensource.org/licenses/mit-license.php
10 | */
11 |
12 | @import "icons/famfamfam.less";
13 | @import "inc/defaultbase.less";
14 |
--------------------------------------------------------------------------------
/src/themes/defaultdark.less:
--------------------------------------------------------------------------------
1 | /*! SCEditor | (C) 2017, Sam Clarke | sceditor.com/license */
2 | /**
3 | * Default SCEditor
4 | * http://www.sceditor.com/
5 | *
6 | * Copyright (C) 2017, Sam Clarke
7 | *
8 | * SCEditor is licensed under the MIT license:
9 | * http://www.opensource.org/licenses/mit-license.php
10 | */
11 | @import "icons/famfamfam.less";
12 | @import "inc/defaultbase.less";
13 |
14 | div.sceditor-toolbar {
15 | background: #5d5d5d;
16 | }
17 | div.sceditor-group {
18 | background: #303030;
19 | border-bottom: 1px solid #000;
20 | }
21 | .sceditor-button:hover,
22 | .sceditor-button:active,
23 | .sceditor-button.active {
24 | background: #6b6b6b;
25 | }
26 | .sceditor-button svg {
27 | fill: #fff;
28 | }
29 | .sceditor-button.disabled svg {
30 | fill: #777;
31 | }
--------------------------------------------------------------------------------
/src/themes/icons/famfamfam.less:
--------------------------------------------------------------------------------
1 | // Where to find the famfamfam icon images
2 | @famfamfam-image-location: "famfamfam.png";
3 |
4 | div.sceditor-grip, .sceditor-button div {
5 | background-image: url("@{famfamfam-image-location}");
6 | background-repeat: no-repeat;
7 | width: 16px;
8 | height: 16px;
9 | }
10 | .sceditor-button-youtube div { background-position: 0px 0px; }
11 | .sceditor-button-link div { background-position: 0px -16px; }
12 | .sceditor-button-unlink div { background-position: 0px -32px; }
13 | .sceditor-button-underline div { background-position: 0px -48px; }
14 | .sceditor-button-time div { background-position: 0px -64px; }
15 | .sceditor-button-table div { background-position: 0px -80px; }
16 | .sceditor-button-superscript div { background-position: 0px -96px; }
17 | .sceditor-button-subscript div { background-position: 0px -112px; }
18 | .sceditor-button-strike div { background-position: 0px -128px; }
19 | .sceditor-button-source div { background-position: 0px -144px; }
20 | .sceditor-button-size div { background-position: 0px -160px; }
21 | .sceditor-button-rtl div { background-position: 0px -176px; }
22 | .sceditor-button-right div { background-position: 0px -192px; }
23 | .sceditor-button-removeformat div { background-position: 0px -208px; }
24 | .sceditor-button-quote div { background-position: 0px -224px; }
25 | .sceditor-button-print div { background-position: 0px -240px; }
26 | .sceditor-button-pastetext div { background-position: 0px -256px; }
27 | .sceditor-button-paste div { background-position: 0px -272px; }
28 | .sceditor-button-outdent div { background-position: 0px -288px; }
29 | .sceditor-button-orderedlist div { background-position: 0px -304px; }
30 | .sceditor-button-maximize div { background-position: 0px -320px; }
31 | .sceditor-button-ltr div { background-position: 0px -336px; }
32 | .sceditor-button-left div { background-position: 0px -352px; }
33 | .sceditor-button-justify div { background-position: 0px -368px; }
34 | .sceditor-button-italic div { background-position: 0px -384px; }
35 | .sceditor-button-indent div { background-position: 0px -400px; }
36 | .sceditor-button-image div { background-position: 0px -416px; }
37 | .sceditor-button-horizontalrule div { background-position: 0px -432px; }
38 | .sceditor-button-format div { background-position: 0px -448px; }
39 | .sceditor-button-font div { background-position: 0px -464px; }
40 | .sceditor-button-emoticon div { background-position: 0px -480px; }
41 | .sceditor-button-emojis div { background-position: 0px -660px; }
42 | .sceditor-button-email div { background-position: 0px -496px; }
43 | .sceditor-button-date div { background-position: 0px -512px; }
44 | .sceditor-button-cut div { background-position: 0px -528px; }
45 | .sceditor-button-copy div { background-position: 0px -544px; }
46 | .sceditor-button-color div { background-position: 0px -560px; }
47 | .sceditor-button-code div { background-position: 0px -576px; }
48 | .sceditor-button-center div { background-position: 0px -592px; }
49 | .sceditor-button-bulletlist div { background-position: 0px -608px; }
50 | .sceditor-button-bold div { background-position: 0px -624px; }
51 | div.sceditor-grip {
52 | background-position: 0px -640px;
53 | width: 10px;
54 | height: 10px;
55 | }
56 | .rtl div.sceditor-grip { background-position: 0px -650px; }
57 |
--------------------------------------------------------------------------------
/src/themes/icons/famfamfam.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/src/themes/icons/famfamfam.png
--------------------------------------------------------------------------------
/src/themes/icons/src/famfamfam/bold.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/src/themes/icons/src/famfamfam/bold.png
--------------------------------------------------------------------------------
/src/themes/icons/src/famfamfam/bulletlist.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/src/themes/icons/src/famfamfam/bulletlist.png
--------------------------------------------------------------------------------
/src/themes/icons/src/famfamfam/center.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/src/themes/icons/src/famfamfam/center.png
--------------------------------------------------------------------------------
/src/themes/icons/src/famfamfam/code.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/src/themes/icons/src/famfamfam/code.png
--------------------------------------------------------------------------------
/src/themes/icons/src/famfamfam/color.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/src/themes/icons/src/famfamfam/color.png
--------------------------------------------------------------------------------
/src/themes/icons/src/famfamfam/copy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/src/themes/icons/src/famfamfam/copy.png
--------------------------------------------------------------------------------
/src/themes/icons/src/famfamfam/cut.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/src/themes/icons/src/famfamfam/cut.png
--------------------------------------------------------------------------------
/src/themes/icons/src/famfamfam/date.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/src/themes/icons/src/famfamfam/date.png
--------------------------------------------------------------------------------
/src/themes/icons/src/famfamfam/email.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/src/themes/icons/src/famfamfam/email.png
--------------------------------------------------------------------------------
/src/themes/icons/src/famfamfam/emoticon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/src/themes/icons/src/famfamfam/emoticon.png
--------------------------------------------------------------------------------
/src/themes/icons/src/famfamfam/font.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/src/themes/icons/src/famfamfam/font.png
--------------------------------------------------------------------------------
/src/themes/icons/src/famfamfam/format.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/src/themes/icons/src/famfamfam/format.png
--------------------------------------------------------------------------------
/src/themes/icons/src/famfamfam/grip-rtl.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/src/themes/icons/src/famfamfam/grip-rtl.png
--------------------------------------------------------------------------------
/src/themes/icons/src/famfamfam/grip.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/src/themes/icons/src/famfamfam/grip.png
--------------------------------------------------------------------------------
/src/themes/icons/src/famfamfam/horizontalrule.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/src/themes/icons/src/famfamfam/horizontalrule.png
--------------------------------------------------------------------------------
/src/themes/icons/src/famfamfam/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/src/themes/icons/src/famfamfam/image.png
--------------------------------------------------------------------------------
/src/themes/icons/src/famfamfam/indent.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/src/themes/icons/src/famfamfam/indent.png
--------------------------------------------------------------------------------
/src/themes/icons/src/famfamfam/italic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/src/themes/icons/src/famfamfam/italic.png
--------------------------------------------------------------------------------
/src/themes/icons/src/famfamfam/justify.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/src/themes/icons/src/famfamfam/justify.png
--------------------------------------------------------------------------------
/src/themes/icons/src/famfamfam/left.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/src/themes/icons/src/famfamfam/left.png
--------------------------------------------------------------------------------
/src/themes/icons/src/famfamfam/ltr.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/src/themes/icons/src/famfamfam/ltr.png
--------------------------------------------------------------------------------
/src/themes/icons/src/famfamfam/maximize.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/src/themes/icons/src/famfamfam/maximize.png
--------------------------------------------------------------------------------
/src/themes/icons/src/famfamfam/orderedlist.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/src/themes/icons/src/famfamfam/orderedlist.png
--------------------------------------------------------------------------------
/src/themes/icons/src/famfamfam/outdent.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/src/themes/icons/src/famfamfam/outdent.png
--------------------------------------------------------------------------------
/src/themes/icons/src/famfamfam/paste.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/src/themes/icons/src/famfamfam/paste.png
--------------------------------------------------------------------------------
/src/themes/icons/src/famfamfam/pastetext.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/src/themes/icons/src/famfamfam/pastetext.png
--------------------------------------------------------------------------------
/src/themes/icons/src/famfamfam/print.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/src/themes/icons/src/famfamfam/print.png
--------------------------------------------------------------------------------
/src/themes/icons/src/famfamfam/quote.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/src/themes/icons/src/famfamfam/quote.png
--------------------------------------------------------------------------------
/src/themes/icons/src/famfamfam/removeformat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/src/themes/icons/src/famfamfam/removeformat.png
--------------------------------------------------------------------------------
/src/themes/icons/src/famfamfam/right.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/src/themes/icons/src/famfamfam/right.png
--------------------------------------------------------------------------------
/src/themes/icons/src/famfamfam/rtl.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/src/themes/icons/src/famfamfam/rtl.png
--------------------------------------------------------------------------------
/src/themes/icons/src/famfamfam/size.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/src/themes/icons/src/famfamfam/size.png
--------------------------------------------------------------------------------
/src/themes/icons/src/famfamfam/source.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/src/themes/icons/src/famfamfam/source.png
--------------------------------------------------------------------------------
/src/themes/icons/src/famfamfam/strike.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/src/themes/icons/src/famfamfam/strike.png
--------------------------------------------------------------------------------
/src/themes/icons/src/famfamfam/subscript.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/src/themes/icons/src/famfamfam/subscript.png
--------------------------------------------------------------------------------
/src/themes/icons/src/famfamfam/superscript.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/src/themes/icons/src/famfamfam/superscript.png
--------------------------------------------------------------------------------
/src/themes/icons/src/famfamfam/table.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/src/themes/icons/src/famfamfam/table.png
--------------------------------------------------------------------------------
/src/themes/icons/src/famfamfam/text_ltr.xcf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/src/themes/icons/src/famfamfam/text_ltr.xcf
--------------------------------------------------------------------------------
/src/themes/icons/src/famfamfam/text_rtl.xcf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/src/themes/icons/src/famfamfam/text_rtl.xcf
--------------------------------------------------------------------------------
/src/themes/icons/src/famfamfam/time.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/src/themes/icons/src/famfamfam/time.png
--------------------------------------------------------------------------------
/src/themes/icons/src/famfamfam/underline.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/src/themes/icons/src/famfamfam/underline.png
--------------------------------------------------------------------------------
/src/themes/icons/src/famfamfam/unlink.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/src/themes/icons/src/famfamfam/unlink.png
--------------------------------------------------------------------------------
/src/themes/icons/src/famfamfam/url.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/src/themes/icons/src/famfamfam/url.png
--------------------------------------------------------------------------------
/src/themes/icons/src/famfamfam/youtube.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/samclarke/SCEditor/6b154af9611178336bbb41ce948ca8febff1caab/src/themes/icons/src/famfamfam/youtube.png
--------------------------------------------------------------------------------
/src/themes/modern.less:
--------------------------------------------------------------------------------
1 | /**
2 | * Modern theme
3 | *
4 | * Copyright (C) 2012, Sam Clarke (samclarke.com)
5 | *
6 | * SCEditor is licensed under the MIT license:
7 | * http://www.opensource.org/licenses/mit-license.php
8 | *
9 | * Icons by Mark James (http://www.famfamfam.com/lab/icons/silk/)
10 | * Licensed under the Creative Commons CC-BY license (http://creativecommons.org/licenses/by/3.0/)
11 | */
12 |
13 | @import "default.less";
14 |
15 | .sceditor-container { border: 1px solid #999; }
16 |
17 | .sceditor-container textarea {
18 | font-family: Consolas, "Bitstream Vera Sans Mono", "Andale Mono", Monaco, "DejaVu Sans Mono", "Lucida Console", monospace;
19 | background: #2e3436;
20 | color: #fff;
21 | margin: 0;
22 | padding: 5px;
23 | }
24 |
25 | div.sceditor-toolbar {
26 | background: #ccc;
27 | background: linear-gradient(to bottom, #cccccc 0%,#b2b2b2 100%);
28 | }
29 |
30 | div.sceditor-group {
31 | display: inline;
32 | background: transparent;
33 | margin: 0;
34 | padding: 0;
35 | border: 0;
36 | }
37 | .sceditor-button {
38 | padding: 4px;
39 | margin: 2px 1px 2px 3px;
40 | height: 16px;
41 | .rounded(12px);
42 | }
43 | .sceditor-button:hover,
44 | .sceditor-button.active,
45 | .sceditor-button.active:hover {
46 | .box-shadow(none);
47 | }
48 | .sceditor-button:hover {
49 | background: #fff;
50 | background: rgba(255,255,255,0.75);
51 | margin: 1px 0 1px 2px;
52 | border: 1px solid #eee;
53 | }
54 | .sceditor-button.disabled:hover {
55 | margin: 2px 1px 2px 3px;
56 | border: 0;
57 | }
58 | .sceditor-button.active {
59 | background: #b1b1b1;
60 | background: rgba(0,0,0,0.1);
61 | margin: 1px 0 1px 2px;
62 | border: 1px solid #999;
63 | }
64 | .sceditor-button.active:hover {
65 | background: #fff;
66 | background: rgba(255,255,255,0.25);
67 | }
68 | .sceditor-button:active, .sceditor-button.active:active {
69 | margin: 1px 0 1px 2px;
70 | border: 1px solid #999;
71 | .box-shadow(inset 0 0 4px rgba(0,0,0,0.5));
72 | }
73 | .sceditor-button div,
74 | .sceditor-button svg {
75 | margin: 0;
76 | }
--------------------------------------------------------------------------------
/src/themes/office-toolbar.less:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2012, Sam Clarke (samclarke.com)
3 | *
4 | * SCEditor is licensed under the MIT license:
5 | * http://www.opensource.org/licenses/mit-license.php
6 | *
7 | * Icons by Mark James (http://www.famfamfam.com/lab/icons/silk/)
8 | * Licensed under the Creative Commons CC-BY license (http://creativecommons.org/licenses/by/3.0/)
9 | */
10 |
11 | @import "default.less";
12 |
13 | .sceditor-container {
14 | border: 1px solid #8db2e3;
15 | }
16 |
17 | .sceditor-container textarea {
18 | font-family: Consolas, "Bitstream Vera Sans Mono", "Andale Mono", Monaco, "DejaVu Sans Mono", "Lucida Console", monospace;
19 | }
20 |
21 | div.sceditor-toolbar {
22 | border-bottom: 1px solid #95a9c3;
23 | background: #dee8f5;
24 | background: linear-gradient(to bottom, #dee8f5 0%,#c7d8ed 29%,#ccdcee 61%,#c0d8ef 100%);
25 | }
26 |
27 | div.sceditor-group {
28 | border: 1px solid #7596bf;
29 | background: transparent;
30 | padding: 0;
31 | background: #cadcf0;
32 | background: linear-gradient(to bottom, #cadcf0 24%,#bcd0e9 38%,#d0e1f7 99%);
33 | }
34 | .sceditor-button {
35 | height: 16px;
36 | padding: 3px 4px;
37 | .rounded(0);
38 | box-shadow: inset 0 1px #d5e3f1,
39 | inset 0 -1px #e3edfb,
40 | inset 1px 0 #cddcef,
41 | inset -1px 0 #b8ceea;
42 | }
43 | .sceditor-button:first-child { .rounded(4px 0 0 4px); }
44 | .sceditor-button:last-child { .rounded(0 4px 4px 0); }
45 | .sceditor-button div,
46 | .sceditor-button svg {
47 | margin: 0;
48 | }
49 | .sceditor-button.active {
50 | background: rgb(251,219,181);
51 | background: linear-gradient(to bottom, rgba(251,219,181,1) 11%,rgba(254,180,86,1) 29%,rgba(253,235,159,1) 99%);
52 | box-shadow: inset 0 1px #ebd1b4,
53 | inset 0 -1px #ffe47f,
54 | inset -1px 0 #b8ceea;
55 | }
56 | .sceditor-button:hover {
57 | background: #fef7d5;
58 | background: linear-gradient(to bottom, #fef7d5 0%,#fae5a9 42%,#ffd048 42%,#ffe59f 100%);
59 | box-shadow: inset 0 1px #fffbe8,
60 | inset -1px 0 #ffefc4,
61 | inset 0 -1px #fff9cc;
62 | }
63 | .sceditor-button:active {
64 | background: #e7a66d;
65 | background: linear-gradient(to bottom, #e7a66d 0%,#fcb16d 1%,#ff8d05 42%,#ffc450 100%);
66 | box-shadow: inset 0 1px 1px #7b6645,
67 | inset 0 -1px #d19c33;
68 | }
69 | .sceditor-button.active:hover {
70 | background: #dba368;
71 | background: linear-gradient(to bottom, #dba368 0%,#ffbd79 4%,#fea335 34%,#ffc64c 66%,#fee069 100%);
72 | box-shadow: inset 0 1px 1px #9e8255,
73 | inset 0 -1px #fcce6b;
74 | }
75 |
--------------------------------------------------------------------------------
/src/themes/office.less:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2012, Sam Clarke (samclarke.com)
3 | *
4 | * SCEditor is licensed under the MIT license:
5 | * http://www.opensource.org/licenses/mit-license.php
6 | *
7 | * Icons by Mark James (http://www.famfamfam.com/lab/icons/silk/)
8 | * Licensed under the Creative Commons CC-BY license (http://creativecommons.org/licenses/by/3.0/)
9 | */
10 |
11 | @import "office-toolbar.less";
12 |
13 | .sceditor-container {
14 | background: rgb(163,194,234);
15 | background: linear-gradient(to bottom, rgba(163,194,234,1) 0%,rgba(109,146,193,1) 39%,rgba(87,127,179,1) 64%,rgba(101,145,204,1) 100%);
16 | }
17 |
18 |
19 | .sceditor-container iframe,
20 | .sceditor-container textarea {
21 | border: 1px solid #646464;
22 | background: #fff;
23 | margin: 7px 40px;
24 | padding: 20px;
25 | width: ~"calc(100% - 120px) !important";
26 | box-shadow: 1px 1px 5px #293a52;
27 | }
28 |
--------------------------------------------------------------------------------
/src/themes/square.less:
--------------------------------------------------------------------------------
1 | /**
2 | * Square theme
3 | *
4 | * This theme is best suited to short toolbars that
5 | * don't span multiple lines.
6 | *
7 | * Copyright (C) 2012, Sam Clarke (samclarke.com)
8 | *
9 | * SCEditor is licensed under the MIT license:
10 | * http://www.opensource.org/licenses/mit-license.php
11 | *
12 | * Icons by Mark James (http://www.famfamfam.com/lab/icons/silk/)
13 | * Licensed under the Creative Commons CC-BY license (http://creativecommons.org/licenses/by/3.0/)
14 | */
15 |
16 | @import "default.less";
17 |
18 | .sceditor-container {
19 | border: 1px solid #d6d6d6;
20 | .rounded(0);
21 | }
22 |
23 | .sceditor-container textarea {
24 | font-family: Consolas, "Bitstream Vera Sans Mono", "Andale Mono", Monaco, "DejaVu Sans Mono", "Lucida Console", monospace;
25 | background: #2e3436;
26 | color: #fff;
27 | margin: 0;
28 | padding: 5px;
29 | }
30 |
31 | div.sceditor-toolbar, div.sceditor-group {
32 | background: #f2f2f2;
33 | background: linear-gradient(to bottom, #f2f2f2 0%,#dddddd 89%);
34 | }
35 |
36 | div.sceditor-toolbar {
37 | padding: 0;
38 | border-bottom: 1px solid #bbb;
39 | background-size: 100% 32px;
40 | }
41 | div.sceditor-group {
42 | margin: 0;
43 | padding: 2px 4px;
44 | border: 0;
45 | border-right: 1px solid #ccc;
46 | border-left: 1px solid #eaeaea;
47 | .rounded(0);
48 | }
49 | div.sceditor-group:last-child { border-right: 0; }
50 | div.sceditor-group:first-child { border-left: 0; }
51 | .sceditor-button {
52 | height: 16px;
53 | padding: 5px;
54 | margin: 1px;
55 |
56 | .rounded(0);
57 | }
58 | .sceditor-button div,
59 | .sceditor-button svg {
60 | margin: 0;
61 | }
62 | .sceditor-button.active,
63 | .sceditor-button:hover,
64 | .sceditor-button:active,
65 | .sceditor-button.active:hover {
66 | margin: 0;
67 | box-shadow: none;
68 | }
69 |
70 | .sceditor-button.active {
71 | background: #f4f4f4;
72 | border: 1px solid #ccc;
73 | }
74 | .sceditor-button:hover {
75 | background: #fefefe;
76 | border: 1px solid #ddd;
77 | }
78 | .sceditor-button.disabled:hover {
79 | margin: 1px;
80 | border: 0;
81 | }
82 | .sceditor-button:active {
83 | background: #eee;
84 | border: 1px solid #ccc;
85 | }
86 | .sceditor-button.active:hover {
87 | background: #f8f8f8;
88 | border: 1px solid #ddd;
89 | }
90 |
--------------------------------------------------------------------------------
/tests/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "qunit": true
4 | },
5 | "globals": {
6 | "QUnit": true,
7 | "module": true,
8 | "test": true,
9 | "asyncTest": true,
10 | "rangy": true,
11 | "sinon": true,
12 | "runner": true,
13 | "patchConsole": true,
14 | "less": true
15 | },
16 | "rules": {
17 | "new-cap": "off",
18 | "strict": "off",
19 | "max-params": "off",
20 | "max-depth": ["error", 6],
21 | "max-len": ["error", {
22 | "code": 120,
23 | "ignoreUrls": true,
24 | "ignoreRegExpLiterals": true
25 | }]
26 | }
27 | }
--------------------------------------------------------------------------------
/tests/dev-server.js:
--------------------------------------------------------------------------------
1 | /* eslint-env node */
2 | /* global Promise */
3 | const WebpackDevServer = require('webpack-dev-server');
4 | const webpack = require('webpack');
5 | const path = require('path');
6 |
7 | exports.create = function (port, coverage) {
8 | return new Promise(function (resolve, reject) {
9 | const webpackOptions = {
10 | mode: 'development',
11 | entry: {
12 | main: [
13 | './src/sceditor.js',
14 | 'webpack-dev-server/client?http://localhost:9000'
15 | ],
16 | 'main-jquery': [
17 | './src/jquery.sceditor.js',
18 | 'webpack-dev-server/client?http://localhost:9000'
19 | ],
20 | unit: [
21 | './tests/unit/index.js'
22 | ]
23 | },
24 | module: {
25 | rules: [
26 | {
27 | test: /\.js$/,
28 | include: path.resolve('src/'),
29 | loader: __dirname + '/loader.js'
30 | }
31 | ]
32 | },
33 | output: {
34 | path: path.join(__dirname, 'dist'),
35 | filename: '[name].js'
36 | },
37 | resolve: {
38 | modules: [
39 | path.join(__dirname, '..'),
40 | path.join(__dirname, '../node_modules')
41 | ],
42 | alias: {
43 | src: path.join(__dirname, '../src'),
44 | tests: path.join(__dirname, '../tests')
45 | }
46 | },
47 | externals: {
48 | jquery: 'jQuery',
49 | rangy: 'rangy'
50 | },
51 | devtool: 'inline-cheap-module-source-map'
52 | };
53 |
54 | if (!coverage) {
55 | webpackOptions.module = {};
56 | }
57 |
58 | const compiler = webpack(webpackOptions);
59 |
60 | // Resolve promise when bundle generated
61 | compiler.hooks.done.tap('BuildStatsPlugin', () => {
62 | resolve();
63 | });
64 |
65 | /* eslint no-new: off */
66 | new WebpackDevServer({
67 | port: port,
68 | static: {
69 | directory: path.join(__dirname, '..'),
70 | // Don't watch when running with coverage as coverage generation
71 | // will trigger second run
72 | watch: !coverage
73 | },
74 | compress: true,
75 | devMiddleware: {
76 | publicPath: '/webpack-build/'
77 | }
78 | }, compiler).startCallback(function (err) {
79 | if (err) {
80 | reject(err);
81 | }
82 | });
83 | });
84 | };
85 |
86 | if (require.main === module) {
87 | exports.create(9000, false);
88 | }
89 |
--------------------------------------------------------------------------------
/tests/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | SCEditor Tests - SCEditor
7 |
8 |
10 |
11 |
12 |
13 | SCEditor Tests
14 |
15 |
16 | Testing SCEditor
17 |
18 | Thank you for taking the time to test SCEditor.
19 |
20 |
21 | - Run the unit tests.
22 | - Run the manual tests.
23 |
24 |
25 |
26 | If you encounter any bugs/problems during testing, please report
27 | them to the
28 | GitHub
29 | issues page along with the names of any failed tests.
30 |
31 |
32 |
33 | Checking changes
34 |
35 | If you've made some changes and just want to check they're
36 | working and test them out, use the
37 | debug test.
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/tests/loader.js:
--------------------------------------------------------------------------------
1 | /* eslint-env node */
2 | const libInstrument = require('istanbul-lib-instrument');
3 |
4 | module.exports = function (source, sourceMap) {
5 | const instrumenter = libInstrument.createInstrumenter({
6 | esModules: true
7 | });
8 |
9 | instrumenter.instrument(source, this.resourcePath, (err, instrumentedSource) => {
10 | this.callback(err, instrumentedSource, instrumenter.lastSourceMap());
11 | }, sourceMap);
12 | };
13 |
--------------------------------------------------------------------------------
/tests/manual/debug/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Debug Test - SCEditor
7 |
8 |
9 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
34 |
35 |
36 |
37 | Debug Test
38 |
39 |
40 |
41 | Constructor Options
42 |
43 |
51 |
52 |
53 |
54 |
55 | Testing Area
56 |
57 |
58 |
59 |
60 |
61 | Output:
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/tests/manual/debug/test.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | 'use strict';
3 |
4 | var evalConsoleInput = function () {
5 | try {
6 | var codeInput = document.querySelector('#console-input textarea');
7 | var code = codeInput.value;
8 |
9 | console.info('> ' + code);
10 |
11 | // eslint-disable-next-line no-eval
12 | eval.call(window, code);
13 | } catch (ex) {
14 | console.error(ex);
15 | }
16 | };
17 |
18 | var createEditor = function () {
19 | var coptionsInput = document.querySelector('#debug-options textarea');
20 | var optionsStr = coptionsInput.value;
21 |
22 | if (window.instance) {
23 | window.instance.destroy();
24 | }
25 |
26 | try {
27 | // eslint-disable-next-line no-new-func
28 | var options = (new Function('return ' + optionsStr))();
29 | var textarea = document.getElementById('testarea');
30 |
31 | sceditor.create(textarea, options);
32 | window.instance = sceditor.instance(textarea);
33 | } catch (ex) {
34 | console.error(ex);
35 | }
36 | };
37 |
38 | patchConsole();
39 | createEditor();
40 |
41 | document.querySelector('#console-input textarea')
42 | .addEventListener('keypress', function (e) {
43 | if (e.which === 13) {
44 | evalConsoleInput();
45 |
46 | return false;
47 | }
48 | });
49 |
50 | document.querySelector('#console-input input')
51 | .addEventListener('click', function () {
52 | evalConsoleInput();
53 |
54 | return false;
55 | });
56 |
57 | document.querySelector('#debug-options input')
58 | .addEventListener('click', function () {
59 | createEditor();
60 |
61 | return false;
62 | });
63 | }());
64 |
--------------------------------------------------------------------------------
/tests/manual/events/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Events Tests - SCEditor
7 |
8 |
10 |
16 |
17 |
18 |
19 |
20 |
21 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 | Events Tests
31 |
32 |
33 |
34 | Tests
35 |
36 |
37 |
38 |
39 | Current Test
40 |
41 |
42 |
43 | Skip this test
44 |
45 | Tests not loaded
46 |
47 | Check there are no JS errors in the tests.
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 | Test 0 / 0
57 |
58 |
59 |
60 |
61 |
62 | Testing Area
63 |
64 |
65 |
66 |
67 |
68 | Output:
69 |
70 |
71 |
72 |
73 |
74 |
--------------------------------------------------------------------------------
/tests/manual/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Manual Tests - SCEditor
7 |
8 |
10 |
11 |
12 |
13 | Manual Tests
14 |
15 |
16 |
17 | Manual Tests
18 |
19 |
20 | Debug
21 |
22 |
23 |
24 | Default Commands
25 |
26 |
27 |
28 | Events
29 |
30 |
31 |
32 | Memory
33 |
34 |
35 |
36 | ValueChanged
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/tests/manual/memory/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Memory Test - SCEditor
7 |
8 |
9 |
15 |
16 |
17 |
18 |
19 |
20 |
22 |
23 |
24 |
25 |
26 |
27 | Memory Tests
28 |
29 |
30 |
31 | Test Area
32 |
33 | This test will create and destroy SCEditor 100 times.
34 | To make sure there are no memory leaks you will need to manually
35 | check the memory usage.
36 |
37 | To do this you will need to create heap snapshots:
38 |
39 | -
40 | Chrome:
41 | Developer tools -> Profiles -> Take Heap Snapshot
42 |
43 | -
44 | IE 11+:
45 | Developer tools -> Memory -> Take Heap Snapshot
46 |
47 |
48 |
49 | To perform this test:
50 |
51 | -
52 | Start the test and once complete create the first heap
53 | snapshot.
54 |
55 | -
56 | Run the test again and create another heap snapshot.
57 |
58 | -
59 | Compare the memory usage between the two snapshots.
60 |
61 |
62 | If the memory usage is less than or equal to the memory usage
63 | of the first snapshot then there's no leaks.
64 | If the memory usage has increased compared to the first
65 | snapshot then you will need to search though the snapshot to
66 | make sure there are no references to SCEditor left.
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/tests/manual/memory/test.js:
--------------------------------------------------------------------------------
1 | var testMemoryLeaks = function (pos) {
2 | pos = pos || 1;
3 |
4 | $('#testarea').sceditor({
5 | autofocus: true,
6 | autofocusEnd: true,
7 | enablePasteFiltering: true,
8 | emoticonsRoot: '../../../',
9 | style: '../../../src/themes/content/default.css'
10 | });
11 |
12 | $('#testarea').sceditor('instance').destroy();
13 | $('#progress').width(pos + '%');
14 |
15 | if (pos <= 100) {
16 | setTimeout(function () {
17 | testMemoryLeaks(pos + 1);
18 | });
19 | }
20 | };
21 |
22 | $(function () {
23 | $('input[type="submit"]').click(function () {
24 | testMemoryLeaks();
25 |
26 | return false;
27 | });
28 | });
29 |
--------------------------------------------------------------------------------
/tests/manual/patchConsole.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | 'use strict';
3 |
4 | var _formatObject = function (obj) {
5 | if (!obj) {
6 | return obj;
7 | }
8 |
9 | if (obj instanceof Error) {
10 | var errorMsg = 'Error: ' + (obj.message || obj.description);
11 |
12 | if (obj.stack) {
13 | errorMsg += '\n' + obj.stack;
14 | }
15 |
16 | return errorMsg;
17 | }
18 |
19 | return String(obj);
20 | };
21 |
22 | var _patchConsoleMethod = function (output, method) {
23 | var originalMethod = console[method];
24 |
25 | return function (msg) {
26 | var div = document.createElement('div');
27 | div.className = method;
28 | div.textContent = _formatObject(msg);
29 |
30 | output.appendChild(div);
31 | output.scrollTop = output.scrollHeight;
32 |
33 | if (!originalMethod) {
34 | return;
35 | }
36 |
37 | if (originalMethod.apply) {
38 | originalMethod.apply(this, arguments);
39 | } else {
40 | originalMethod(msg);
41 | }
42 | };
43 | };
44 |
45 | var _patchAssertMethod = function (output) {
46 | var originalMethod = console.assert;
47 |
48 | return function (assertion, msg) {
49 | var assertion = document.createElement('span');
50 | assertion.textContent = assertion ? 'Assertion passed: ' :
51 | 'Assertion failed: ';
52 |
53 | var div = document.createElement('div');
54 | div.className = 'assert';
55 | div.className += assertion ? ' assert-passed' : ' assert-failed';
56 |
57 | div.appendChild(assertion);
58 | div.appendChild(document.createTextNode(msg));
59 |
60 | output.appendChild(div);
61 | output.scrollTop = output.scrollHeight;
62 |
63 | if (!originalMethod) {
64 | return;
65 | }
66 |
67 | if (originalMethod.apply) {
68 | originalMethod.apply(this, arguments);
69 | } else {
70 | originalMethod(msg);
71 | }
72 | };
73 | };
74 |
75 | var _patchClearMethod = function (output) {
76 | var originalMethod = console.clear;
77 |
78 | return function () {
79 | output.innerHTML = '';
80 |
81 | if (!originalMethod) {
82 | return;
83 | }
84 |
85 | if (originalMethod.apply) {
86 | originalMethod.apply(this, arguments);
87 | } else {
88 | originalMethod();
89 | }
90 | };
91 | };
92 |
93 | window.patchConsole = function (outputDiv) {
94 | var output = outputDiv || document.getElementById('console-output');
95 |
96 | console.info = _patchConsoleMethod(output, 'info');
97 | console.warn = _patchConsoleMethod(output, 'warn');
98 | console.error = _patchConsoleMethod(output, 'error');
99 | console.debug = _patchConsoleMethod(output, 'debug');
100 | console.log = _patchConsoleMethod(output, 'log');
101 | console.assert = _patchAssertMethod(output);
102 | console.clear = _patchClearMethod(output);
103 |
104 | window.onerror = function (msg, url, line) {
105 | console.error('Caught global error: ' + msg +
106 | ' on line ' + line + ' of ' + url);
107 | };
108 | };
109 | }());
110 |
--------------------------------------------------------------------------------
/tests/manual/valuechanged/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ValueChanged Test - SCEditor
7 |
8 |
9 |
15 |
16 |
17 |
18 |
19 |
20 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | ValueChanged Test
30 |
31 |
32 |
33 | Tests
34 |
35 |
36 |
37 |
38 | Current Test
39 |
40 |
41 |
42 | Skip this test
43 |
44 | Tests not loaded
45 |
46 | Check there are no JS errors in the tests.
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 | Test 0 / 0
56 |
57 |
58 |
59 |
60 |
61 | Test Area
62 |
63 |
64 | ValueChanged counter: 0
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 | Output:
76 |
77 |
78 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/tests/unit/closeAssert.js:
--------------------------------------------------------------------------------
1 | var isNear = function (actual, expected, maxDiff) {
2 | return (actual >= expected - maxDiff || actual <= expected + maxDiff);
3 | };
4 |
5 | QUnit.assert.close = function (actual, expected, maxDiff, message) {
6 | message = message || 'Expected ' + actual +
7 | ' to be within ' + expected + '+-' + maxDiff;
8 |
9 | this.pushResult({
10 | result: isNear(actual, expected, maxDiff),
11 | actual: actual,
12 | expected: expected + ' +-' + maxDiff,
13 | message: message
14 | });
15 | };
16 |
17 | QUnit.assert.notClose = function (actual, expected, maxDiff, message) {
18 | message = message || 'Expected ' + actual +
19 | ' to not be within ' + expected + '+-' + maxDiff;
20 |
21 | this.pushResult({
22 | result: !isNear(actual, expected, maxDiff),
23 | actual: actual,
24 | expected: expected + ' +-' + maxDiff,
25 | message: message
26 | });
27 | };
28 |
--------------------------------------------------------------------------------
/tests/unit/formats/bbcode/nesting.js:
--------------------------------------------------------------------------------
1 | import defaultOptions from 'src/lib/defaultOptions.js';
2 | import 'src/formats/bbcode.js';
3 |
4 | QUnit.module('plugins/bbcode - Nesting');
5 |
6 | QUnit.test('inline bbcodes must be inside block ones', assert => {
7 | sceditor.formats.bbcode.set(
8 | 'thisblockstyle', {
9 | styles: {
10 | border: null
11 | },
12 | isInline: false,
13 | format: '[block]{0}[/block]',
14 | html: '{0} '
15 | }
16 | );
17 | sceditor.formats.bbcode.set(
18 | 'thisinlinestyle', {
19 | styles: {
20 | opacity: null
21 | },
22 | format: '[inline]{0}[/inline]',
23 | html: '{0} '
24 | }
25 | );
26 | sceditor.formats.bbcode.set(
27 | 'thisblockbbcode', {
28 | tags: {
29 | block: {
30 | test: null
31 | }
32 | },
33 | isInline: false,
34 | format: '[block]{0}[/block]',
35 | html: '{0} '
36 | }
37 | );
38 | sceditor.formats.bbcode.set(
39 | 'thisinlinebbcode', {
40 | tags: {
41 | block: {
42 | testing: null
43 | }
44 | },
45 | format: '[inline]{0}[/inline]',
46 | html: '{0} '
47 | }
48 | );
49 |
50 | var mockEditor = {
51 | opts: defaultOptions
52 | };
53 | var format = new sceditor.formats.bbcode;
54 | format.init.call(mockEditor);
55 |
56 | assert.equal(
57 | mockEditor.toBBCode(' '),
58 | '[block][inline][/inline][/block]'
59 | );
60 | assert.equal(
61 | mockEditor.toBBCode(' '),
62 | '[block][inline][/inline][/block]'
63 | );
64 |
65 | sceditor.formats.bbcode.remove('thisblockstyle');
66 | sceditor.formats.bbcode.remove('thisinlinestyle');
67 | sceditor.formats.bbcode.remove('thisblockbbcode');
68 | sceditor.formats.bbcode.remove('thisinlinebbcode');
69 | });
70 |
--------------------------------------------------------------------------------
/tests/unit/htmlAssert.js:
--------------------------------------------------------------------------------
1 | import * as utils from 'tests/unit/utils.js';
2 |
3 | var normalize = function (parentNode) {
4 | var nextSibling,
5 | node = parentNode.firstChild;
6 |
7 | while (node) {
8 | if (node.nodeType === 3) {
9 | while ((nextSibling = node.nextSibling) &&
10 | nextSibling.nodeType === 3) {
11 |
12 | node.nodeValue += nextSibling.nodeValue;
13 | parentNode.removeChild(nextSibling);
14 | }
15 | } else {
16 | normalize(node);
17 | }
18 |
19 | node = node.nextSibling;
20 | }
21 | };
22 |
23 | var compareNodes = function (nodeA, nodeB) {
24 | if (nodeA.nodeName && nodeB.nodeName &&
25 | nodeA.nodeName.toLowerCase() !== nodeB.nodeName.toLowerCase() ||
26 | nodeA.nodeValue !== nodeB.nodeValue ||
27 | nodeA.nodeType !== nodeB.nodeType ||
28 | nodeA.className !== nodeB.className) {
29 | return false;
30 | }
31 |
32 | if (nodeA.nodeType === 1) {
33 | if (nodeA.attributes.length !== nodeB.attributes.length ||
34 | nodeA.childNodes.length !== nodeB.childNodes.length) {
35 | return false;
36 | }
37 | for (var attrIdx = 0; attrIdx < nodeA.attributes.length; attrIdx++) {
38 | var aAttr = nodeA.attributes[attrIdx];
39 |
40 | if (typeof aAttr.specified === 'undefined' || aAttr.specified) {
41 | if (aAttr.name === 'style') {
42 | if (nodeA.style.cssText !== nodeB.style.cssText) {
43 | return false;
44 | }
45 | } else if (nodeB.getAttribute(aAttr.name) !== aAttr.value) {
46 | return false;
47 | }
48 | }
49 | }
50 |
51 | for (var i = 0; i < nodeA.childNodes.length; i++) {
52 | if (!compareNodes(nodeA.childNodes[i], nodeB.childNodes[i])) {
53 | return false;
54 | }
55 | }
56 | }
57 |
58 | return true;
59 | };
60 |
61 | var compareHtml = function (actual, expected) {
62 | if (actual === expected) {
63 | return true;
64 | }
65 |
66 | if (!actual || !expected || typeof actual !== 'string' ||
67 | typeof expected !== 'string') {
68 | return false;
69 | }
70 |
71 | var nodeA = utils.htmlToDiv(actual);
72 | var nodeB = utils.htmlToDiv(expected);
73 |
74 | if (nodeA.innerHTML === nodeB.innerHTML) {
75 | return true;
76 | }
77 |
78 | return compareNodes(nodeA, nodeB);
79 | };
80 |
81 | function nodeToString(node) {
82 | if (node.nodeType === Node.TEXT_NODE) {
83 | return node.nodeValue;
84 | }
85 |
86 | if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
87 | const template = document.createElement('template');
88 | template.append(node.cloneNode(true));
89 |
90 | return template.innerHTML;
91 | }
92 |
93 | return node.outerHTML;
94 | }
95 |
96 | QUnit.assert.htmlEqual = function (actual, expected, message) {
97 | this.pushResult({
98 | result: compareHtml(actual, expected),
99 | actual: actual,
100 | expected: expected,
101 | message: message || 'Expected HTML to be equal'
102 | });
103 | };
104 |
105 | QUnit.assert.htmlNotEqual = function (actual, expected, message) {
106 | this.pushResult({
107 | result: !compareHtml(actual, expected),
108 | actual: actual,
109 | expected: expected,
110 | message: message || 'Expected HTML to not be equal'
111 | });
112 | };
113 |
114 | QUnit.assert.nodesEqual = function (actual, expected, message) {
115 | normalize(actual);
116 | normalize(expected);
117 |
118 | this.pushResult({
119 | result: compareNodes(actual, expected),
120 | actual: nodeToString(actual),
121 | expected: nodeToString(expected),
122 | message: message || 'Expected nodes to be equal'
123 | });
124 | };
125 |
126 | QUnit.assert.nodesNodeEqual = function (actual, expected, message) {
127 | normalize(actual);
128 | normalize(expected);
129 |
130 | this.pushResult({
131 | result: !compareNodes(actual, expected),
132 | actual: nodeToString(actual),
133 | expected: nodeToString(expected),
134 | message: message || 'Expected nodes to not be equal'
135 | });
136 | };
137 |
--------------------------------------------------------------------------------
/tests/unit/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SCEditor Tests
6 |
7 |
8 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/tests/unit/index.js:
--------------------------------------------------------------------------------
1 | import 'src/jquery.sceditor.js';
2 | import 'tests/unit/closeAssert.js';
3 | import 'tests/unit/htmlAssert.js';
4 | import 'tests/unit/lib/PluginManager.js';
5 | import 'tests/unit/lib/RangeHelper.js';
6 | import 'tests/unit/lib/SCEditor.js';
7 | import 'tests/unit/lib/dom.js';
8 | import 'tests/unit/lib/emoticons.js';
9 | import 'tests/unit/lib/escape.js';
10 | import 'tests/unit/lib/utils.js';
11 | import 'tests/unit/formats/bbcode.js';
12 | import 'tests/unit/formats/bbcode.parser.js';
13 | import 'tests/unit/formats/bbcode/matching.js';
14 | import 'tests/unit/formats/bbcode/nesting.js';
15 | import 'tests/unit/formats/xhtml.js';
16 | import 'tests/unit/plugins/autoyoutube.js';
17 | import 'tests/unit/jquery.sceditor.js';
18 |
--------------------------------------------------------------------------------
/tests/unit/init.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | // Report QUnit results to SauceLabs
3 | var log = [];
4 |
5 | QUnit.config.autostart = false;
6 |
7 | QUnit.on('runEnd', function (testResults) {
8 | var tests = [];
9 |
10 | for (var i = 0, len = log.length; i < len; i++) {
11 | var details = log[i];
12 | tests.push({
13 | name: details.name,
14 | result: details.result,
15 | expected: details.expected,
16 | actual: details.actual,
17 | source: details.source
18 | });
19 | }
20 |
21 | testResults.tests = tests;
22 |
23 | // Send istanbul coverage to grunt
24 | if (window.__grunt_contrib_qunit__) {
25 | window.__grunt_contrib_qunit__('qunit.coverage', window.__coverage__);
26 | }
27 | });
28 |
29 | // Add moduleSetup and moduleTeardown properties to the
30 | // modules settings and add support for a module fixture
31 | // div#qunit-module-fixture
32 | var oldModule = QUnit.module;
33 | QUnit.module = function (name, settings) {
34 | settings = settings || {};
35 |
36 | if (settings.moduleSetup) {
37 | QUnit.moduleStart(function (details) {
38 | $('#qunit-module-fixture').empty();
39 |
40 | if (details.name === name) {
41 | settings.moduleSetup();
42 | }
43 | });
44 | }
45 |
46 | if (settings.moduleTeardown) {
47 | QUnit.moduleDone(function (details) {
48 | if (details.name === name) {
49 | settings.moduleTeardown();
50 | }
51 |
52 | $('#qunit-module-fixture').empty();
53 | });
54 | }
55 |
56 | oldModule(name, settings);
57 | };
58 |
59 | QUnit.on('testStart', function (testDetails) {
60 | QUnit.log = function (details) {
61 | if (!details.result) {
62 | details.name = testDetails.name;
63 | log.push(details);
64 | }
65 | };
66 | });
67 |
68 | less.pageLoadFinished.then(() => {
69 | QUnit.start();
70 | });
71 | }());
72 |
--------------------------------------------------------------------------------
/tests/unit/jquery.sceditor.js:
--------------------------------------------------------------------------------
1 | import 'src/jquery.sceditor.js';
2 |
3 | var textarea;
4 | var sceditor;
5 |
6 | QUnit.module('jquery.sceditor', {
7 | beforeEach: function () {
8 | $.sceditor.defaultOptions.emoticonsRoot = '../../';
9 |
10 | var fixture = document.getElementById('qunit-fixture');
11 |
12 | textarea = document.createElement('textarea');
13 | fixture.appendChild(textarea);
14 |
15 | $(textarea).sceditor({
16 | style: '../../src/themes/content/default.css'
17 | });
18 | sceditor = textarea._sceditor;
19 | },
20 | afterEach: function () {
21 | $.sceditor.defaultOptions.emoticonsRoot = '';
22 | }
23 | });
24 |
25 | QUnit.test('sceditor(\'instance\')', function (assert) {
26 | assert.ok($(textarea).sceditor('instance') === sceditor);
27 | });
28 |
--------------------------------------------------------------------------------
/tests/unit/lib/escape.js:
--------------------------------------------------------------------------------
1 | import * as escape from 'src/lib/escape.js';
2 |
3 | QUnit.module('lib/escape');
4 |
5 |
6 | QUnit.test('regex()', function (assert) {
7 | assert.equal(
8 | escape.regex('- \\ ^ / $ * + ? . ( ) | { } [ ] | ! :'),
9 | '\\- \\\\ \\^ \\/ \\$ \\* \\+ \\? \\. \\( \\) \\| ' +
10 | '\\{ \\} \\[ \\] \\| \\! \\:'
11 | );
12 | });
13 |
14 | QUnit.test('regex() - Emoticons', function (assert) {
15 | assert.equal(
16 | escape.regex('^^ >.< =)'),
17 | '\\^\\^ >\\.< \\=\\)'
18 | );
19 | });
20 |
21 |
22 | QUnit.test('entities()', function (assert) {
23 | assert.strictEqual(escape.entities(null), null);
24 | assert.strictEqual(escape.entities(''), '');
25 |
26 | assert.equal(
27 | escape.entities('& < > " \' `'),
28 | '& < > " ' `'
29 | );
30 |
31 | assert.equal(
32 | escape.entities('& < > " \' `', false),
33 | '& < > " \' `'
34 | );
35 | });
36 |
37 | QUnit.test('entities() - XSS', function (assert) {
38 | assert.equal(
39 | escape.entities(''),
40 | '<script>alert("XSS");</script>'
41 | );
42 | });
43 |
44 | QUnit.test('entities() - IE XSS', function (assert) {
45 | assert.equal(
46 | escape.entities('
'),
47 | '<img src="x" alt="``onerror=alert(1)" />'
48 | );
49 | });
50 |
51 |
52 | QUnit.test('uriScheme() - No schmes', function (assert) {
53 | var urls = [
54 | '',
55 | '/test.html',
56 | '//localhost/test.html',
57 | 'www.example.com/test?id=123'
58 | ];
59 |
60 | assert.expect(urls.length);
61 |
62 | for (var i = 0; i < urls.length; i++) {
63 | var url = urls[i];
64 |
65 | assert.equal(escape.uriScheme(url), url);
66 | }
67 | });
68 |
69 | QUnit.test('uriScheme() - Valid schmes', function (assert) {
70 | var urls = [
71 | 'http://localhost',
72 | 'https://example.com/test.html',
73 | 'ftp://localhost',
74 | 'sftp://example.com/test/',
75 | 'mailto:user@localhost',
76 | 'spotify:xyz',
77 | 'skype:xyz',
78 | 'ssh:user@host.com:22',
79 | 'teamspeak:12345',
80 | 'tel:12345',
81 | '//www.example.com/test?id=123',
82 | 'data:image/png;test',
83 | 'data:image/gif;test',
84 | 'data:image/jpg;test',
85 | 'data:image/bmp;test'
86 | ];
87 |
88 | assert.expect(urls.length);
89 |
90 | for (var i = 0; i < urls.length; i++) {
91 | var url = urls[i];
92 |
93 | assert.equal(escape.uriScheme(url), url);
94 | }
95 | });
96 |
97 | QUnit.test('uriScheme() - Invalid schmes', function (assert) {
98 | var path = location.pathname.split('/');
99 | path.pop();
100 |
101 | var baseUrl = location.protocol + '//' +
102 | location.host +
103 | path.join('/') + '/';
104 |
105 | /*jshint scripturl:true*/
106 | var urls = [
107 | // eslint-disable-next-line no-script-url
108 | 'javascript:alert("XSS");',
109 | 'jav ascript:alert(\'XSS\');',
110 | 'vbscript:msgbox("XSS")',
111 | 'data:application/javascript;alert("xss")'
112 | ];
113 |
114 | assert.expect(urls.length);
115 |
116 | for (var i = 0; i < urls.length; i++) {
117 | var url = urls[i];
118 |
119 | assert.equal(escape.uriScheme(url), baseUrl + url);
120 | }
121 | });
122 |
--------------------------------------------------------------------------------
/tests/unit/utils.js:
--------------------------------------------------------------------------------
1 | export function htmlToDiv(html) {
2 | var container = document.createElement('div');
3 |
4 | container.innerHTML = html;
5 |
6 | $('#qunit-fixture').append(container);
7 |
8 | return container;
9 | };
10 |
11 | export function htmlToNode(html) {
12 | var container = htmlToDiv(html);
13 | var childNodes = [];
14 |
15 | for (var i = 0; i < container.childNodes.length; i++) {
16 | childNodes.push(container.childNodes[i]);
17 | }
18 |
19 | return childNodes.length === 1 ? childNodes[0] : childNodes;
20 | };
21 |
22 | export function htmlToFragment(html) {
23 | var container = htmlToDiv(html);
24 | var frag = document.createDocumentFragment();
25 |
26 | while (container.firstChild) {
27 | frag.appendChild(container.firstChild);
28 | }
29 |
30 | return frag;
31 | }
32 |
33 | export function nodeToHtml(node) {
34 | var container = document.createElement('div');
35 | container.appendChild(node);
36 |
37 | return container.innerHTML;
38 | };
39 |
40 | export function stripWhiteSpace(str) {
41 | if (!str) {
42 | return str;
43 | }
44 |
45 | return str.replace(/[\r\n\s\t]/g, '');
46 | }
47 |
--------------------------------------------------------------------------------