Changes the TinyMCE workflow for building and compiling plugins
git-svn-id: https://svn.libreccm.org/ccm/trunk@5812 8810af33-2d31-482b-a856-94f89814c4dfmaster
parent
2c736f7c97
commit
1d4a0804c7
File diff suppressed because it is too large
Load Diff
|
|
@ -12,8 +12,11 @@ waf.bebop.dhtml_editor_src=/assets/tinymce/js/tinymce/tinymce.min.js
|
||||||
|
|
||||||
This change will only take effect after you've run `ant load-bundle` again and restarted your installation.
|
This change will only take effect after you've run `ant load-bundle` again and restarted your installation.
|
||||||
|
|
||||||
## How to compile an individual plugin
|
## How to compile the editor and the plugins
|
||||||
|
|
||||||
After you changed a plugin in `tools-ng/tinymce/plugins`, you may want to see this changes reflected in your installation for testing. To do this, you need to change into the directory of the plugin and execute `npm run build`. Of course you need to have `npm` installed to do this.
|
Use the handy `tinymce.sh` script for that. You can do the following things:
|
||||||
|
|
||||||
After you've done this, you need to recompile your code. You can do this by running `ant deploy`.
|
- `./tinymce.sh` - Sets up the environment for compiling and builds the whole editor with all plugins. You can find the compiled files in `editor/js`
|
||||||
|
- `./tinymce.sh build` - Builds everything (Editor, Plugins, Themes, ...)
|
||||||
|
- `./tinymce.sh plugin <name>` - To compile a single plugin run this with the desired plugin name. The plugin will also be copied into `ccm-core`
|
||||||
|
- `./tinymce.sh test <name>` - Similar to `plugin`, but without linting and copies the files into the current runtime for instant testing.
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,24 @@
|
||||||
|
Version 4.9.2 (2018-12-17)
|
||||||
|
Fixed a bug with pressing the space key on IE 11 would result in nbsp characters being inserted between words at the end of a block. #TINY-2996
|
||||||
|
Fixed a bug where character composition using quote and space on US International keyboards would produce a space instead of a quote. #TINY-2999
|
||||||
|
Fixed a bug where remove format wouldn't remove the inner most inline element in some situations. #TINY-2982
|
||||||
|
Fixed a bug where outdenting an list item would affect attributes on other list items within the same list. #TINY-2971
|
||||||
|
Fixed a bug where the DomParser filters wouldn't be applied for elements created when parsing invalid html. #TINY-2978
|
||||||
|
Fixed a bug where setProgressState wouldn't automatically close floating ui elements like menus. #TINY-2896
|
||||||
|
Fixed a bug where it wasn't possible to navigate out of a figcaption element using the arrow keys. #TINY-2894
|
||||||
|
Fixed a bug where enter key before an image inside a link would remove the image. #TINY-2780
|
||||||
|
Version 4.9.1 (2018-12-04)
|
||||||
|
Added functionality to insert html to the replacement feature of the Textpattern Plugin. #TINY-2839
|
||||||
|
Fixed a bug where `editor.selection.getContent({format: 'text'})` didn't work as expected in IE11 on an unfocused editor. #TINY-2862
|
||||||
|
Fixed a bug in the Textpattern Plugin where the editor would get an incorrect selection after inserting a text pattern on Safari. #TINY-2838
|
||||||
|
Fixed a bug where the space bar didn't work correctly in editors with the forced_root_block setting set to false. #TINY-2816
|
||||||
|
Version 4.9.0 (2018-11-27)
|
||||||
|
Added a replace feature to the Textpattern Plugin. #TINY-1908
|
||||||
|
Added functionality to the Lists Plugin that improves the indentation logic. #TINY-1790
|
||||||
|
Fixed a bug where it wasn't possible to delete/backspace when the caret was between a contentEditable=false element and a BR. #TINY-2372
|
||||||
|
Fixed a bug where copying table cells without a text selection would fail to copy anything. #TINY-1789
|
||||||
|
Implemented missing `autosave_restore_when_empty` functionality in the Autosave Plugin. Patch contributed by gzzo. #GH-4447
|
||||||
|
Reduced insertion of unnecessary nonbreaking spaces in the editor. #TINY-1879
|
||||||
Version 4.8.5 (2018-10-30)
|
Version 4.8.5 (2018-10-30)
|
||||||
Added a content_css_cors setting to the editor that adds the crossorigin="anonymous" attribute to link tags added by the StyleSheetLoader. #TINY-1909
|
Added a content_css_cors setting to the editor that adds the crossorigin="anonymous" attribute to link tags added by the StyleSheetLoader. #TINY-1909
|
||||||
Fixed a bug where trying to remove formatting with a collapsed selection range would throw an exception. #GH-4636
|
Fixed a bug where trying to remove formatting with a collapsed selection range would throw an exception. #GH-4636
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
root = true
|
|
||||||
|
|
||||||
[*]
|
|
||||||
charset = utf-8
|
|
||||||
indent_style = space
|
|
||||||
indent_size = 2
|
|
||||||
trim_trailing_whitespace = true
|
|
||||||
end_of_line = lf
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
* eol=lf
|
|
||||||
*.jar binary
|
|
||||||
*.gif binary
|
|
||||||
*.png binary
|
|
||||||
*.jpg binary
|
|
||||||
*.swf binary
|
|
||||||
*.xap binary
|
|
||||||
*.zip binary
|
|
||||||
*.eot binary
|
|
||||||
*.woff binary
|
|
||||||
*.ttf binary
|
|
||||||
*.mov binary
|
|
||||||
*.avi binary
|
|
||||||
*.flv binary
|
|
||||||
*.rm binary
|
|
||||||
*.dcr binary
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
**Do you want to request a *feature* or report a *bug*?**
|
|
||||||
|
|
||||||
**What is the current behavior?**
|
|
||||||
|
|
||||||
**If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem via [fiddle.tinymce.com](http://fiddle.tinymce.com/) or similar.**
|
|
||||||
|
|
||||||
**What is the expected behavior?**
|
|
||||||
|
|
||||||
**Which versions of TinyMCE, and which browser / OS are affected by this issue? Did this work in previous versions of TinyMCE?**
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
**Before submitting a pull request** please do the following:
|
|
||||||
|
|
||||||
1. Fork [the repository](https://github.com/tinymce/tinymce) and create your branch from `master`
|
|
||||||
2. Have you added some code that should be tested? Write some tests! (Are you unsure how to write the test you want to write, ask us for help!)
|
|
||||||
3. Ensure that the tests pass: `grunt test`
|
|
||||||
4. Ensure that your code passes the linter: `grunt lint`
|
|
||||||
5. Make sure to sign the CLA.
|
|
||||||
|
|
@ -1,825 +0,0 @@
|
||||||
/*eslint-env node */
|
|
||||||
|
|
||||||
let zipUtils = require('./tools/modules/zip-helper');
|
|
||||||
let gruntUtils = require('./tools/modules/grunt-utils');
|
|
||||||
let gruntWebPack = require('./tools/modules/grunt-webpack');
|
|
||||||
let swag = require('@ephox/swag');
|
|
||||||
let path = require('path');
|
|
||||||
|
|
||||||
let plugins = [
|
|
||||||
'advlist', 'anchor', 'autolink', 'autoresize', 'autosave', 'bbcode', 'charmap', 'code', 'codesample',
|
|
||||||
'colorpicker', /*'compat3x', */ 'contextmenu', 'directionality', 'emoticons', 'help', 'fullpage',
|
|
||||||
'fullscreen', 'hr', 'image', 'imagetools', 'importcss', 'insertdatetime', 'legacyoutput', 'link',
|
|
||||||
'lists', 'media', 'nonbreaking', 'noneditable', 'pagebreak', 'paste', 'preview', 'print', 'save',
|
|
||||||
'searchreplace', 'spellchecker', 'tabfocus', 'table', 'template', 'textcolor', 'textpattern', 'toc',
|
|
||||||
'visualblocks', 'visualchars', 'wordcount',
|
|
||||||
];
|
|
||||||
|
|
||||||
let themes = [
|
|
||||||
'modern', 'mobile', 'inlite'
|
|
||||||
];
|
|
||||||
|
|
||||||
module.exports = function (grunt) {
|
|
||||||
var packageData = grunt.file.readJSON('package.json');
|
|
||||||
var changelogLine = grunt.file.read('changelog.txt').toString().split('\n')[0];
|
|
||||||
var BUILD_VERSION = packageData.version + '-' + (process.env.BUILD_NUMBER ? process.env.BUILD_NUMBER : '0');
|
|
||||||
packageData.date = /^Version [^\(]+\(([^\)]+)\)/.exec(changelogLine)[1];
|
|
||||||
|
|
||||||
grunt.initConfig({
|
|
||||||
pkg: packageData,
|
|
||||||
|
|
||||||
shell: {
|
|
||||||
tsc: { command: 'node ./node_modules/typescript/bin/tsc' }
|
|
||||||
},
|
|
||||||
|
|
||||||
tslint: {
|
|
||||||
options: {
|
|
||||||
configuration: 'tslint.json'
|
|
||||||
},
|
|
||||||
files: { src: [ 'src/**/*.ts' ] }
|
|
||||||
},
|
|
||||||
|
|
||||||
globals: {
|
|
||||||
options: {
|
|
||||||
configFile: 'src/core/main/json/globals.json',
|
|
||||||
outputDir: 'lib/globals',
|
|
||||||
templateFile: 'src/core/main/js/GlobalsTemplate.js'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
rollup: Object.assign(
|
|
||||||
{
|
|
||||||
core: {
|
|
||||||
options: {
|
|
||||||
treeshake: true,
|
|
||||||
name: 'tinymce',
|
|
||||||
format: 'iife',
|
|
||||||
banner: '(function () {',
|
|
||||||
footer: '})();',
|
|
||||||
plugins: [
|
|
||||||
swag.nodeResolve({
|
|
||||||
basedir: __dirname,
|
|
||||||
prefixes: {
|
|
||||||
'tinymce/core': 'lib/core/main/ts'
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
swag.remapImports()
|
|
||||||
]
|
|
||||||
},
|
|
||||||
files:[
|
|
||||||
{
|
|
||||||
src: 'lib/core/main/ts/api/Main.js',
|
|
||||||
dest: 'js/tinymce/tinymce.js'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
gruntUtils.generate(plugins, 'plugin', (name) => {
|
|
||||||
return {
|
|
||||||
options: {
|
|
||||||
treeshake: true,
|
|
||||||
name: name,
|
|
||||||
format: 'iife',
|
|
||||||
banner: '(function () {',
|
|
||||||
footer: '})();',
|
|
||||||
plugins: [
|
|
||||||
swag.nodeResolve({
|
|
||||||
basedir: __dirname,
|
|
||||||
prefixes: gruntUtils.prefixes({
|
|
||||||
'tinymce/core': 'lib/globals/tinymce/core'
|
|
||||||
}, [
|
|
||||||
[`tinymce/plugins/${name}`, `lib/plugins/${name}/main/ts`]
|
|
||||||
])
|
|
||||||
}),
|
|
||||||
swag.remapImports()
|
|
||||||
]
|
|
||||||
},
|
|
||||||
files:[ { src: `lib/plugins/${name}/main/ts/Plugin.js`, dest: `js/tinymce/plugins/${name}/plugin.js` } ]
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
gruntUtils.generate(themes, 'theme', (name) => {
|
|
||||||
return {
|
|
||||||
options: {
|
|
||||||
treeshake: true,
|
|
||||||
name: name,
|
|
||||||
format: 'iife',
|
|
||||||
banner: '(function () {',
|
|
||||||
footer: '})();',
|
|
||||||
plugins: [
|
|
||||||
swag.nodeResolve({
|
|
||||||
basedir: __dirname,
|
|
||||||
prefixes: gruntUtils.prefixes({
|
|
||||||
'tinymce/core': 'lib/globals/tinymce/core',
|
|
||||||
'tinymce/ui': 'lib/ui/main/ts'
|
|
||||||
}, [
|
|
||||||
[`tinymce/themes/${name}`, `lib/themes/${name}/main/ts`]
|
|
||||||
])
|
|
||||||
}),
|
|
||||||
swag.remapImports()
|
|
||||||
]
|
|
||||||
},
|
|
||||||
files:[
|
|
||||||
{
|
|
||||||
src: `lib/themes/${name}/main/ts/Theme.js`,
|
|
||||||
dest: `js/tinymce/themes/${name}/theme.js`
|
|
||||||
}
|
|
||||||
]
|
|
||||||
};
|
|
||||||
})
|
|
||||||
),
|
|
||||||
|
|
||||||
uglify: Object.assign(
|
|
||||||
{
|
|
||||||
options: {
|
|
||||||
output: {
|
|
||||||
ascii_only: true,
|
|
||||||
},
|
|
||||||
ie8: true
|
|
||||||
},
|
|
||||||
core: {
|
|
||||||
files: [
|
|
||||||
{ src: 'js/tinymce/tinymce.js', dest: 'js/tinymce/tinymce.min.js' },
|
|
||||||
{ src: 'src/core/main/js/JqueryIntegration.js', dest: 'js/tinymce/jquery.tinymce.min.js' }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
'compat3x-plugin': {
|
|
||||||
files: [
|
|
||||||
{
|
|
||||||
src: 'src/plugins/compat3x/main/js/plugin.js',
|
|
||||||
dest: 'js/tinymce/plugins/compat3x/plugin.min.js'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
gruntUtils.generate(plugins, 'plugin', (name) => {
|
|
||||||
return {
|
|
||||||
files: [ { src: `js/tinymce/plugins/${name}/plugin.js`, dest: `js/tinymce/plugins/${name}/plugin.min.js` } ]
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
gruntUtils.generate(themes, 'theme', (name) => {
|
|
||||||
return {
|
|
||||||
files: [ { src: `js/tinymce/themes/${name}/theme.js`, dest: `js/tinymce/themes/${name}/theme.min.js` } ]
|
|
||||||
};
|
|
||||||
})
|
|
||||||
),
|
|
||||||
|
|
||||||
webpack: Object.assign(
|
|
||||||
{core: () => gruntWebPack.create('src/core/demo/ts/demo/Demos.ts', 'tsconfig.json', 'scratch/demos/core', 'demo.js')},
|
|
||||||
{plugins: () => gruntWebPack.allPlugins(plugins)},
|
|
||||||
{themes: () => gruntWebPack.allThemes(themes)},
|
|
||||||
gruntUtils.generate(plugins, 'plugin', (name) => () => gruntWebPack.createPlugin(name) ),
|
|
||||||
gruntUtils.generate(themes, 'theme', (name) => () => gruntWebPack.createTheme(name) )
|
|
||||||
),
|
|
||||||
|
|
||||||
'webpack-dev-server': {
|
|
||||||
options: {
|
|
||||||
webpack: gruntWebPack.all(plugins, themes),
|
|
||||||
publicPath: '/',
|
|
||||||
inline: false,
|
|
||||||
port: grunt.option('webpack-port') !== undefined ? grunt.option('webpack-port') : 3000,
|
|
||||||
host: '0.0.0.0',
|
|
||||||
disableHostCheck: true,
|
|
||||||
before: app => gruntWebPack.generateDemoIndex(grunt, app, plugins, themes)
|
|
||||||
},
|
|
||||||
start: { }
|
|
||||||
},
|
|
||||||
|
|
||||||
less: {
|
|
||||||
desktop: {
|
|
||||||
options: {
|
|
||||||
cleancss: true,
|
|
||||||
strictImports: true,
|
|
||||||
compress: true,
|
|
||||||
yuicompress: true,
|
|
||||||
sourceMap: true,
|
|
||||||
sourceMapRootpath: '.',
|
|
||||||
optimization: 2
|
|
||||||
},
|
|
||||||
files: {
|
|
||||||
'js/tinymce/skins/lightgray/skin.min.css': 'src/skins/lightgray/main/less/desktop/Skin.less'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mobile: {
|
|
||||||
options: {
|
|
||||||
plugins : [ new (require('less-plugin-autoprefix'))({ browsers : [ 'last 2 versions', /* for phantom */'safari >= 4' ] }) ],
|
|
||||||
compress: true,
|
|
||||||
yuicompress: true,
|
|
||||||
sourceMap: true,
|
|
||||||
sourceMapRootpath: '.',
|
|
||||||
optimization: 2
|
|
||||||
},
|
|
||||||
files: {
|
|
||||||
'js/tinymce/skins/lightgray/skin.mobile.min.css': 'src/skins/lightgray/main/less/mobile/app/mobile-less.less'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'content-mobile': {
|
|
||||||
options: {
|
|
||||||
cleancss: true,
|
|
||||||
strictImports: true,
|
|
||||||
compress: true
|
|
||||||
},
|
|
||||||
files: {
|
|
||||||
'js/tinymce/skins/lightgray/content.mobile.min.css': 'src/skins/lightgray/main/less/mobile/content.less'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
content: {
|
|
||||||
options: {
|
|
||||||
cleancss: true,
|
|
||||||
strictImports: true,
|
|
||||||
compress: true
|
|
||||||
},
|
|
||||||
files: {
|
|
||||||
'js/tinymce/skins/lightgray/content.min.css': 'src/skins/lightgray/main/less/desktop/Content.less'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'content-inline': {
|
|
||||||
options: {
|
|
||||||
cleancss: true,
|
|
||||||
strictImports: true,
|
|
||||||
compress: true
|
|
||||||
},
|
|
||||||
files: {
|
|
||||||
'js/tinymce/skins/lightgray/content.inline.min.css': 'src/skins/lightgray/main/less/desktop/Content.Inline.less'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
copy: {
|
|
||||||
core: {
|
|
||||||
options: {
|
|
||||||
process: function (content) {
|
|
||||||
return content.
|
|
||||||
replace('@@majorVersion@@', packageData.version.split('.')[0]).
|
|
||||||
replace('@@minorVersion@@', packageData.version.split('.').slice(1).join('.')).
|
|
||||||
replace('@@releaseDate@@', packageData.date);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
files: [
|
|
||||||
{
|
|
||||||
src: 'js/tinymce/tinymce.js',
|
|
||||||
dest: 'js/tinymce/tinymce.js'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
src: 'js/tinymce/tinymce.min.js',
|
|
||||||
dest: 'js/tinymce/tinymce.min.js'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
src: 'src/core/main/text/readme_lang.md',
|
|
||||||
dest: 'js/tinymce/langs/readme.md'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
src: 'LICENSE.TXT',
|
|
||||||
dest: 'js/tinymce/license.txt'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
skins: {
|
|
||||||
files: [
|
|
||||||
{
|
|
||||||
expand: true,
|
|
||||||
flatten: true,
|
|
||||||
cwd: 'src/skins/lightgray/main/fonts',
|
|
||||||
src: [
|
|
||||||
'**',
|
|
||||||
'!*.json',
|
|
||||||
'!*.md'
|
|
||||||
],
|
|
||||||
dest: 'js/tinymce/skins/lightgray/fonts'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
expand: true,
|
|
||||||
flatten: true,
|
|
||||||
cwd: 'src/skins/lightgray/main/img',
|
|
||||||
src: '**',
|
|
||||||
dest: 'js/tinymce/skins/lightgray/img'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
plugins: {
|
|
||||||
files: [
|
|
||||||
{ expand: true, cwd: 'src/plugins/compat3x/main', src: ['img/**'], dest: 'js/tinymce/plugins/compat3x' },
|
|
||||||
{ expand: true, cwd: 'src/plugins/compat3x/main', src: ['css/**'], dest: 'js/tinymce/plugins/compat3x' },
|
|
||||||
{ expand: true, cwd: 'src/plugins/compat3x/main/js', src: ['utils/**', 'plugin.js', 'tiny_mce_popup.js'], dest: 'js/tinymce/plugins/compat3x' },
|
|
||||||
{ src: 'src/plugins/codesample/main/css/prism.css', dest: 'js/tinymce/plugins/codesample/css/prism.css' }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
'emoticons-plugin': {
|
|
||||||
files: [
|
|
||||||
{
|
|
||||||
flatten: true,
|
|
||||||
expand: true,
|
|
||||||
cwd: 'src/plugins/emoticons/main/img',
|
|
||||||
src: '*.gif',
|
|
||||||
dest: 'js/tinymce/plugins/emoticons/img/'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
'help-plugin': {
|
|
||||||
files: [
|
|
||||||
{ src: 'src/plugins/help/main/img/logo.png', dest: 'js/tinymce/plugins/help/img/logo.png' }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
'visualblocks-plugin': {
|
|
||||||
files: [
|
|
||||||
{ src: 'src/plugins/visualblocks/main/css/visualblocks.css', dest: 'js/tinymce/plugins/visualblocks/css/visualblocks.css' }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
moxiezip: {
|
|
||||||
production: {
|
|
||||||
options: {
|
|
||||||
baseDir: 'tinymce',
|
|
||||||
excludes: [
|
|
||||||
'js/**/plugin.js',
|
|
||||||
'js/**/theme.js',
|
|
||||||
'js/**/*.map',
|
|
||||||
'js/tinymce/tinymce.full.min.js',
|
|
||||||
'js/tinymce/plugins/moxiemanager',
|
|
||||||
'js/tinymce/plugins/compat3x',
|
|
||||||
'js/tinymce/plugins/visualblocks/img',
|
|
||||||
'js/tinymce/skins/*/fonts/*.json',
|
|
||||||
'js/tinymce/skins/*/fonts/readme.md',
|
|
||||||
'readme.md'
|
|
||||||
],
|
|
||||||
to: 'tmp/tinymce_<%= pkg.version %>.zip'
|
|
||||||
},
|
|
||||||
src: [
|
|
||||||
'js/tinymce/langs',
|
|
||||||
'js/tinymce/plugins',
|
|
||||||
'js/tinymce/skins',
|
|
||||||
'js/tinymce/themes',
|
|
||||||
'js/tinymce/tinymce.min.js',
|
|
||||||
'js/tinymce/jquery.tinymce.min.js',
|
|
||||||
'js/tinymce/license.txt',
|
|
||||||
'changelog.txt',
|
|
||||||
'LICENSE.TXT',
|
|
||||||
'readme.md'
|
|
||||||
]
|
|
||||||
},
|
|
||||||
|
|
||||||
development: {
|
|
||||||
options: {
|
|
||||||
baseDir: 'tinymce',
|
|
||||||
excludes: [
|
|
||||||
'src/**/dist',
|
|
||||||
'src/**/scratch',
|
|
||||||
'src/**/lib',
|
|
||||||
'src/**/dependency',
|
|
||||||
'js/tinymce/tinymce.full.min.js',
|
|
||||||
'js/tests/.jshintrc'
|
|
||||||
],
|
|
||||||
to: 'tmp/tinymce_<%= pkg.version %>_dev.zip'
|
|
||||||
},
|
|
||||||
src: [
|
|
||||||
'config',
|
|
||||||
'src',
|
|
||||||
'js',
|
|
||||||
'tests',
|
|
||||||
'tools',
|
|
||||||
'changelog.txt',
|
|
||||||
'LICENSE.TXT',
|
|
||||||
'Gruntfile.js',
|
|
||||||
'readme.md',
|
|
||||||
'package.json',
|
|
||||||
'.eslintrc',
|
|
||||||
'.jscsrc',
|
|
||||||
'.jshintrc'
|
|
||||||
]
|
|
||||||
},
|
|
||||||
cdn: {
|
|
||||||
options: {
|
|
||||||
onBeforeSave: function (zip) {
|
|
||||||
zip.addData('dist/version.txt', packageData.version);
|
|
||||||
},
|
|
||||||
pathFilter: function (zipFilePath) {
|
|
||||||
return zipFilePath.replace('js/tinymce/', 'dist/');
|
|
||||||
},
|
|
||||||
excludes: [
|
|
||||||
'js/**/config',
|
|
||||||
'js/**/scratch',
|
|
||||||
'js/**/classes',
|
|
||||||
'js/**/lib',
|
|
||||||
'js/**/dependency',
|
|
||||||
'js/**/src',
|
|
||||||
'js/**/*.less',
|
|
||||||
'js/**/*.dev.js',
|
|
||||||
'js/**/*.dev.svg',
|
|
||||||
'js/**/*.map',
|
|
||||||
'js/tinymce/tinymce.full.min.js',
|
|
||||||
'js/tinymce/plugins/moxiemanager',
|
|
||||||
'js/tinymce/plugins/visualblocks/img',
|
|
||||||
'js/tinymce/skins/*/fonts/*.json',
|
|
||||||
'js/tinymce/skins/*/fonts/*.dev.svg',
|
|
||||||
'js/tinymce/skins/*/fonts/readme.md',
|
|
||||||
'readme.md',
|
|
||||||
'js/tests/.jshintrc'
|
|
||||||
],
|
|
||||||
concat: [
|
|
||||||
{
|
|
||||||
src: [
|
|
||||||
'js/tinymce/tinymce.min.js',
|
|
||||||
'js/tinymce/themes/*/theme.min.js',
|
|
||||||
'js/tinymce/plugins/*/plugin.min.js',
|
|
||||||
'!js/tinymce/plugins/compat3x/plugin.min.js',
|
|
||||||
'!js/tinymce/plugins/example/plugin.min.js',
|
|
||||||
'!js/tinymce/plugins/example_dependency/plugin.min.js'
|
|
||||||
],
|
|
||||||
|
|
||||||
dest: [
|
|
||||||
'js/tinymce/tinymce.min.js'
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
to: 'tmp/tinymce_<%= pkg.version %>_cdn.zip'
|
|
||||||
},
|
|
||||||
src: [
|
|
||||||
'js/tinymce/jquery.tinymce.min.js',
|
|
||||||
'js/tinymce/tinymce.js',
|
|
||||||
'js/tinymce/langs',
|
|
||||||
'js/tinymce/plugins',
|
|
||||||
'js/tinymce/skins',
|
|
||||||
'js/tinymce/themes',
|
|
||||||
'js/tinymce/license.txt'
|
|
||||||
]
|
|
||||||
},
|
|
||||||
|
|
||||||
component: {
|
|
||||||
options: {
|
|
||||||
excludes: [
|
|
||||||
'js/**/config',
|
|
||||||
'js/**/scratch',
|
|
||||||
'js/**/classes',
|
|
||||||
'js/**/lib',
|
|
||||||
'js/**/dependency',
|
|
||||||
'js/**/src',
|
|
||||||
'js/**/*.less',
|
|
||||||
'js/**/*.dev.svg',
|
|
||||||
'js/**/*.dev.js',
|
|
||||||
'js/**/*.map',
|
|
||||||
'js/tinymce/tinymce.full.min.js',
|
|
||||||
'js/tinymce/plugins/moxiemanager',
|
|
||||||
'js/tinymce/plugins/example',
|
|
||||||
'js/tinymce/plugins/example_dependency',
|
|
||||||
'js/tinymce/plugins/compat3x',
|
|
||||||
'js/tinymce/plugins/visualblocks/img',
|
|
||||||
'js/tinymce/skins/*/fonts/*.json',
|
|
||||||
'js/tinymce/skins/*/fonts/readme.md'
|
|
||||||
],
|
|
||||||
pathFilter: function (zipFilePath) {
|
|
||||||
if (zipFilePath.indexOf('js/tinymce/') === 0) {
|
|
||||||
return zipFilePath.substr('js/tinymce/'.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
return zipFilePath;
|
|
||||||
},
|
|
||||||
onBeforeSave: function (zip) {
|
|
||||||
function jsonToBuffer(json) {
|
|
||||||
return new Buffer(JSON.stringify(json, null, '\t'));
|
|
||||||
}
|
|
||||||
|
|
||||||
zip.addData('bower.json', jsonToBuffer({
|
|
||||||
'name': 'tinymce',
|
|
||||||
'description': 'Web based JavaScript HTML WYSIWYG editor control.',
|
|
||||||
'license': 'LGPL-2.1',
|
|
||||||
'keywords': ['editor', 'wysiwyg', 'tinymce', 'richtext', 'javascript', 'html'],
|
|
||||||
'homepage': 'http://www.tinymce.com',
|
|
||||||
'ignore': ['readme.md', 'composer.json', 'package.json', '.npmignore', 'changelog.txt']
|
|
||||||
}));
|
|
||||||
|
|
||||||
zip.addData('package.json', jsonToBuffer({
|
|
||||||
'name': 'tinymce',
|
|
||||||
'version': packageData.version,
|
|
||||||
'repository': {
|
|
||||||
'type': 'git',
|
|
||||||
'url': 'https://github.com/tinymce/tinymce-dist.git'
|
|
||||||
},
|
|
||||||
'description': 'Web based JavaScript HTML WYSIWYG editor control.',
|
|
||||||
'author': 'Ephox Corporation',
|
|
||||||
'main': 'tinymce.js',
|
|
||||||
'license': 'LGPL-2.1',
|
|
||||||
'keywords': ['editor', 'wysiwyg', 'tinymce', 'richtext', 'javascript', 'html'],
|
|
||||||
'bugs': { 'url': 'https://github.com/tinymce/tinymce/issues' }
|
|
||||||
}));
|
|
||||||
|
|
||||||
zip.addData('composer.json', jsonToBuffer({
|
|
||||||
'name': 'tinymce/tinymce',
|
|
||||||
'version': packageData.version,
|
|
||||||
'description': 'Web based JavaScript HTML WYSIWYG editor control.',
|
|
||||||
'license': ['LGPL-2.1-only'],
|
|
||||||
'keywords': ['editor', 'wysiwyg', 'tinymce', 'richtext', 'javascript', 'html'],
|
|
||||||
'homepage': 'http://www.tinymce.com',
|
|
||||||
'type': 'component',
|
|
||||||
'extra': {
|
|
||||||
'component': {
|
|
||||||
'scripts': [
|
|
||||||
'tinymce.js',
|
|
||||||
'plugins/*/plugin.js',
|
|
||||||
'themes/*/theme.js'
|
|
||||||
],
|
|
||||||
'files': [
|
|
||||||
'tinymce.min.js',
|
|
||||||
'plugins/*/plugin.min.js',
|
|
||||||
'themes/*/theme.min.js',
|
|
||||||
'skins/**'
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'archive': {
|
|
||||||
'exclude': ['readme.md', 'bower.js', 'package.json', '.npmignore', 'changelog.txt']
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
zip.addFile(
|
|
||||||
'jquery.tinymce.js',
|
|
||||||
'js/tinymce/jquery.tinymce.min.js'
|
|
||||||
);
|
|
||||||
|
|
||||||
var getDirs = zipUtils.getDirectories(grunt, this.excludes);
|
|
||||||
|
|
||||||
zipUtils.addIndexFiles(
|
|
||||||
zip,
|
|
||||||
getDirs('js/tinymce/plugins'),
|
|
||||||
zipUtils.generateIndex('plugins', 'plugin')
|
|
||||||
);
|
|
||||||
zipUtils.addIndexFiles(
|
|
||||||
zip,
|
|
||||||
getDirs('js/tinymce/themes'),
|
|
||||||
zipUtils.generateIndex('themes', 'theme')
|
|
||||||
);
|
|
||||||
},
|
|
||||||
to: 'tmp/tinymce_<%= pkg.version %>_component.zip'
|
|
||||||
},
|
|
||||||
src: [
|
|
||||||
'js/tinymce/skins',
|
|
||||||
'js/tinymce/plugins',
|
|
||||||
'js/tinymce/themes',
|
|
||||||
'js/tinymce/tinymce.js',
|
|
||||||
'js/tinymce/tinymce.min.js',
|
|
||||||
'js/tinymce/jquery.tinymce.min.js',
|
|
||||||
'js/tinymce/license.txt',
|
|
||||||
'changelog.txt',
|
|
||||||
'readme.md'
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
nugetpack: {
|
|
||||||
main: {
|
|
||||||
options: {
|
|
||||||
id: 'TinyMCE',
|
|
||||||
version: packageData.version,
|
|
||||||
authors: 'Ephox Corp',
|
|
||||||
owners: 'Ephox Corp',
|
|
||||||
description: 'The best WYSIWYG editor! TinyMCE is a platform independent web based Javascript HTML WYSIWYG editor ' +
|
|
||||||
'control released as Open Source under LGPL by Ephox Corp. TinyMCE has the ability to convert HTML ' +
|
|
||||||
'TEXTAREA fields or other HTML elements to editor instances. TinyMCE is very easy to integrate ' +
|
|
||||||
'into other Content Management Systems.',
|
|
||||||
releaseNotes: 'Release notes for my package.',
|
|
||||||
summary: 'TinyMCE is a platform independent web based Javascript HTML WYSIWYG editor ' +
|
|
||||||
'control released as Open Source under LGPL by Ephox Corp.',
|
|
||||||
projectUrl: 'http://www.tinymce.com/',
|
|
||||||
iconUrl: 'http://www.tinymce.com/favicon.ico',
|
|
||||||
licenseUrl: 'http://www.tinymce.com/license',
|
|
||||||
requireLicenseAcceptance: true,
|
|
||||||
tags: 'Editor TinyMCE HTML HTMLEditor',
|
|
||||||
excludes: [
|
|
||||||
'js/**/config',
|
|
||||||
'js/**/scratch',
|
|
||||||
'js/**/classes',
|
|
||||||
'js/**/lib',
|
|
||||||
'js/**/dependency',
|
|
||||||
'js/**/src',
|
|
||||||
'js/**/*.less',
|
|
||||||
'js/**/*.dev.svg',
|
|
||||||
'js/**/*.dev.js',
|
|
||||||
'js/**/*.map',
|
|
||||||
'js/tinymce/tinymce.full.min.js'
|
|
||||||
],
|
|
||||||
outputDir: 'tmp'
|
|
||||||
},
|
|
||||||
files: [
|
|
||||||
{ src: 'js/tinymce/langs', dest: '/content/scripts/tinymce/langs' },
|
|
||||||
{ src: 'js/tinymce/plugins', dest: '/content/scripts/tinymce/plugins' },
|
|
||||||
{ src: 'js/tinymce/themes', dest: '/content/scripts/tinymce/themes' },
|
|
||||||
{ src: 'js/tinymce/skins', dest: '/content/scripts/tinymce/skins' },
|
|
||||||
{ src: 'js/tinymce/tinymce.js', dest: '/content/scripts/tinymce/tinymce.js' },
|
|
||||||
{ src: 'js/tinymce/tinymce.min.js', dest: '/content/scripts/tinymce/tinymce.min.js' },
|
|
||||||
{ src: 'js/tinymce/jquery.tinymce.min.js', dest: '/content/scripts/tinymce/jquery.tinymce.min.js' },
|
|
||||||
{ src: 'js/tinymce/license.txt', dest: '/content/scripts/tinymce/license.txt' }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
|
|
||||||
jquery: {
|
|
||||||
options: {
|
|
||||||
id: 'TinyMCE.jQuery',
|
|
||||||
title: 'TinyMCE.jQuery [Deprecated]',
|
|
||||||
version: packageData.version,
|
|
||||||
authors: 'Ephox Corp',
|
|
||||||
owners: 'Ephox Corp',
|
|
||||||
description: 'This package has been deprecated use https://www.nuget.org/packages/TinyMCE/',
|
|
||||||
releaseNotes: 'This package has been deprecated use https://www.nuget.org/packages/TinyMCE/',
|
|
||||||
summary: 'This package has been deprecated use https://www.nuget.org/packages/TinyMCE/',
|
|
||||||
projectUrl: 'http://www.tinymce.com/',
|
|
||||||
iconUrl: 'http://www.tinymce.com/favicon.ico',
|
|
||||||
licenseUrl: 'http://www.tinymce.com/license',
|
|
||||||
requireLicenseAcceptance: true,
|
|
||||||
tags: 'Editor TinyMCE HTML HTMLEditor',
|
|
||||||
excludes: [
|
|
||||||
'js/**/config',
|
|
||||||
'js/**/scratch',
|
|
||||||
'js/**/classes',
|
|
||||||
'js/**/lib',
|
|
||||||
'js/**/dependency',
|
|
||||||
'js/**/src',
|
|
||||||
'js/**/*.less',
|
|
||||||
'js/**/*.dev.svg',
|
|
||||||
'js/**/*.dev.js',
|
|
||||||
'js/**/*.map',
|
|
||||||
'js/tinymce/tinymce.full.min.js'
|
|
||||||
],
|
|
||||||
outputDir: 'tmp'
|
|
||||||
},
|
|
||||||
|
|
||||||
files: [
|
|
||||||
{ src: 'js/tinymce/langs', dest: '/content/scripts/tinymce/langs' },
|
|
||||||
{ src: 'js/tinymce/plugins', dest: '/content/scripts/tinymce/plugins' },
|
|
||||||
{ src: 'js/tinymce/themes', dest: '/content/scripts/tinymce/themes' },
|
|
||||||
{ src: 'js/tinymce/skins', dest: '/content/scripts/tinymce/skins' },
|
|
||||||
{ src: 'js/tinymce/tinymce.js', dest: '/content/scripts/tinymce/tinymce.js' },
|
|
||||||
{ src: 'js/tinymce/tinymce.min.js', dest: '/content/scripts/tinymce/tinymce.min.js' },
|
|
||||||
{ src: 'js/tinymce/jquery.tinymce.min.js', dest: '/content/scripts/tinymce/jquery.tinymce.min.js' },
|
|
||||||
{ src: 'js/tinymce/license.txt', dest: '/content/scripts/tinymce/license.txt' }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
bundle: {
|
|
||||||
minified: {
|
|
||||||
options: {
|
|
||||||
themesDir: 'js/tinymce/themes',
|
|
||||||
pluginsDir: 'js/tinymce/plugins',
|
|
||||||
pluginFileName: 'plugin.min.js',
|
|
||||||
themeFileName: 'theme.min.js',
|
|
||||||
outputPath: 'js/tinymce/tinymce.full.min.js'
|
|
||||||
},
|
|
||||||
|
|
||||||
src: [
|
|
||||||
'js/tinymce/tinymce.min.js'
|
|
||||||
]
|
|
||||||
},
|
|
||||||
|
|
||||||
source: {
|
|
||||||
options: {
|
|
||||||
themesDir: 'js/tinymce/themes',
|
|
||||||
pluginsDir: 'js/tinymce/plugins',
|
|
||||||
pluginFileName: 'plugin.js',
|
|
||||||
themeFileName: 'theme.js',
|
|
||||||
outputPath: 'js/tinymce/tinymce.full.js'
|
|
||||||
},
|
|
||||||
|
|
||||||
src: [
|
|
||||||
'js/tinymce/tinymce.js'
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
clean: {
|
|
||||||
dist: ['js'],
|
|
||||||
lib: ['lib'],
|
|
||||||
scratch: ['scratch'],
|
|
||||||
release: ['tmp']
|
|
||||||
},
|
|
||||||
|
|
||||||
'bedrock-manual': {
|
|
||||||
core: {
|
|
||||||
config: 'tsconfig.json',
|
|
||||||
projectdir: '.',
|
|
||||||
stopOnFailure: true,
|
|
||||||
testfiles: [
|
|
||||||
'src/**/test/ts/atomic/**/*Test.ts',
|
|
||||||
'src/**/test/ts/browser/**/*Test.ts'
|
|
||||||
],
|
|
||||||
customRoutes: 'src/core/test/json/routes.json'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
'bedrock-auto': {
|
|
||||||
phantomjs: {
|
|
||||||
browser: 'phantomjs',
|
|
||||||
config: 'tsconfig.json',
|
|
||||||
testfiles: ['src/**/test/ts/**/*Test.ts'],
|
|
||||||
stopOnFailure: true,
|
|
||||||
overallTimeout: 600000,
|
|
||||||
singleTimeout: 300000,
|
|
||||||
customRoutes: 'src/core/test/json/routes.json',
|
|
||||||
name: 'phantomjs'
|
|
||||||
},
|
|
||||||
'chrome-headless': {
|
|
||||||
browser: 'chrome-headless',
|
|
||||||
config: 'tsconfig.json',
|
|
||||||
testfiles: ['src/**/test/ts/**/*Test.ts'],
|
|
||||||
stopOnFailure: true,
|
|
||||||
overallTimeout: 600000,
|
|
||||||
singleTimeout: 300000,
|
|
||||||
customRoutes: 'src/core/test/json/routes.json',
|
|
||||||
name: 'chrome-headless'
|
|
||||||
},
|
|
||||||
chrome: {
|
|
||||||
browser: 'chrome',
|
|
||||||
config: 'tsconfig.json',
|
|
||||||
testfiles: ['src/**/test/ts/**/*Test.ts'],
|
|
||||||
stopOnFailure: true,
|
|
||||||
overallTimeout: 600000,
|
|
||||||
singleTimeout: 300000,
|
|
||||||
customRoutes: 'src/core/test/json/routes.json',
|
|
||||||
name: 'chrome'
|
|
||||||
},
|
|
||||||
firefox: {
|
|
||||||
browser: 'firefox',
|
|
||||||
config: 'tsconfig.json',
|
|
||||||
testfiles: ['src/**/test/ts/**/*Test.ts'],
|
|
||||||
stopOnFailure: true,
|
|
||||||
overallTimeout: 600000,
|
|
||||||
singleTimeout: 300000,
|
|
||||||
customRoutes: 'src/core/test/json/routes.json',
|
|
||||||
name: 'firefox'
|
|
||||||
},
|
|
||||||
MicrosoftEdge: {
|
|
||||||
browser: 'MicrosoftEdge',
|
|
||||||
config: 'tsconfig.json',
|
|
||||||
testfiles: ['src/**/test/ts/**/*Test.ts'],
|
|
||||||
stopOnFailure: true,
|
|
||||||
overallTimeout: 600000,
|
|
||||||
singleTimeout: 300000,
|
|
||||||
customRoutes: 'src/core/test/json/routes.json',
|
|
||||||
name: 'MicrosoftEdge'
|
|
||||||
},
|
|
||||||
ie: {
|
|
||||||
browser: 'ie',
|
|
||||||
config: 'tsconfig.json',
|
|
||||||
testfiles: ['src/**/test/ts/**/*Test.ts'],
|
|
||||||
stopOnFailure: true,
|
|
||||||
overallTimeout: 600000,
|
|
||||||
singleTimeout: 300000,
|
|
||||||
customRoutes: 'src/core/test/json/routes.json',
|
|
||||||
name: 'ie'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
watch: {
|
|
||||||
skins: {
|
|
||||||
files: ['src/skins/lightgray/main/less/**/*'],
|
|
||||||
tasks: ['less', 'copy:skins'],
|
|
||||||
options: {
|
|
||||||
spawn: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
grunt.registerTask('version', 'Creates a version file', function () {
|
|
||||||
grunt.file.write('tmp/version.txt', BUILD_VERSION);
|
|
||||||
});
|
|
||||||
|
|
||||||
grunt.registerTask('build-headers', 'Appends build headers to js files', function () {
|
|
||||||
var header = '// ' + packageData.version + ' (' + packageData.date + ')\n';
|
|
||||||
grunt.file.write('js/tinymce/tinymce.js', header + grunt.file.read('js/tinymce/tinymce.js'));
|
|
||||||
grunt.file.write('js/tinymce/tinymce.min.js', header + grunt.file.read('js/tinymce/tinymce.min.js'));
|
|
||||||
});
|
|
||||||
|
|
||||||
require('load-grunt-tasks')(grunt);
|
|
||||||
grunt.loadTasks('tools/tasks');
|
|
||||||
grunt.loadNpmTasks('@ephox/bedrock');
|
|
||||||
grunt.loadNpmTasks('@ephox/swag');
|
|
||||||
grunt.loadNpmTasks('grunt-tslint');
|
|
||||||
|
|
||||||
grunt.registerTask('prod', [
|
|
||||||
'validateVersion',
|
|
||||||
'shell:tsc',
|
|
||||||
'tslint',
|
|
||||||
'globals',
|
|
||||||
'rollup',
|
|
||||||
'uglify',
|
|
||||||
'less',
|
|
||||||
'copy',
|
|
||||||
'build-headers',
|
|
||||||
'clean:release',
|
|
||||||
'moxiezip',
|
|
||||||
'nugetpack',
|
|
||||||
'version'
|
|
||||||
]);
|
|
||||||
|
|
||||||
grunt.registerTask('dev', [
|
|
||||||
'shell:tsc',
|
|
||||||
'globals',
|
|
||||||
'rollup',
|
|
||||||
'less',
|
|
||||||
'copy'
|
|
||||||
]);
|
|
||||||
|
|
||||||
grunt.registerTask('start', ['webpack-dev-server']);
|
|
||||||
|
|
||||||
grunt.registerTask('default', ['prod']);
|
|
||||||
grunt.registerTask('test', ['bedrock-auto:phantomjs']);
|
|
||||||
};
|
|
||||||
|
|
@ -1,99 +0,0 @@
|
||||||
TinyMCE - JavaScript Library for Rich Text Editing
|
|
||||||
===================================================
|
|
||||||
|
|
||||||
Building TinyMCE
|
|
||||||
-----------------
|
|
||||||
Install [Node.js](https://nodejs.org/en/) on your system.
|
|
||||||
Clone this repository on your system
|
|
||||||
```
|
|
||||||
$ git clone https://github.com/tinymce/tinymce.git
|
|
||||||
```
|
|
||||||
Open a console and go to the project directory.
|
|
||||||
```
|
|
||||||
$ cd tinymce/
|
|
||||||
```
|
|
||||||
Install `grunt` command line tool globally.
|
|
||||||
```
|
|
||||||
$ npm i -g grunt-cli
|
|
||||||
```
|
|
||||||
Install all package dependencies.
|
|
||||||
```
|
|
||||||
$ npm install
|
|
||||||
```
|
|
||||||
Now, build TinyMCE by using `grunt`.
|
|
||||||
```
|
|
||||||
$ grunt
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
Build tasks
|
|
||||||
------------
|
|
||||||
`grunt`
|
|
||||||
Lints, compiles, minifies and creates release packages for TinyMCE. This will produce the production ready packages.
|
|
||||||
|
|
||||||
`grunt start`
|
|
||||||
Starts a webpack-dev-server that compiles the core, themes, plugins and all demos. Go to `localhost:3000` for a list of links to all the demo pages.
|
|
||||||
|
|
||||||
`grunt dev`
|
|
||||||
Runs tsc, webpack and less. This will only produce the bare essentials for a development build and is a lot faster.
|
|
||||||
|
|
||||||
`grunt test`
|
|
||||||
Runs all tests on PhantomJS.
|
|
||||||
|
|
||||||
`grunt bedrock-manual`
|
|
||||||
Runs all tests manually in a browser.
|
|
||||||
|
|
||||||
`grunt bedrock-auto:<browser>`
|
|
||||||
Runs all tests through selenium browsers supported are chrome, firefox, ie, MicrosoftEdge, chrome-headless and phantomjs.
|
|
||||||
|
|
||||||
`grunt webpack:core`
|
|
||||||
Builds the demo js files for the core part of tinymce this is required to get the core demos working.
|
|
||||||
|
|
||||||
`grunt webpack:plugins`
|
|
||||||
Builds the demo js files for the plugins part of tinymce this is required to get the plugins demos working.
|
|
||||||
|
|
||||||
`grunt webpack:themes`
|
|
||||||
Builds the demo js files for the themes part of tinymce this is required to get the themes demos working.
|
|
||||||
|
|
||||||
`grunt webpack:<name>-plugin`
|
|
||||||
Builds the demo js files for the specific plugin.
|
|
||||||
|
|
||||||
`grunt webpack:<name>-theme`
|
|
||||||
Builds the demo js files for the specific theme.
|
|
||||||
|
|
||||||
`grunt --help`
|
|
||||||
Displays the various build tasks.
|
|
||||||
|
|
||||||
Bundle themes and plugins into a single file
|
|
||||||
---------------------------------------------
|
|
||||||
`grunt bundle --themes=modern --plugins=table,paste`
|
|
||||||
|
|
||||||
Minifies the core, adds the modern theme and adds the table and paste plugin into tinymce.min.js.
|
|
||||||
|
|
||||||
Contributing to the TinyMCE project
|
|
||||||
------------------------------------
|
|
||||||
TinyMCE is an open source software project and we encourage developers to contribute patches and code to be included in the main package of TinyMCE.
|
|
||||||
|
|
||||||
__Basic Rules__
|
|
||||||
|
|
||||||
* Contributed code will be licensed under the LGPL license but not limited to LGPL
|
|
||||||
* Copyright notices will be changed to Ephox Corporation, contributors will get credit for their work
|
|
||||||
* All third party code will be reviewed, tested and possibly modified before being released
|
|
||||||
* All contributors will have to have signed the Contributor License Agreement
|
|
||||||
|
|
||||||
These basic rules ensures that the contributed code remains open source and under the LGPL license.
|
|
||||||
|
|
||||||
__How to Contribute to the Code__
|
|
||||||
|
|
||||||
The TinyMCE source code is [hosted on Github](https://github.com/tinymce/tinymce). Through Github you can submit pull requests and log new bugs and feature requests.
|
|
||||||
|
|
||||||
When you submit a pull request, you will get a notice about signing the __Contributors License Agreement (CLA)__.
|
|
||||||
You should have a __valid email address on your GitHub account__, and you will be sent a key to verify your identity and digitally sign the agreement.
|
|
||||||
|
|
||||||
After you signed your pull request will automatically be ready for review & merge.
|
|
||||||
|
|
||||||
__How to Contribute to the Docs__
|
|
||||||
|
|
||||||
Docs are hosted on Github in the [tinymce-docs](https://github.com/tinymce/tinymce-docs) repo.
|
|
||||||
|
|
||||||
[How to contribute](https://www.tinymce.com/docs/advanced/contributing-docs/) to the docs, including a style guide, can be found on the TinyMCE website.
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
/**
|
|
||||||
* NativeTypes.ts
|
|
||||||
*
|
|
||||||
* Released under LGPL License.
|
|
||||||
* Copyright (c) 1999-2018 Ephox Corp. All rights reserved
|
|
||||||
*
|
|
||||||
* License: http://www.tinymce.com/license
|
|
||||||
* Contributing: http://www.tinymce.com/contributing
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { Selection } from '@ephox/dom-globals';
|
|
||||||
|
|
||||||
// tslint:disable-next-line:no-empty-interface
|
|
||||||
export interface NativeSelection extends Selection {}
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
/**
|
|
||||||
* InputKeys.ts
|
|
||||||
*
|
|
||||||
* Released under LGPL License.
|
|
||||||
* Copyright (c) 1999-2018 Ephox Corp. All rights reserved
|
|
||||||
*
|
|
||||||
* License: http://www.tinymce.com/license
|
|
||||||
* Contributing: http://www.tinymce.com/contributing
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { Editor } from '../api/Editor';
|
|
||||||
import { normalizeNbspsInEditor } from './Nbsps';
|
|
||||||
|
|
||||||
const setup = (editor: Editor) => {
|
|
||||||
editor.on('input', (e) => {
|
|
||||||
// We only care about non composing inputs since moving the caret or modifying the text node will blow away the IME
|
|
||||||
if (e.isComposing === false) {
|
|
||||||
normalizeNbspsInEditor(editor);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export {
|
|
||||||
setup
|
|
||||||
};
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
/**
|
|
||||||
* InsertNewLine.js
|
|
||||||
*
|
|
||||||
* Released under LGPL License.
|
|
||||||
* Copyright (c) 1999-2017 Ephox Corp. All rights reserved
|
|
||||||
*
|
|
||||||
* License: http://www.tinymce.com/license
|
|
||||||
* Contributing: http://www.tinymce.com/contributing
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { Fun } from '@ephox/katamari';
|
|
||||||
import InsertBlock from './InsertBlock';
|
|
||||||
import InsertBr from './InsertBr';
|
|
||||||
import NewLineAction from './NewLineAction';
|
|
||||||
|
|
||||||
const insert = function (editor, evt) {
|
|
||||||
NewLineAction.getAction(editor, evt).fold(
|
|
||||||
function () {
|
|
||||||
InsertBr.insert(editor, evt);
|
|
||||||
},
|
|
||||||
function () {
|
|
||||||
InsertBlock.insert(editor, evt);
|
|
||||||
},
|
|
||||||
Fun.noop
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
insert
|
|
||||||
};
|
|
||||||
|
|
@ -1,68 +0,0 @@
|
||||||
/**
|
|
||||||
* GetSelectionContent.js
|
|
||||||
*
|
|
||||||
* Released under LGPL License.
|
|
||||||
* Copyright (c) 1999-2017 Ephox Corp. All rights reserved
|
|
||||||
*
|
|
||||||
* License: http://www.tinymce.com/license
|
|
||||||
* Contributing: http://www.tinymce.com/contributing
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { Element } from '@ephox/sugar';
|
|
||||||
import EventProcessRanges from './EventProcessRanges';
|
|
||||||
import FragmentReader from './FragmentReader';
|
|
||||||
import MultiRange from './MultiRange';
|
|
||||||
import Zwsp from '../text/Zwsp';
|
|
||||||
|
|
||||||
const getContent = function (editor, args) {
|
|
||||||
const rng = editor.selection.getRng(), tmpElm = editor.dom.create('body');
|
|
||||||
const sel = editor.selection.getSel();
|
|
||||||
let fragment;
|
|
||||||
const ranges = EventProcessRanges.processRanges(editor, MultiRange.getRanges(sel));
|
|
||||||
|
|
||||||
args = args || {};
|
|
||||||
args.get = true;
|
|
||||||
args.format = args.format || 'html';
|
|
||||||
args.selection = true;
|
|
||||||
|
|
||||||
args = editor.fire('BeforeGetContent', args);
|
|
||||||
if (args.isDefaultPrevented()) {
|
|
||||||
editor.fire('GetContent', args);
|
|
||||||
return args.content;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (args.format === 'text') {
|
|
||||||
return editor.selection.isCollapsed() ? '' : Zwsp.trim(rng.text || (sel.toString ? sel.toString() : ''));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rng.cloneContents) {
|
|
||||||
fragment = args.contextual ? FragmentReader.read(Element.fromDom(editor.getBody()), ranges).dom() : rng.cloneContents();
|
|
||||||
if (fragment) {
|
|
||||||
tmpElm.appendChild(fragment);
|
|
||||||
}
|
|
||||||
} else if (rng.item !== undefined || rng.htmlText !== undefined) {
|
|
||||||
// IE will produce invalid markup if elements are present that
|
|
||||||
// it doesn't understand like custom elements or HTML5 elements.
|
|
||||||
// Adding a BR in front of the contents and then remoiving it seems to fix it though.
|
|
||||||
tmpElm.innerHTML = '<br>' + (rng.item ? rng.item(0).outerHTML : rng.htmlText);
|
|
||||||
tmpElm.removeChild(tmpElm.firstChild);
|
|
||||||
} else {
|
|
||||||
tmpElm.innerHTML = rng.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
args.getInner = true;
|
|
||||||
|
|
||||||
const content = editor.selection.serializer.serialize(tmpElm, args);
|
|
||||||
if (args.format === 'tree') {
|
|
||||||
return content;
|
|
||||||
}
|
|
||||||
|
|
||||||
args.content = editor.selection.isCollapsed() ? '' : content;
|
|
||||||
editor.fire('GetContent', args);
|
|
||||||
|
|
||||||
return args.content;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
getContent
|
|
||||||
};
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
/**
|
|
||||||
* Bidi.js
|
|
||||||
*
|
|
||||||
* Released under LGPL License.
|
|
||||||
* Copyright (c) 1999-2017 Ephox Corp. All rights reserved
|
|
||||||
*
|
|
||||||
* License: http://www.tinymce.com/license
|
|
||||||
* Contributing: http://www.tinymce.com/contributing
|
|
||||||
*/
|
|
||||||
|
|
||||||
const strongRtl = /[\u0591-\u07FF\uFB1D-\uFDFF\uFE70-\uFEFC]/;
|
|
||||||
|
|
||||||
const hasStrongRtl = (text: string) => strongRtl.test(text);
|
|
||||||
|
|
||||||
export {
|
|
||||||
hasStrongRtl
|
|
||||||
};
|
|
||||||
|
|
@ -1,90 +0,0 @@
|
||||||
/**
|
|
||||||
* Fun.js
|
|
||||||
*
|
|
||||||
* Released under LGPL License.
|
|
||||||
* Copyright (c) 1999-2017 Ephox Corp. All rights reserved
|
|
||||||
*
|
|
||||||
* License: http://www.tinymce.com/license
|
|
||||||
* Contributing: http://www.tinymce.com/contributing
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Functional utility class.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
* @class tinymce.util.Fun
|
|
||||||
*/
|
|
||||||
|
|
||||||
const slice = [].slice;
|
|
||||||
|
|
||||||
const constant = function (value) {
|
|
||||||
return function () {
|
|
||||||
return value;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const negate = function (predicate) {
|
|
||||||
return function (x) {
|
|
||||||
return !predicate(x);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const compose = function (f, g) {
|
|
||||||
return function (x) {
|
|
||||||
return f(g(x));
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const or = function (...x: any[]) {
|
|
||||||
const args = slice.call(arguments);
|
|
||||||
|
|
||||||
return function (x) {
|
|
||||||
for (let i = 0; i < args.length; i++) {
|
|
||||||
if (args[i](x)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const and = function (...x: any[]) {
|
|
||||||
const args = slice.call(arguments);
|
|
||||||
|
|
||||||
return function (x) {
|
|
||||||
for (let i = 0; i < args.length; i++) {
|
|
||||||
if (!args[i](x)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const curry = function (fn, ...x: any[]) {
|
|
||||||
const args = slice.call(arguments);
|
|
||||||
|
|
||||||
if (args.length - 1 >= fn.length) {
|
|
||||||
return fn.apply(this, args.slice(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
return function () {
|
|
||||||
const tempArgs = args.concat([].slice.call(arguments));
|
|
||||||
return curry.apply(this, tempArgs);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const noop = function () {
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
constant,
|
|
||||||
negate,
|
|
||||||
and,
|
|
||||||
or,
|
|
||||||
curry,
|
|
||||||
compose,
|
|
||||||
noop
|
|
||||||
};
|
|
||||||
|
|
@ -1,302 +0,0 @@
|
||||||
import { GeneralSteps, Keys, Logger, Pipeline } from '@ephox/agar';
|
|
||||||
import { TinyActions, TinyApis, TinyLoader } from '@ephox/mcagar';
|
|
||||||
import Theme from 'tinymce/themes/modern/Theme';
|
|
||||||
import { UnitTest } from '@ephox/bedrock';
|
|
||||||
|
|
||||||
UnitTest.asynctest('browser.tinymce.core.keyboard.SpaceKeyTest', (success, failure) => {
|
|
||||||
Theme();
|
|
||||||
|
|
||||||
TinyLoader.setup(function (editor, onSuccess, onFailure) {
|
|
||||||
const tinyApis = TinyApis(editor);
|
|
||||||
const tinyActions = TinyActions(editor);
|
|
||||||
const img = '<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs=" />';
|
|
||||||
|
|
||||||
Pipeline.async({}, [
|
|
||||||
Logger.t('Space key around inline boundary elements', GeneralSteps.sequence([
|
|
||||||
Logger.t('Press space at beginning of inline boundary inserting nbsp', GeneralSteps.sequence([
|
|
||||||
tinyApis.sFocus,
|
|
||||||
tinyApis.sSetContent('<p>a <a href="#">b</a> c</p>'),
|
|
||||||
tinyApis.sSetCursor([0, 1, 0], 0),
|
|
||||||
tinyApis.sNodeChanged,
|
|
||||||
tinyActions.sContentKeystroke(Keys.space(), {}),
|
|
||||||
tinyApis.sAssertSelection([0, 1, 0], 1, [0, 1, 0], 1),
|
|
||||||
tinyApis.sAssertContent('<p>a <a href="#"> b</a> c</p>')
|
|
||||||
])),
|
|
||||||
Logger.t('Press space at end of inline boundary inserting nbsp', GeneralSteps.sequence([
|
|
||||||
tinyApis.sFocus,
|
|
||||||
tinyApis.sSetContent('<p>a <a href="#">b</a> c</p>'),
|
|
||||||
tinyApis.sSetCursor([0, 1, 0], 1),
|
|
||||||
tinyApis.sNodeChanged,
|
|
||||||
tinyActions.sContentKeystroke(Keys.space(), {}),
|
|
||||||
tinyApis.sAssertSelection([0, 1, 0], 2, [0, 1, 0], 2),
|
|
||||||
tinyApis.sAssertContent('<p>a <a href="#">b </a> c</p>')
|
|
||||||
])),
|
|
||||||
Logger.t('Press space at beginning of inline boundary inserting space', GeneralSteps.sequence([
|
|
||||||
tinyApis.sFocus,
|
|
||||||
tinyApis.sSetContent('<p>a<a href="#">b</a>c</p>'),
|
|
||||||
tinyApis.sSetCursor([0, 1, 0], 0),
|
|
||||||
tinyApis.sNodeChanged,
|
|
||||||
tinyActions.sContentKeystroke(Keys.space(), {}),
|
|
||||||
tinyApis.sAssertSelection([0, 1, 0], 1, [0, 1, 0], 1),
|
|
||||||
tinyApis.sAssertContent('<p>a<a href="#"> b</a>c</p>')
|
|
||||||
])),
|
|
||||||
Logger.t('Press space at end of inline boundary inserting space', GeneralSteps.sequence([
|
|
||||||
tinyApis.sFocus,
|
|
||||||
tinyApis.sSetContent('<p>a<a href="#">b</a>c</p>'),
|
|
||||||
tinyApis.sSetCursor([0, 1, 0], 1),
|
|
||||||
tinyApis.sNodeChanged,
|
|
||||||
tinyActions.sContentKeystroke(Keys.space(), {}),
|
|
||||||
tinyApis.sAssertSelection([0, 1, 0], 2, [0, 1, 0], 2),
|
|
||||||
tinyApis.sAssertContent('<p>a<a href="#">b </a>c</p>')
|
|
||||||
])),
|
|
||||||
Logger.t('Press space at start of inline boundary with leading space inserting nbsp', GeneralSteps.sequence([
|
|
||||||
tinyApis.sFocus,
|
|
||||||
tinyApis.sSetContent('<p>a<a href="#"> b</a>c</p>'),
|
|
||||||
tinyApis.sSetCursor([0, 1, 0], 0),
|
|
||||||
tinyApis.sNodeChanged,
|
|
||||||
tinyActions.sContentKeystroke(Keys.space(), {}),
|
|
||||||
tinyApis.sAssertSelection([0, 1, 0], 1, [0, 1, 0], 1),
|
|
||||||
tinyApis.sAssertContent('<p>a<a href="#"> b</a>c</p>')
|
|
||||||
])),
|
|
||||||
Logger.t('Press space at end of inline boundary with trailing space inserting nbsp', GeneralSteps.sequence([
|
|
||||||
tinyApis.sFocus,
|
|
||||||
tinyApis.sSetContent('<p>a<a href="#">b </a>c</p>'),
|
|
||||||
tinyApis.sSetCursor([0, 1, 0], 2),
|
|
||||||
tinyApis.sNodeChanged,
|
|
||||||
tinyActions.sContentKeystroke(Keys.space(), {}),
|
|
||||||
tinyApis.sAssertSelection([0, 1, 0], 3, [0, 1, 0], 3),
|
|
||||||
tinyApis.sAssertContent('<p>a<a href="#">b </a>c</p>')
|
|
||||||
]))
|
|
||||||
])),
|
|
||||||
Logger.t('Space key in block elements', GeneralSteps.sequence([
|
|
||||||
Logger.t('Press space at beginning of block', GeneralSteps.sequence([
|
|
||||||
tinyApis.sFocus,
|
|
||||||
tinyApis.sSetContent('<p>a</p>'),
|
|
||||||
tinyApis.sSetCursor([0, 0], 0),
|
|
||||||
tinyActions.sContentKeystroke(Keys.space(), {}),
|
|
||||||
tinyApis.sAssertSelection([0, 0], 1, [0, 0], 1),
|
|
||||||
tinyApis.sAssertContent('<p> a</p>')
|
|
||||||
])),
|
|
||||||
Logger.t('Press space at end of block', GeneralSteps.sequence([
|
|
||||||
tinyApis.sFocus,
|
|
||||||
tinyApis.sSetContent('<p>a</p>'),
|
|
||||||
tinyApis.sSetCursor([0, 0], 1),
|
|
||||||
tinyActions.sContentKeystroke(Keys.space(), {}),
|
|
||||||
tinyApis.sAssertSelection([0, 0], 2, [0, 0], 2),
|
|
||||||
tinyApis.sAssertContent('<p>a </p>')
|
|
||||||
]))
|
|
||||||
])),
|
|
||||||
Logger.t('Space key in text', GeneralSteps.sequence([
|
|
||||||
Logger.t('Press space in middle of text', GeneralSteps.sequence([
|
|
||||||
tinyApis.sFocus,
|
|
||||||
tinyApis.sSetContent('<p>ab</p>'),
|
|
||||||
tinyApis.sSetCursor([0, 0], 1),
|
|
||||||
tinyActions.sContentKeystroke(Keys.space(), {}),
|
|
||||||
tinyApis.sAssertSelection([0, 0], 2, [0, 0], 2),
|
|
||||||
tinyApis.sAssertContent('<p>a b</p>')
|
|
||||||
])),
|
|
||||||
Logger.t('Press space after letter preceded by space', GeneralSteps.sequence([
|
|
||||||
tinyApis.sFocus,
|
|
||||||
tinyApis.sSetContent('<p>a bc</p>'),
|
|
||||||
tinyApis.sSetCursor([0, 0], 3),
|
|
||||||
tinyActions.sContentKeystroke(Keys.space(), {}),
|
|
||||||
tinyApis.sAssertSelection([0, 0], 4, [0, 0], 4),
|
|
||||||
tinyApis.sAssertContent('<p>a b c</p>')
|
|
||||||
])),
|
|
||||||
Logger.t('Press space before letter followed by space', GeneralSteps.sequence([
|
|
||||||
tinyApis.sFocus,
|
|
||||||
tinyApis.sSetContent('<p>ab c</p>'),
|
|
||||||
tinyApis.sSetCursor([0, 0], 1),
|
|
||||||
tinyActions.sContentKeystroke(Keys.space(), {}),
|
|
||||||
tinyApis.sAssertSelection([0, 0], 2, [0, 0], 2),
|
|
||||||
tinyApis.sAssertContent('<p>a b c</p>')
|
|
||||||
])),
|
|
||||||
Logger.t('Press space after letter followed by space in inline element', GeneralSteps.sequence([
|
|
||||||
tinyApis.sFocus,
|
|
||||||
tinyApis.sSetContent('<p>a<em> c</em></p>'),
|
|
||||||
tinyApis.sSetCursor([0, 0], 1),
|
|
||||||
tinyActions.sContentKeystroke(Keys.space(), {}),
|
|
||||||
tinyApis.sAssertSelection([0, 0], 2, [0, 0], 2),
|
|
||||||
tinyApis.sAssertContent('<p>a <em> c</em></p>')
|
|
||||||
])),
|
|
||||||
Logger.t('Press space before letter preceded by space in inline element', GeneralSteps.sequence([
|
|
||||||
tinyApis.sFocus,
|
|
||||||
tinyApis.sSetContent('<p>a<em>b </em>c</p>'),
|
|
||||||
tinyApis.sSetCursor([0, 2], 0),
|
|
||||||
tinyActions.sContentKeystroke(Keys.space(), {}),
|
|
||||||
tinyApis.sAssertSelection([0, 2], 1, [0, 2], 1),
|
|
||||||
tinyApis.sAssertContent('<p>a<em>b </em> c</p>')
|
|
||||||
])),
|
|
||||||
Logger.t('Press space after letter followed by nbsp in inline element', GeneralSteps.sequence([
|
|
||||||
tinyApis.sFocus,
|
|
||||||
tinyApis.sSetContent('<p>a<em> c</em></p>'),
|
|
||||||
tinyApis.sSetCursor([0, 0], 1),
|
|
||||||
tinyActions.sContentKeystroke(Keys.space(), {}),
|
|
||||||
tinyApis.sAssertSelection([0, 0], 2, [0, 0], 2),
|
|
||||||
tinyApis.sAssertContent('<p>a <em> c</em></p>')
|
|
||||||
])),
|
|
||||||
Logger.t('Press space before letter preceded by nbsp in inline element', GeneralSteps.sequence([
|
|
||||||
tinyApis.sFocus,
|
|
||||||
tinyApis.sSetContent('<p>a<em>b </em>c</p>'),
|
|
||||||
tinyApis.sSetCursor([0, 2], 0),
|
|
||||||
tinyActions.sContentKeystroke(Keys.space(), {}),
|
|
||||||
tinyApis.sAssertSelection([0, 2], 1, [0, 2], 1),
|
|
||||||
tinyApis.sAssertContent('<p>a<em>b </em> c</p>')
|
|
||||||
])),
|
|
||||||
Logger.t('Press space before nbsp in text', GeneralSteps.sequence([
|
|
||||||
tinyApis.sFocus,
|
|
||||||
tinyApis.sSetContent('<p>a b</p>'),
|
|
||||||
tinyApis.sSetCursor([0, 0], 1),
|
|
||||||
tinyActions.sContentKeystroke(Keys.space(), {}),
|
|
||||||
tinyApis.sAssertSelection([0, 0], 2, [0, 0], 2),
|
|
||||||
tinyApis.sAssertContent('<p>a b</p>')
|
|
||||||
])),
|
|
||||||
Logger.t('Press space after nbsp in text', GeneralSteps.sequence([
|
|
||||||
tinyApis.sFocus,
|
|
||||||
tinyApis.sSetContent('<p>a b</p>'),
|
|
||||||
tinyApis.sSetCursor([0, 0], 2),
|
|
||||||
tinyActions.sContentKeystroke(Keys.space(), {}),
|
|
||||||
tinyApis.sAssertSelection([0, 0], 3, [0, 0], 3),
|
|
||||||
tinyApis.sAssertContent('<p>a b</p>')
|
|
||||||
])),
|
|
||||||
Logger.t('Press space between two nbsp in text', GeneralSteps.sequence([
|
|
||||||
tinyApis.sFocus,
|
|
||||||
tinyApis.sSetContent('<p>a b</p>'),
|
|
||||||
tinyApis.sSetCursor([0, 0], 2),
|
|
||||||
tinyActions.sContentKeystroke(Keys.space(), {}),
|
|
||||||
tinyApis.sAssertSelection([0, 0], 3, [0, 0], 3),
|
|
||||||
tinyApis.sAssertContent('<p>a b</p>')
|
|
||||||
])),
|
|
||||||
Logger.t('Press space before two nbsp in text', GeneralSteps.sequence([
|
|
||||||
tinyApis.sFocus,
|
|
||||||
tinyApis.sSetContent('<p>a b</p>'),
|
|
||||||
tinyApis.sSetCursor([0, 0], 1),
|
|
||||||
tinyActions.sContentKeystroke(Keys.space(), {}),
|
|
||||||
tinyApis.sAssertSelection([0, 0], 2, [0, 0], 2),
|
|
||||||
tinyApis.sAssertContent('<p>a b</p>')
|
|
||||||
])),
|
|
||||||
Logger.t('Press space after two nbsp in text', GeneralSteps.sequence([
|
|
||||||
tinyApis.sFocus,
|
|
||||||
tinyApis.sSetContent('<p>a b</p>'),
|
|
||||||
tinyApis.sSetCursor([0, 0], 3),
|
|
||||||
tinyActions.sContentKeystroke(Keys.space(), {}),
|
|
||||||
tinyApis.sAssertSelection([0, 0], 4, [0, 0], 4),
|
|
||||||
tinyApis.sAssertContent('<p>a b</p>')
|
|
||||||
])),
|
|
||||||
Logger.t('Press space before letter followed by space in inline element', GeneralSteps.sequence([
|
|
||||||
tinyApis.sFocus,
|
|
||||||
tinyApis.sSetContent('<p>ab<em> c</em></p>'),
|
|
||||||
tinyApis.sSetCursor([0, 0], 1),
|
|
||||||
tinyActions.sContentKeystroke(Keys.space(), {}),
|
|
||||||
tinyApis.sAssertSelection([0, 0], 2, [0, 0], 2),
|
|
||||||
tinyApis.sAssertContent('<p>a b<em> c</em></p>')
|
|
||||||
])),
|
|
||||||
Logger.t('Press space after letter preceded by space in inline element', GeneralSteps.sequence([
|
|
||||||
tinyApis.sFocus,
|
|
||||||
tinyApis.sSetContent('<p>a<em>b </em>cd</p>'),
|
|
||||||
tinyApis.sSetCursor([0, 2], 1),
|
|
||||||
tinyActions.sContentKeystroke(Keys.space(), {}),
|
|
||||||
tinyApis.sAssertSelection([0, 2], 2, [0, 2], 2),
|
|
||||||
tinyApis.sAssertContent('<p>a<em>b </em>c d</p>')
|
|
||||||
]))
|
|
||||||
])),
|
|
||||||
Logger.t('Space key in preformatted text', GeneralSteps.sequence([
|
|
||||||
Logger.t('Press space at start of pre', GeneralSteps.sequence([
|
|
||||||
tinyApis.sFocus,
|
|
||||||
tinyApis.sSetContent('<pre>ab</pre>'),
|
|
||||||
tinyApis.sSetCursor([0, 0], 0),
|
|
||||||
tinyActions.sContentKeystroke(Keys.space(), {}),
|
|
||||||
tinyApis.sAssertSelection([0, 0], 1, [0, 0], 1),
|
|
||||||
tinyApis.sAssertContent('<pre> ab</pre>')
|
|
||||||
])),
|
|
||||||
Logger.t('Press space in middle of text', GeneralSteps.sequence([
|
|
||||||
tinyApis.sFocus,
|
|
||||||
tinyApis.sSetContent('<pre>ab</pre>'),
|
|
||||||
tinyApis.sSetCursor([0, 0], 1),
|
|
||||||
tinyActions.sContentKeystroke(Keys.space(), {}),
|
|
||||||
tinyApis.sAssertSelection([0, 0], 2, [0, 0], 2),
|
|
||||||
tinyApis.sAssertContent('<pre>a b</pre>')
|
|
||||||
])),
|
|
||||||
Logger.t('Press space at end of pre', GeneralSteps.sequence([
|
|
||||||
tinyApis.sFocus,
|
|
||||||
tinyApis.sSetContent('<pre>ab</pre>'),
|
|
||||||
tinyApis.sSetCursor([0, 0], 2),
|
|
||||||
tinyActions.sContentKeystroke(Keys.space(), {}),
|
|
||||||
tinyApis.sAssertSelection([0, 0], 3, [0, 0], 3),
|
|
||||||
tinyApis.sAssertContent('<pre>ab </pre>')
|
|
||||||
])),
|
|
||||||
Logger.t('Press space in after space', GeneralSteps.sequence([
|
|
||||||
tinyApis.sFocus,
|
|
||||||
tinyApis.sSetContent('<pre>a b</pre>'),
|
|
||||||
tinyApis.sSetCursor([0, 0], 2),
|
|
||||||
tinyActions.sContentKeystroke(Keys.space(), {}),
|
|
||||||
tinyApis.sAssertSelection([0, 0], 3, [0, 0], 3),
|
|
||||||
tinyApis.sAssertContent('<pre>a b</pre>')
|
|
||||||
])),
|
|
||||||
Logger.t('Press space in before space', GeneralSteps.sequence([
|
|
||||||
tinyApis.sFocus,
|
|
||||||
tinyApis.sSetContent('<pre>a b</pre>'),
|
|
||||||
tinyApis.sSetCursor([0, 0], 1),
|
|
||||||
tinyActions.sContentKeystroke(Keys.space(), {}),
|
|
||||||
tinyApis.sAssertSelection([0, 0], 2, [0, 0], 2),
|
|
||||||
tinyApis.sAssertContent('<pre>a b</pre>')
|
|
||||||
]))
|
|
||||||
])),
|
|
||||||
Logger.t('Space key at br', GeneralSteps.sequence([
|
|
||||||
Logger.t('Press space between two br:s in block', GeneralSteps.sequence([
|
|
||||||
tinyApis.sFocus,
|
|
||||||
tinyApis.sSetRawContent('<p><br><br></p>'),
|
|
||||||
tinyApis.sSetCursor([0], 1),
|
|
||||||
tinyActions.sContentKeystroke(Keys.space(), {}),
|
|
||||||
tinyApis.sAssertSelection([0, 1], 1, [0, 1], 1),
|
|
||||||
tinyApis.sAssertContent('<p><br /> </p>')
|
|
||||||
])),
|
|
||||||
Logger.t('Press space after br in beginning of text node', GeneralSteps.sequence([
|
|
||||||
tinyApis.sFocus,
|
|
||||||
tinyApis.sSetRawContent('<p>a<br />b</p>'),
|
|
||||||
tinyApis.sSetCursor([0, 2], 0),
|
|
||||||
tinyActions.sContentKeystroke(Keys.space(), {}),
|
|
||||||
tinyApis.sAssertSelection([0, 2], 1, [0, 2], 1),
|
|
||||||
tinyApis.sAssertContent('<p>a<br /> b</p>')
|
|
||||||
])),
|
|
||||||
Logger.t('Press space before br in beginning of text node', GeneralSteps.sequence([
|
|
||||||
tinyApis.sFocus,
|
|
||||||
tinyApis.sSetRawContent('<p><br />b</p>'),
|
|
||||||
tinyApis.sSetCursor([0], 0),
|
|
||||||
tinyActions.sContentKeystroke(Keys.space(), {}),
|
|
||||||
tinyApis.sAssertSelection([0, 0], 1, [0, 0], 1),
|
|
||||||
tinyApis.sAssertContent('<p> <br />b</p>')
|
|
||||||
]))
|
|
||||||
])),
|
|
||||||
Logger.t('Space key at node indexes', GeneralSteps.sequence([
|
|
||||||
Logger.t('Press space before image element in block', GeneralSteps.sequence([
|
|
||||||
tinyApis.sFocus,
|
|
||||||
tinyApis.sSetRawContent(`<p>${img}</p>`),
|
|
||||||
tinyApis.sSetCursor([0], 0),
|
|
||||||
tinyActions.sContentKeystroke(Keys.space(), {}),
|
|
||||||
tinyApis.sAssertSelection([0, 0], 1, [0, 0], 1),
|
|
||||||
tinyApis.sAssertContent(`<p> ${img}</p>`)
|
|
||||||
])),
|
|
||||||
Logger.t('Press space between two image elements in block', GeneralSteps.sequence([
|
|
||||||
tinyApis.sFocus,
|
|
||||||
tinyApis.sSetRawContent(`<p>${img}${img}</p>`),
|
|
||||||
tinyApis.sSetCursor([0], 1),
|
|
||||||
tinyActions.sContentKeystroke(Keys.space(), {}),
|
|
||||||
tinyApis.sAssertSelection([0, 1], 1, [0, 1], 1),
|
|
||||||
tinyApis.sAssertContent(`<p>${img} ${img}</p>`)
|
|
||||||
])),
|
|
||||||
Logger.t('Press space after image element in block', GeneralSteps.sequence([
|
|
||||||
tinyApis.sFocus,
|
|
||||||
tinyApis.sSetRawContent(`<p>${img}</p>`),
|
|
||||||
tinyApis.sSetCursor([0], 1),
|
|
||||||
tinyActions.sContentKeystroke(Keys.space(), {}),
|
|
||||||
tinyApis.sAssertSelection([0, 1], 1, [0, 1], 1),
|
|
||||||
tinyApis.sAssertContent(`<p>${img} </p>`)
|
|
||||||
]))
|
|
||||||
]))
|
|
||||||
], onSuccess, onFailure);
|
|
||||||
}, {
|
|
||||||
indent: false,
|
|
||||||
skin_url: '/project/js/tinymce/skins/lightgray'
|
|
||||||
}, success, failure);
|
|
||||||
});
|
|
||||||
|
|
@ -1,58 +0,0 @@
|
||||||
import { LegacyUnit } from '@ephox/mcagar';
|
|
||||||
import { Pipeline } from '@ephox/agar';
|
|
||||||
import Fun from 'tinymce/core/util/Fun';
|
|
||||||
import { UnitTest } from '@ephox/bedrock';
|
|
||||||
|
|
||||||
UnitTest.asynctest('browser.tinymce.core.util.FunTest', function () {
|
|
||||||
const success = arguments[arguments.length - 2];
|
|
||||||
const failure = arguments[arguments.length - 1];
|
|
||||||
const suite = LegacyUnit.createSuite();
|
|
||||||
|
|
||||||
const isTrue = function (value) {
|
|
||||||
return value === true;
|
|
||||||
};
|
|
||||||
|
|
||||||
const isFalse = function (value) {
|
|
||||||
return value === true;
|
|
||||||
};
|
|
||||||
|
|
||||||
const isAbove = function (target, value) {
|
|
||||||
return value() > target();
|
|
||||||
};
|
|
||||||
|
|
||||||
suite.test('constant', function () {
|
|
||||||
LegacyUnit.strictEqual(Fun.constant(1)(), 1);
|
|
||||||
LegacyUnit.strictEqual(Fun.constant('1')(), '1');
|
|
||||||
LegacyUnit.strictEqual(Fun.constant(null)(), null);
|
|
||||||
});
|
|
||||||
|
|
||||||
suite.test('negate', function () {
|
|
||||||
LegacyUnit.strictEqual(Fun.negate(isTrue)(false), true);
|
|
||||||
LegacyUnit.strictEqual(Fun.negate(isFalse)(true), false);
|
|
||||||
});
|
|
||||||
|
|
||||||
suite.test('and', function () {
|
|
||||||
const isAbove5 = Fun.curry(isAbove, Fun.constant(5));
|
|
||||||
const isAbove10 = Fun.curry(isAbove, Fun.constant(10));
|
|
||||||
|
|
||||||
LegacyUnit.strictEqual(Fun.and(isAbove10, isAbove5)(Fun.constant(10)), false);
|
|
||||||
LegacyUnit.strictEqual(Fun.and(isAbove10, isAbove5)(Fun.constant(30)), true);
|
|
||||||
});
|
|
||||||
|
|
||||||
suite.test('or', function () {
|
|
||||||
const isAbove5 = Fun.curry(isAbove, Fun.constant(5));
|
|
||||||
const isAbove10 = Fun.curry(isAbove, Fun.constant(10));
|
|
||||||
|
|
||||||
LegacyUnit.strictEqual(Fun.or(isAbove10, isAbove5)(Fun.constant(5)), false);
|
|
||||||
LegacyUnit.strictEqual(Fun.or(isAbove10, isAbove5)(Fun.constant(15)), true);
|
|
||||||
LegacyUnit.strictEqual(Fun.or(isAbove5, isAbove10)(Fun.constant(15)), true);
|
|
||||||
});
|
|
||||||
|
|
||||||
suite.test('compose', function () {
|
|
||||||
LegacyUnit.strictEqual(Fun.compose(Fun.curry(isAbove, Fun.constant(5)), Fun.constant)(10), true);
|
|
||||||
});
|
|
||||||
|
|
||||||
Pipeline.async({}, suite.toSteps({}), function () {
|
|
||||||
success();
|
|
||||||
}, failure);
|
|
||||||
});
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
/**
|
|
||||||
* Commands.js
|
|
||||||
*
|
|
||||||
* Released under LGPL License.
|
|
||||||
* Copyright (c) 1999-2017 Ephox Corp. All rights reserved
|
|
||||||
*
|
|
||||||
* License: http://www.tinymce.com/license
|
|
||||||
* Contributing: http://www.tinymce.com/contributing
|
|
||||||
*/
|
|
||||||
|
|
||||||
import Dialog from '../ui/Dialog';
|
|
||||||
|
|
||||||
const register = function (editor) {
|
|
||||||
editor.addCommand('mceAnchor', function () {
|
|
||||||
Dialog.open(editor);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
register
|
|
||||||
};
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
/**
|
|
||||||
* Commands.js
|
|
||||||
*
|
|
||||||
* Released under LGPL License.
|
|
||||||
* Copyright (c) 1999-2017 Ephox Corp. All rights reserved
|
|
||||||
*
|
|
||||||
* License: http://www.tinymce.com/license
|
|
||||||
* Contributing: http://www.tinymce.com/contributing
|
|
||||||
*/
|
|
||||||
|
|
||||||
import Resize from '../core/Resize';
|
|
||||||
|
|
||||||
const register = function (editor, oldSize) {
|
|
||||||
editor.addCommand('mceAutoResize', function () {
|
|
||||||
Resize.resize(editor, oldSize);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
register
|
|
||||||
};
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
/**
|
|
||||||
* Settings.js
|
|
||||||
*
|
|
||||||
* Released under LGPL License.
|
|
||||||
* Copyright (c) 1999-2017 Ephox Corp. All rights reserved
|
|
||||||
*
|
|
||||||
* License: http://www.tinymce.com/license
|
|
||||||
* Contributing: http://www.tinymce.com/contributing
|
|
||||||
*/
|
|
||||||
|
|
||||||
const getDialect = function (editor) {
|
|
||||||
// Note: This option isn't even used since we only support one dialect
|
|
||||||
return editor.getParam('bbcode_dialect', 'punbb').toLowerCase();
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
getDialect
|
|
||||||
};
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
/**
|
|
||||||
* Commands.js
|
|
||||||
*
|
|
||||||
* Released under LGPL License.
|
|
||||||
* Copyright (c) 1999-2017 Ephox Corp. All rights reserved
|
|
||||||
*
|
|
||||||
* License: http://www.tinymce.com/license
|
|
||||||
* Contributing: http://www.tinymce.com/contributing
|
|
||||||
*/
|
|
||||||
|
|
||||||
import Dialog from '../ui/Dialog';
|
|
||||||
|
|
||||||
const register = function (editor) {
|
|
||||||
editor.addCommand('mceShowCharmap', function () {
|
|
||||||
Dialog.open(editor);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
register
|
|
||||||
};
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
/**
|
|
||||||
* Events.js
|
|
||||||
*
|
|
||||||
* Released under LGPL License.
|
|
||||||
* Copyright (c) 1999-2017 Ephox Corp. All rights reserved
|
|
||||||
*
|
|
||||||
* License: http://www.tinymce.com/license
|
|
||||||
* Contributing: http://www.tinymce.com/contributing
|
|
||||||
*/
|
|
||||||
|
|
||||||
const fireInsertCustomChar = function (editor, chr) {
|
|
||||||
return editor.fire('insertCustomChar', { chr });
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
fireInsertCustomChar
|
|
||||||
};
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
/**
|
|
||||||
* Settings.js
|
|
||||||
*
|
|
||||||
* Released under LGPL License.
|
|
||||||
* Copyright (c) 1999-2017 Ephox Corp. All rights reserved
|
|
||||||
*
|
|
||||||
* License: http://www.tinymce.com/license
|
|
||||||
* Contributing: http://www.tinymce.com/contributing
|
|
||||||
*/
|
|
||||||
|
|
||||||
const getCharMap = function (editor) {
|
|
||||||
return editor.settings.charmap;
|
|
||||||
};
|
|
||||||
|
|
||||||
const getCharMapAppend = function (editor) {
|
|
||||||
return editor.settings.charmap_append;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
getCharMap,
|
|
||||||
getCharMapAppend
|
|
||||||
};
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
/**
|
|
||||||
* Commands.js
|
|
||||||
*
|
|
||||||
* Released under LGPL License.
|
|
||||||
* Copyright (c) 1999-2017 Ephox Corp. All rights reserved
|
|
||||||
*
|
|
||||||
* License: http://www.tinymce.com/license
|
|
||||||
* Contributing: http://www.tinymce.com/contributing
|
|
||||||
*/
|
|
||||||
|
|
||||||
import Dialog from '../ui/Dialog';
|
|
||||||
|
|
||||||
const register = function (editor) {
|
|
||||||
editor.addCommand('mceCodeEditor', function () {
|
|
||||||
Dialog.open(editor);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
register
|
|
||||||
};
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
/**
|
|
||||||
* Api.js
|
|
||||||
*
|
|
||||||
* Released under LGPL License.
|
|
||||||
* Copyright (c) 1999-2017 Ephox Corp. All rights reserved
|
|
||||||
*
|
|
||||||
* License: http://www.tinymce.com/license
|
|
||||||
* Contributing: http://www.tinymce.com/contributing
|
|
||||||
*/
|
|
||||||
|
|
||||||
const get = function (visibleState) {
|
|
||||||
const isContextMenuVisible = function () {
|
|
||||||
return visibleState.get();
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
isContextMenuVisible
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
get
|
|
||||||
};
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
/**
|
|
||||||
* Commands.js
|
|
||||||
*
|
|
||||||
* Released under LGPL License.
|
|
||||||
* Copyright (c) 1999-2017 Ephox Corp. All rights reserved
|
|
||||||
*
|
|
||||||
* License: http://www.tinymce.com/license
|
|
||||||
* Contributing: http://www.tinymce.com/contributing
|
|
||||||
*/
|
|
||||||
|
|
||||||
import Dialog from '../ui/Dialog';
|
|
||||||
|
|
||||||
const register = function (editor, headState) {
|
|
||||||
editor.addCommand('mceFullPageProperties', function () {
|
|
||||||
Dialog.open(editor, headState);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
register
|
|
||||||
};
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
/**
|
|
||||||
* Api.js
|
|
||||||
*
|
|
||||||
* Released under LGPL License.
|
|
||||||
* Copyright (c) 1999-2017 Ephox Corp. All rights reserved
|
|
||||||
*
|
|
||||||
* License: http://www.tinymce.com/license
|
|
||||||
* Contributing: http://www.tinymce.com/contributing
|
|
||||||
*/
|
|
||||||
|
|
||||||
const get = function (fullscreenState) {
|
|
||||||
return {
|
|
||||||
isFullscreen () {
|
|
||||||
return fullscreenState.get() !== null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
get
|
|
||||||
};
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
/**
|
|
||||||
* Events.js
|
|
||||||
*
|
|
||||||
* Released under LGPL License.
|
|
||||||
* Copyright (c) 1999-2017 Ephox Corp. All rights reserved
|
|
||||||
*
|
|
||||||
* License: http://www.tinymce.com/license
|
|
||||||
* Contributing: http://www.tinymce.com/contributing
|
|
||||||
*/
|
|
||||||
|
|
||||||
const fireFullscreenStateChanged = function (editor, state) {
|
|
||||||
editor.fire('FullscreenStateChanged', { state });
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
fireFullscreenStateChanged
|
|
||||||
};
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
/**
|
|
||||||
* Commands.js
|
|
||||||
*
|
|
||||||
* Released under LGPL License.
|
|
||||||
* Copyright (c) 1999-2017 Ephox Corp. All rights reserved
|
|
||||||
*
|
|
||||||
* License: http://www.tinymce.com/license
|
|
||||||
* Contributing: http://www.tinymce.com/contributing
|
|
||||||
*/
|
|
||||||
|
|
||||||
import Dialog from '../ui/Dialog';
|
|
||||||
|
|
||||||
const register = function (editor, pluginUrl) {
|
|
||||||
editor.addCommand('mceHelp', Dialog.open(editor, pluginUrl));
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
register
|
|
||||||
};
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
/**
|
|
||||||
* Commands.js
|
|
||||||
*
|
|
||||||
* Released under LGPL License.
|
|
||||||
* Copyright (c) 1999-2017 Ephox Corp. All rights reserved
|
|
||||||
*
|
|
||||||
* License: http://www.tinymce.com/license
|
|
||||||
* Contributing: http://www.tinymce.com/contributing
|
|
||||||
*/
|
|
||||||
|
|
||||||
const register = function (editor) {
|
|
||||||
editor.addCommand('InsertHorizontalRule', function () {
|
|
||||||
editor.execCommand('mceInsertContent', false, '<hr />');
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
register
|
|
||||||
};
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
/**
|
|
||||||
* Commands.js
|
|
||||||
*
|
|
||||||
* Released under LGPL License.
|
|
||||||
* Copyright (c) 1999-2017 Ephox Corp. All rights reserved
|
|
||||||
*
|
|
||||||
* License: http://www.tinymce.com/license
|
|
||||||
* Contributing: http://www.tinymce.com/contributing
|
|
||||||
*/
|
|
||||||
|
|
||||||
import Dialog from '../ui/Dialog';
|
|
||||||
|
|
||||||
const register = function (editor) {
|
|
||||||
editor.addCommand('mceImage', Dialog(editor).open);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
register
|
|
||||||
};
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
/**
|
|
||||||
* Commands.js
|
|
||||||
*
|
|
||||||
* Released under LGPL License.
|
|
||||||
* Copyright (c) 1999-2017 Ephox Corp. All rights reserved
|
|
||||||
*
|
|
||||||
* License: http://www.tinymce.com/license
|
|
||||||
* Contributing: http://www.tinymce.com/contributing
|
|
||||||
*/
|
|
||||||
|
|
||||||
import Actions from '../core/Actions';
|
|
||||||
|
|
||||||
const register = function (editor) {
|
|
||||||
editor.addCommand('mceLink', Actions.openDialog(editor));
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
register
|
|
||||||
};
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
/**
|
|
||||||
* Keyboard.js
|
|
||||||
*
|
|
||||||
* Released under LGPL License.
|
|
||||||
* Copyright (c) 1999-2017 Ephox Corp. All rights reserved
|
|
||||||
*
|
|
||||||
* License: http://www.tinymce.com/license
|
|
||||||
* Contributing: http://www.tinymce.com/contributing
|
|
||||||
*/
|
|
||||||
|
|
||||||
import Actions from './Actions';
|
|
||||||
|
|
||||||
const setup = function (editor) {
|
|
||||||
editor.addShortcut('Meta+K', '', Actions.openDialog(editor));
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
setup
|
|
||||||
};
|
|
||||||
|
|
@ -1,75 +0,0 @@
|
||||||
/**
|
|
||||||
* Indentation.js
|
|
||||||
*
|
|
||||||
* Released under LGPL License.
|
|
||||||
* Copyright (c) 1999-2018 Ephox Corp. All rights reserved
|
|
||||||
*
|
|
||||||
* License: http://www.tinymce.com/license
|
|
||||||
* Contributing: http://www.tinymce.com/contributing
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { Arr } from '@ephox/katamari';
|
|
||||||
import { Compare, Element, Replication, Traverse } from '@ephox/sugar';
|
|
||||||
import { Editor } from 'tinymce/core/api/Editor';
|
|
||||||
import Range from '../core/Range';
|
|
||||||
import Selection from '../core/Selection';
|
|
||||||
import SplitList from '../core/SplitList';
|
|
||||||
import { IndentValue } from '../listModel/Indentation';
|
|
||||||
import { listsIndentation } from '../listModel/ListsIndendation';
|
|
||||||
|
|
||||||
const outdentDlItem = (editor: Editor, item: Element): void => {
|
|
||||||
if (Compare.is(item, 'DD')) {
|
|
||||||
Replication.mutate(item, 'DT');
|
|
||||||
} else if (Compare.is(item, 'DT')) {
|
|
||||||
Traverse.parent(item).each((dl) => SplitList.splitList(editor, dl.dom(), item.dom()));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const indentDlItem = (item: Element): void => {
|
|
||||||
if (Compare.is(item, 'DT')) {
|
|
||||||
Replication.mutate(item, 'DD');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const dlIndentation = (editor: Editor, indentation: IndentValue, dlItems: Element[]) => {
|
|
||||||
if (indentation === IndentValue.Indent) {
|
|
||||||
Arr.each(dlItems, indentDlItem);
|
|
||||||
} else {
|
|
||||||
Arr.each(dlItems, (item) => outdentDlItem(editor, item));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const selectionIndentation = (editor: Editor, indentation: IndentValue) => {
|
|
||||||
const dlItems = Arr.map(Selection.getSelectedDlItems(editor), Element.fromDom);
|
|
||||||
const lists = Arr.map(Selection.getSelectedListRoots(editor), Element.fromDom);
|
|
||||||
|
|
||||||
if (dlItems.length || lists.length) {
|
|
||||||
const bookmark = editor.selection.getBookmark();
|
|
||||||
|
|
||||||
dlIndentation(editor, indentation, dlItems);
|
|
||||||
|
|
||||||
listsIndentation(
|
|
||||||
editor,
|
|
||||||
lists,
|
|
||||||
indentation
|
|
||||||
);
|
|
||||||
|
|
||||||
editor.selection.moveToBookmark(bookmark);
|
|
||||||
editor.selection.setRng(Range.normalizeRange(editor.selection.getRng()));
|
|
||||||
editor.nodeChanged();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const indentListSelection = (editor: Editor) => {
|
|
||||||
selectionIndentation(editor, IndentValue.Indent);
|
|
||||||
};
|
|
||||||
|
|
||||||
const outdentListSelection = (editor: Editor) => {
|
|
||||||
selectionIndentation(editor, IndentValue.Outdent);
|
|
||||||
};
|
|
||||||
|
|
||||||
const flattenListSelection = (editor: Editor) => {
|
|
||||||
selectionIndentation(editor, IndentValue.Flatten);
|
|
||||||
};
|
|
||||||
|
|
||||||
export { indentListSelection, outdentListSelection, flattenListSelection };
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
/**
|
|
||||||
* Api.js
|
|
||||||
*
|
|
||||||
* Released under LGPL License.
|
|
||||||
* Copyright (c) 1999-2017 Ephox Corp. All rights reserved
|
|
||||||
*
|
|
||||||
* License: http://www.tinymce.com/license
|
|
||||||
* Contributing: http://www.tinymce.com/contributing
|
|
||||||
*/
|
|
||||||
|
|
||||||
import Delete from '../core/Delete';
|
|
||||||
|
|
||||||
const get = function (editor) {
|
|
||||||
return {
|
|
||||||
backspaceDelete (isForward) {
|
|
||||||
Delete.backspaceDelete(editor, isForward);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
get
|
|
||||||
};
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
/**
|
|
||||||
* Settings.js
|
|
||||||
*
|
|
||||||
* Released under LGPL License.
|
|
||||||
* Copyright (c) 1999-2017 Ephox Corp. All rights reserved
|
|
||||||
*
|
|
||||||
* License: http://www.tinymce.com/license
|
|
||||||
* Contributing: http://www.tinymce.com/contributing
|
|
||||||
*/
|
|
||||||
|
|
||||||
const shouldIndentOnTab = function (editor) {
|
|
||||||
return editor.getParam('lists_indent_on_tab', true);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
shouldIndentOnTab
|
|
||||||
};
|
|
||||||
|
|
@ -1,106 +0,0 @@
|
||||||
/**
|
|
||||||
* ComposeList.js
|
|
||||||
*
|
|
||||||
* Released under LGPL License.
|
|
||||||
* Copyright (c) 1999-2018 Ephox Corp. All rights reserved
|
|
||||||
*
|
|
||||||
* License: http://www.tinymce.com/license
|
|
||||||
* Contributing: http://www.tinymce.com/contributing
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { Entry } from './Entry';
|
|
||||||
import { Element, Insert, InsertAll, Attr, Css, Node, Replication } from '@ephox/sugar';
|
|
||||||
import { Arr, Option, Options } from '@ephox/katamari';
|
|
||||||
import { ListType } from './ListType';
|
|
||||||
|
|
||||||
interface Section {
|
|
||||||
list: Element;
|
|
||||||
item: Element;
|
|
||||||
}
|
|
||||||
|
|
||||||
const createSection = (listType: ListType): Section => {
|
|
||||||
const section: Section = {
|
|
||||||
list: Element.fromTag(listType),
|
|
||||||
item: Element.fromTag('li')
|
|
||||||
};
|
|
||||||
Insert.append(section.list, section.item);
|
|
||||||
return section;
|
|
||||||
};
|
|
||||||
|
|
||||||
const joinSections = (parent: Section, appendor: Section): void => {
|
|
||||||
Insert.append(parent.item, appendor.list);
|
|
||||||
};
|
|
||||||
|
|
||||||
const createJoinedSections = (length: number, listType: ListType): Section[] => {
|
|
||||||
const sections: Section[] = [];
|
|
||||||
for (let i = 0; i < length; i++) {
|
|
||||||
const newSection = createSection(listType);
|
|
||||||
Arr.last(sections).each((lastSection) => joinSections(lastSection, newSection));
|
|
||||||
sections.push(newSection);
|
|
||||||
}
|
|
||||||
return sections;
|
|
||||||
};
|
|
||||||
|
|
||||||
const normalizeSection = (section: Section, entry: Entry): void => {
|
|
||||||
if (Node.name(section.list).toUpperCase() !== entry.listType) {
|
|
||||||
section.list = Replication.mutate(section.list, entry.listType);
|
|
||||||
}
|
|
||||||
Attr.setAll(section.list, entry.listAttributes);
|
|
||||||
};
|
|
||||||
|
|
||||||
const createItem = (attr: Record<string, any>, content: Element[]): Element => {
|
|
||||||
const item = Element.fromTag('li');
|
|
||||||
Attr.setAll(item, attr);
|
|
||||||
InsertAll.append(item, content);
|
|
||||||
return item;
|
|
||||||
};
|
|
||||||
|
|
||||||
const setItem = (section: Section, item: Element): void => {
|
|
||||||
Insert.append(section.list, item);
|
|
||||||
section.item = item;
|
|
||||||
};
|
|
||||||
|
|
||||||
const writeShallow = (outline: Section[], entry: Entry): Section[] => {
|
|
||||||
const newOutline = outline.slice(0, entry.depth);
|
|
||||||
|
|
||||||
Arr.last(newOutline).each((section) => {
|
|
||||||
setItem(section, createItem(entry.itemAttributes, entry.content));
|
|
||||||
normalizeSection(section, entry);
|
|
||||||
});
|
|
||||||
|
|
||||||
return newOutline;
|
|
||||||
};
|
|
||||||
|
|
||||||
const populateSections = (sections: Section[], entry: Entry): void => {
|
|
||||||
Arr.last(sections).each((section) => {
|
|
||||||
Attr.setAll(section.list, entry.listAttributes);
|
|
||||||
Attr.setAll(section.item, entry.itemAttributes);
|
|
||||||
InsertAll.append(section.item, entry.content);
|
|
||||||
});
|
|
||||||
|
|
||||||
for (let i = 0; i < sections.length - 1; i++) {
|
|
||||||
Css.set(sections[i].item, 'list-style-type', 'none');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const writeDeep = (outline: Section[], entry: Entry): Section[] => {
|
|
||||||
const newSections = createJoinedSections(entry.depth - outline.length, entry.listType);
|
|
||||||
populateSections(newSections, entry);
|
|
||||||
|
|
||||||
Options.liftN([
|
|
||||||
Arr.last(outline),
|
|
||||||
Arr.head(newSections)
|
|
||||||
], joinSections);
|
|
||||||
return outline.concat(newSections);
|
|
||||||
};
|
|
||||||
|
|
||||||
const composeList = (entries: Entry[]): Option<Element> => {
|
|
||||||
const outline: Section[] = Arr.foldl(entries, (outline, entry) => {
|
|
||||||
return entry.depth > outline.length ? writeDeep(outline, entry) : writeShallow(outline, entry);
|
|
||||||
}, []);
|
|
||||||
return Arr.head(outline).map((section) => section.list);
|
|
||||||
};
|
|
||||||
|
|
||||||
export {
|
|
||||||
composeList
|
|
||||||
};
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
/**
|
|
||||||
* Entry.js
|
|
||||||
*
|
|
||||||
* Released under LGPL License.
|
|
||||||
* Copyright (c) 1999-2018 Ephox Corp. All rights reserved
|
|
||||||
*
|
|
||||||
* License: http://www.tinymce.com/license
|
|
||||||
* Contributing: http://www.tinymce.com/contributing
|
|
||||||
*/
|
|
||||||
import { Element } from '@ephox/sugar';
|
|
||||||
import { ListType } from './ListType';
|
|
||||||
|
|
||||||
/*
|
|
||||||
General workflow: Parse lists to entries -> Manipulate entries -> Compose entries to lists
|
|
||||||
|
|
||||||
0-------1---2--------->Depth
|
|
||||||
<ol> |
|
|
||||||
<li>a</li> | Entry { depth: 1, content: [a], listType: ListType.OL, ... }
|
|
||||||
<li>b | Entry { depth: 1, content: [b], listType: ListType.OL, ... }
|
|
||||||
<ul> |
|
|
||||||
<li>c</li> | Entry { depth: 2, content: [c], listType: ListType.UL, ... }
|
|
||||||
</ul> |
|
|
||||||
</li> |
|
|
||||||
</ol> |
|
|
||||||
0-------1---2--------->Depth
|
|
||||||
*/
|
|
||||||
|
|
||||||
export interface Entry {
|
|
||||||
depth: number;
|
|
||||||
content: Element[];
|
|
||||||
isSelected: boolean;
|
|
||||||
listType: ListType;
|
|
||||||
listAttributes: Record<string, any>;
|
|
||||||
itemAttributes: Record<string, any>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const isIndented = (entry: Entry) => {
|
|
||||||
return entry.depth > 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const isSelected = (entry: Entry) => {
|
|
||||||
return entry.isSelected;
|
|
||||||
};
|
|
||||||
|
|
@ -1,32 +0,0 @@
|
||||||
/**
|
|
||||||
* Indentation.js
|
|
||||||
*
|
|
||||||
* Released under LGPL License.
|
|
||||||
* Copyright (c) 1999-2018 Ephox Corp. All rights reserved
|
|
||||||
*
|
|
||||||
* License: http://www.tinymce.com/license
|
|
||||||
* Contributing: http://www.tinymce.com/contributing
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { Entry } from './Entry';
|
|
||||||
|
|
||||||
export const enum IndentValue {
|
|
||||||
Indent = 'Indent',
|
|
||||||
Outdent = 'Outdent',
|
|
||||||
Flatten = 'Flatten'
|
|
||||||
}
|
|
||||||
|
|
||||||
export const indentEntry = (indentation: IndentValue, entry: Entry): void => {
|
|
||||||
switch (indentation) {
|
|
||||||
case IndentValue.Indent:
|
|
||||||
entry.depth ++;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case IndentValue.Outdent:
|
|
||||||
entry.depth --;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case IndentValue.Flatten:
|
|
||||||
entry.depth = 0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
@ -1,39 +0,0 @@
|
||||||
/**
|
|
||||||
* ListType.js
|
|
||||||
*
|
|
||||||
* Released under LGPL License.
|
|
||||||
* Copyright (c) 1999-2018 Ephox Corp. All rights reserved
|
|
||||||
*
|
|
||||||
* License: http://www.tinymce.com/license
|
|
||||||
* Contributing: http://www.tinymce.com/contributing
|
|
||||||
*/
|
|
||||||
import { Element, Compare, Node } from '@ephox/sugar';
|
|
||||||
import { Option } from '@ephox/katamari';
|
|
||||||
|
|
||||||
export enum ListType {
|
|
||||||
OL = 'OL',
|
|
||||||
UL = 'UL',
|
|
||||||
DL = 'DL',
|
|
||||||
}
|
|
||||||
|
|
||||||
const getListType = (list: Element): Option<ListType> => {
|
|
||||||
switch (Node.name(list)) {
|
|
||||||
case 'ol':
|
|
||||||
return Option.some(ListType.OL);
|
|
||||||
case 'ul':
|
|
||||||
return Option.some(ListType.UL);
|
|
||||||
case 'dl':
|
|
||||||
return Option.some(ListType.DL);
|
|
||||||
default:
|
|
||||||
return Option.none();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const isList = (el: Element) => {
|
|
||||||
return Compare.is(el, 'OL,UL,DL');
|
|
||||||
};
|
|
||||||
|
|
||||||
export {
|
|
||||||
isList,
|
|
||||||
getListType
|
|
||||||
};
|
|
||||||
|
|
@ -1,47 +0,0 @@
|
||||||
/**
|
|
||||||
* NormalizeEntries.js
|
|
||||||
*
|
|
||||||
* Released under LGPL License.
|
|
||||||
* Copyright (c) 1999-2018 Ephox Corp. All rights reserved
|
|
||||||
*
|
|
||||||
* License: http://www.tinymce.com/license
|
|
||||||
* Contributing: http://www.tinymce.com/contributing
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { Entry } from './Entry';
|
|
||||||
import { Arr, Merger, Option } from '@ephox/katamari';
|
|
||||||
|
|
||||||
const assimilateEntry = (adherent: Entry, source: Entry) => {
|
|
||||||
adherent.listType = source.listType;
|
|
||||||
adherent.listAttributes = Merger.merge({}, source.listAttributes);
|
|
||||||
adherent.itemAttributes = Merger.merge({}, source.itemAttributes);
|
|
||||||
};
|
|
||||||
|
|
||||||
const normalizeShallow = (outline: Array<Option<Entry>>, entry: Entry): Array<Option<Entry>> => {
|
|
||||||
const matchingEntryDepth = entry.depth - 1;
|
|
||||||
outline[matchingEntryDepth].each((matchingEntry) => assimilateEntry(entry, matchingEntry));
|
|
||||||
|
|
||||||
const newOutline = outline.slice(0, matchingEntryDepth);
|
|
||||||
newOutline.push(Option.some(entry));
|
|
||||||
return newOutline;
|
|
||||||
};
|
|
||||||
|
|
||||||
const normalizeDeep = (outline: Array<Option<Entry>>, entry: Entry): Array<Option<Entry>> => {
|
|
||||||
const newOutline = outline.slice(0);
|
|
||||||
const diff = entry.depth - outline.length;
|
|
||||||
for (let i = 1; i < diff; i++) {
|
|
||||||
newOutline.push(Option.none());
|
|
||||||
}
|
|
||||||
newOutline.push(Option.some(entry));
|
|
||||||
return newOutline;
|
|
||||||
};
|
|
||||||
|
|
||||||
const normalizeEntries = (entries: Entry[]): void => {
|
|
||||||
Arr.foldl(entries, (outline: Array<Option<Entry>>, entry) => {
|
|
||||||
return entry.depth > outline.length ? normalizeDeep(outline, entry) : normalizeShallow(outline, entry);
|
|
||||||
}, []);
|
|
||||||
};
|
|
||||||
|
|
||||||
export {
|
|
||||||
normalizeEntries
|
|
||||||
};
|
|
||||||
|
|
@ -1,88 +0,0 @@
|
||||||
/**
|
|
||||||
* ParseLists.js
|
|
||||||
*
|
|
||||||
* Released under LGPL License.
|
|
||||||
* Copyright (c) 1999-2018 Ephox Corp. All rights reserved
|
|
||||||
*
|
|
||||||
* License: http://www.tinymce.com/license
|
|
||||||
* Contributing: http://www.tinymce.com/contributing
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { Arr, Cell, Fun, Option } from '@ephox/katamari';
|
|
||||||
import { Attr, Compare, Element, Replication, Traverse } from '@ephox/sugar';
|
|
||||||
import { getListType, isList, ListType } from './ListType';
|
|
||||||
import { Entry } from './Entry';
|
|
||||||
import { hasLastChildList } from './Util';
|
|
||||||
|
|
||||||
type Parser = (depth: number, itemSelection: Option<ItemTuple>, selectionState: Cell<boolean>, el: Element) => Entry[];
|
|
||||||
|
|
||||||
export interface ItemTuple {
|
|
||||||
start: Element;
|
|
||||||
end: Element;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface EntrySet {
|
|
||||||
entries: Entry[];
|
|
||||||
sourceList: Element;
|
|
||||||
}
|
|
||||||
|
|
||||||
const enum ItemRange {
|
|
||||||
Start = 'Start',
|
|
||||||
End = 'End'
|
|
||||||
}
|
|
||||||
|
|
||||||
const getItemContent = (li: Element): Element[] => {
|
|
||||||
const childNodes = Traverse.children(li);
|
|
||||||
const contentLength = childNodes.length + (hasLastChildList(li) ? -1 : 0);
|
|
||||||
return Arr.map(childNodes.slice(0, contentLength), Replication.deep);
|
|
||||||
};
|
|
||||||
|
|
||||||
const createEntry = (li: Element, depth: number, isSelected: boolean): Entry => {
|
|
||||||
const list = Traverse.parent(li);
|
|
||||||
return {
|
|
||||||
depth,
|
|
||||||
isSelected,
|
|
||||||
content: getItemContent(li),
|
|
||||||
listType: list.bind(getListType).getOr(ListType.OL),
|
|
||||||
listAttributes: list.map(Attr.clone).getOr({}),
|
|
||||||
itemAttributes: Attr.clone(li)
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const parseItem: Parser = (depth: number, itemSelection: Option<ItemTuple>, selectionState: Cell<boolean>, item: Element): Entry[] => {
|
|
||||||
const curriedParseList = Fun.curry(parseList, depth, itemSelection, selectionState);
|
|
||||||
|
|
||||||
const updateSelectionState = (itemRange: ItemRange) => itemSelection.each((selection) => {
|
|
||||||
if (Compare.eq(itemRange === ItemRange.Start ? selection.start : selection.end, item)) {
|
|
||||||
selectionState.set(itemRange === ItemRange.Start);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return Traverse.firstChild(item).filter(isList).fold(() => {
|
|
||||||
updateSelectionState(ItemRange.Start);
|
|
||||||
const fromCurrentItem: Entry = createEntry(item, depth, selectionState.get());
|
|
||||||
updateSelectionState(ItemRange.End);
|
|
||||||
const fromChildList: Entry[] = Traverse.lastChild(item).filter(isList).map(curriedParseList).getOr([]);
|
|
||||||
|
|
||||||
return [ fromCurrentItem, ...fromChildList ];
|
|
||||||
}, curriedParseList);
|
|
||||||
};
|
|
||||||
|
|
||||||
const parseList: Parser = (depth: number, itemSelection: Option<ItemTuple>, selectionState: Cell<boolean>, list: Element): Entry[] => {
|
|
||||||
const newDepth = depth + 1;
|
|
||||||
return Arr.bind(Traverse.children(list), (child) =>
|
|
||||||
isList(child) ? parseList(newDepth, itemSelection, selectionState, child) : parseItem(newDepth, itemSelection, selectionState, child)
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const parseLists = (lists: Element[], itemSelection: Option<ItemTuple>): EntrySet[] => {
|
|
||||||
const selectionState = Cell(false);
|
|
||||||
const initialDepth = 0;
|
|
||||||
|
|
||||||
return Arr.map(lists, (list) => ({
|
|
||||||
entries: parseList(initialDepth, itemSelection, selectionState, list),
|
|
||||||
sourceList: list
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
|
|
||||||
export { parseLists };
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
/**
|
|
||||||
* Util.js
|
|
||||||
*
|
|
||||||
* Released under LGPL License.
|
|
||||||
* Copyright (c) 1999-2018 Ephox Corp. All rights reserved
|
|
||||||
*
|
|
||||||
* License: http://www.tinymce.com/license
|
|
||||||
* Contributing: http://www.tinymce.com/contributing
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { Element, Traverse } from '@ephox/sugar';
|
|
||||||
import { isList } from './ListType';
|
|
||||||
|
|
||||||
const hasFirstChildList = (li: Element) => {
|
|
||||||
return Traverse.firstChild(li).map(isList).getOr(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
const hasLastChildList = (li: Element) => {
|
|
||||||
return Traverse.lastChild(li).map(isList).getOr(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
export {
|
|
||||||
hasFirstChildList,
|
|
||||||
hasLastChildList
|
|
||||||
};
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
/**
|
|
||||||
* Api.js
|
|
||||||
*
|
|
||||||
* Released under LGPL License.
|
|
||||||
* Copyright (c) 1999-2017 Ephox Corp. All rights reserved
|
|
||||||
*
|
|
||||||
* License: http://www.tinymce.com/license
|
|
||||||
* Contributing: http://www.tinymce.com/contributing
|
|
||||||
*/
|
|
||||||
|
|
||||||
import Dialog from '../ui/Dialog';
|
|
||||||
|
|
||||||
const get = function (editor) {
|
|
||||||
const showDialog = function () {
|
|
||||||
Dialog.showDialog(editor);
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
showDialog
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
get
|
|
||||||
};
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
/**
|
|
||||||
* Commands.js
|
|
||||||
*
|
|
||||||
* Released under LGPL License.
|
|
||||||
* Copyright (c) 1999-2017 Ephox Corp. All rights reserved
|
|
||||||
*
|
|
||||||
* License: http://www.tinymce.com/license
|
|
||||||
* Contributing: http://www.tinymce.com/contributing
|
|
||||||
*/
|
|
||||||
|
|
||||||
import Dialog from '../ui/Dialog';
|
|
||||||
|
|
||||||
const register = function (editor) {
|
|
||||||
const showDialog = function () {
|
|
||||||
Dialog.showDialog(editor);
|
|
||||||
};
|
|
||||||
|
|
||||||
editor.addCommand('mceMedia', showDialog);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
register
|
|
||||||
};
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
/**
|
|
||||||
* Commands.js
|
|
||||||
*
|
|
||||||
* Released under LGPL License.
|
|
||||||
* Copyright (c) 1999-2017 Ephox Corp. All rights reserved
|
|
||||||
*
|
|
||||||
* License: http://www.tinymce.com/license
|
|
||||||
* Contributing: http://www.tinymce.com/contributing
|
|
||||||
*/
|
|
||||||
|
|
||||||
import Actions from '../core/Actions';
|
|
||||||
|
|
||||||
const register = function (editor) {
|
|
||||||
editor.addCommand('mceNonBreaking', function () {
|
|
||||||
Actions.insertNbsp(editor, 1);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
register
|
|
||||||
};
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
/**
|
|
||||||
* Plugin.js
|
|
||||||
*
|
|
||||||
* Released under LGPL License.
|
|
||||||
* Copyright (c) 1999-2017 Ephox Corp. All rights reserved
|
|
||||||
*
|
|
||||||
* License: http://www.tinymce.com/license
|
|
||||||
* Contributing: http://www.tinymce.com/contributing
|
|
||||||
*/
|
|
||||||
|
|
||||||
import PluginManager from 'tinymce/core/api/PluginManager';
|
|
||||||
import FilterContent from './core/FilterContent';
|
|
||||||
|
|
||||||
PluginManager.add('noneditable', function (editor) {
|
|
||||||
FilterContent.setup(editor);
|
|
||||||
});
|
|
||||||
|
|
||||||
export default function () { }
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
/**
|
|
||||||
* Api.js
|
|
||||||
*
|
|
||||||
* Released under LGPL License.
|
|
||||||
* Copyright (c) 1999-2017 Ephox Corp. All rights reserved
|
|
||||||
*
|
|
||||||
* License: http://www.tinymce.com/license
|
|
||||||
* Contributing: http://www.tinymce.com/contributing
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { Clipboard } from '../api/Clipboard';
|
|
||||||
|
|
||||||
const get = function (clipboard: Clipboard, quirks) {
|
|
||||||
return {
|
|
||||||
clipboard,
|
|
||||||
quirks
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
get
|
|
||||||
};
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
/**
|
|
||||||
* Commands.js
|
|
||||||
*
|
|
||||||
* Released under LGPL License.
|
|
||||||
* Copyright (c) 1999-2017 Ephox Corp. All rights reserved
|
|
||||||
*
|
|
||||||
* License: http://www.tinymce.com/license
|
|
||||||
* Contributing: http://www.tinymce.com/contributing
|
|
||||||
*/
|
|
||||||
|
|
||||||
import Dialog from '../ui/Dialog';
|
|
||||||
|
|
||||||
const register = function (editor) {
|
|
||||||
editor.addCommand('mcePreview', function () {
|
|
||||||
Dialog.open(editor);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
register
|
|
||||||
};
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
/**
|
|
||||||
* Commands.js
|
|
||||||
*
|
|
||||||
* Released under LGPL License.
|
|
||||||
* Copyright (c) 1999-2017 Ephox Corp. All rights reserved
|
|
||||||
*
|
|
||||||
* License: http://www.tinymce.com/license
|
|
||||||
* Contributing: http://www.tinymce.com/contributing
|
|
||||||
*/
|
|
||||||
|
|
||||||
const register = function (editor) {
|
|
||||||
editor.addCommand('mcePrint', function () {
|
|
||||||
editor.getWin().print();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
register
|
|
||||||
};
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
/**
|
|
||||||
* Commands.js
|
|
||||||
*
|
|
||||||
* Released under LGPL License.
|
|
||||||
* Copyright (c) 1999-2017 Ephox Corp. All rights reserved
|
|
||||||
*
|
|
||||||
* License: http://www.tinymce.com/license
|
|
||||||
* Contributing: http://www.tinymce.com/contributing
|
|
||||||
*/
|
|
||||||
|
|
||||||
import Dialog from '../ui/Dialog';
|
|
||||||
|
|
||||||
const register = function (editor, currentIndexState) {
|
|
||||||
editor.addCommand('SearchReplace', function () {
|
|
||||||
Dialog.open(editor, currentIndexState);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
register
|
|
||||||
};
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
/**
|
|
||||||
* Plugin.js
|
|
||||||
*
|
|
||||||
* Released under LGPL License.
|
|
||||||
* Copyright (c) 1999-2017 Ephox Corp. All rights reserved
|
|
||||||
*
|
|
||||||
* License: http://www.tinymce.com/license
|
|
||||||
* Contributing: http://www.tinymce.com/contributing
|
|
||||||
*/
|
|
||||||
|
|
||||||
import PluginManager from 'tinymce/core/api/PluginManager';
|
|
||||||
import Keyboard from './core/Keyboard';
|
|
||||||
|
|
||||||
PluginManager.add('tabfocus', function (editor) {
|
|
||||||
Keyboard.setup(editor);
|
|
||||||
});
|
|
||||||
|
|
||||||
export default function () { }
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
/**
|
|
||||||
* Plugin.js
|
|
||||||
*
|
|
||||||
* Released under LGPL License.
|
|
||||||
* Copyright (c) 1999-2017 Ephox Corp. All rights reserved
|
|
||||||
*
|
|
||||||
* License: http://www.tinymce.com/license
|
|
||||||
* Contributing: http://www.tinymce.com/contributing
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { Cell } from '@ephox/katamari';
|
|
||||||
import PluginManager from 'tinymce/core/api/PluginManager';
|
|
||||||
import Api from './api/Api';
|
|
||||||
import Settings from './api/Settings';
|
|
||||||
import Keyboard from './core/Keyboard';
|
|
||||||
|
|
||||||
PluginManager.add('textpattern', function (editor) {
|
|
||||||
const patternsState = Cell(Settings.getPatterns(editor.settings));
|
|
||||||
|
|
||||||
Keyboard.setup(editor, patternsState);
|
|
||||||
|
|
||||||
return Api.get(patternsState);
|
|
||||||
});
|
|
||||||
|
|
||||||
export default function () { }
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
/**
|
|
||||||
* Api.js
|
|
||||||
*
|
|
||||||
* Released under LGPL License.
|
|
||||||
* Copyright (c) 1999-2017 Ephox Corp. All rights reserved
|
|
||||||
*
|
|
||||||
* License: http://www.tinymce.com/license
|
|
||||||
* Contributing: http://www.tinymce.com/contributing
|
|
||||||
*/
|
|
||||||
|
|
||||||
const get = function (patternsState) {
|
|
||||||
const setPatterns = function (newPatterns) {
|
|
||||||
patternsState.set(newPatterns);
|
|
||||||
};
|
|
||||||
|
|
||||||
const getPatterns = function () {
|
|
||||||
return patternsState.get();
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
setPatterns,
|
|
||||||
getPatterns
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
get
|
|
||||||
};
|
|
||||||
|
|
@ -1,34 +0,0 @@
|
||||||
/**
|
|
||||||
* Settings.js
|
|
||||||
*
|
|
||||||
* Released under LGPL License.
|
|
||||||
* Copyright (c) 1999-2017 Ephox Corp. All rights reserved
|
|
||||||
*
|
|
||||||
* License: http://www.tinymce.com/license
|
|
||||||
* Contributing: http://www.tinymce.com/contributing
|
|
||||||
*/
|
|
||||||
|
|
||||||
const defaultPatterns = [
|
|
||||||
{ start: '*', end: '*', format: 'italic' },
|
|
||||||
{ start: '**', end: '**', format: 'bold' },
|
|
||||||
{ start: '***', end: '***', format: ['bold', 'italic'] },
|
|
||||||
{ start: '#', format: 'h1' },
|
|
||||||
{ start: '##', format: 'h2' },
|
|
||||||
{ start: '###', format: 'h3' },
|
|
||||||
{ start: '####', format: 'h4' },
|
|
||||||
{ start: '#####', format: 'h5' },
|
|
||||||
{ start: '######', format: 'h6' },
|
|
||||||
{ start: '1. ', cmd: 'InsertOrderedList' },
|
|
||||||
{ start: '* ', cmd: 'InsertUnorderedList' },
|
|
||||||
{ start: '- ', cmd: 'InsertUnorderedList' }
|
|
||||||
];
|
|
||||||
|
|
||||||
const getPatterns = function (editorSettings) {
|
|
||||||
return editorSettings.textpattern_patterns !== undefined ?
|
|
||||||
editorSettings.textpattern_patterns :
|
|
||||||
defaultPatterns;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
getPatterns
|
|
||||||
};
|
|
||||||
|
|
@ -1,175 +0,0 @@
|
||||||
/**
|
|
||||||
* Formatter.js
|
|
||||||
*
|
|
||||||
* Released under LGPL License.
|
|
||||||
* Copyright (c) 1999-2017 Ephox Corp. All rights reserved
|
|
||||||
*
|
|
||||||
* License: http://www.tinymce.com/license
|
|
||||||
* Contributing: http://www.tinymce.com/contributing
|
|
||||||
*/
|
|
||||||
|
|
||||||
import TreeWalker from 'tinymce/core/api/dom/TreeWalker';
|
|
||||||
import Tools from 'tinymce/core/api/util/Tools';
|
|
||||||
import Patterns from './Patterns';
|
|
||||||
import { document } from '@ephox/dom-globals';
|
|
||||||
|
|
||||||
const splitContainer = function (container, pattern, endOffset, startOffset, space) {
|
|
||||||
|
|
||||||
// Split text node and remove start/end from text node
|
|
||||||
container = startOffset > 0 ? container.splitText(startOffset) : container;
|
|
||||||
container.splitText(endOffset - startOffset + pattern.end.length);
|
|
||||||
container.deleteData(0, pattern.start.length);
|
|
||||||
container.deleteData(container.data.length - pattern.end.length, pattern.end.length);
|
|
||||||
|
|
||||||
return container;
|
|
||||||
};
|
|
||||||
|
|
||||||
const patternFromRng = function (patterns, rng, space) {
|
|
||||||
if (rng.collapsed === false) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const container = rng.startContainer;
|
|
||||||
const text = container.data;
|
|
||||||
const delta = space === true ? 1 : 0;
|
|
||||||
|
|
||||||
if (container.nodeType !== 3) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find best matching end
|
|
||||||
const endPattern = Patterns.findEndPattern(patterns, text, rng.startOffset, delta);
|
|
||||||
if (endPattern === undefined) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find start of matched pattern
|
|
||||||
let endOffset = text.lastIndexOf(endPattern.end, rng.startOffset - delta);
|
|
||||||
const startOffset = text.lastIndexOf(endPattern.start, endOffset - endPattern.end.length);
|
|
||||||
endOffset = text.indexOf(endPattern.end, startOffset + endPattern.start.length);
|
|
||||||
|
|
||||||
if (startOffset === -1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setup a range for the matching word
|
|
||||||
const patternRng = document.createRange();
|
|
||||||
patternRng.setStart(container, startOffset);
|
|
||||||
patternRng.setEnd(container, endOffset + endPattern.end.length);
|
|
||||||
|
|
||||||
const startPattern = Patterns.findPattern(patterns, patternRng.toString());
|
|
||||||
|
|
||||||
if (endPattern === undefined || startPattern !== endPattern || (container.data.length <= endPattern.start.length + endPattern.end.length)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
pattern: endPattern,
|
|
||||||
startOffset,
|
|
||||||
endOffset
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const splitAndApply = function (editor, container, found, space) {
|
|
||||||
const formatArray = Tools.isArray(found.pattern.format) ? found.pattern.format : [found.pattern.format];
|
|
||||||
const validFormats = Tools.grep(formatArray, function (formatName) {
|
|
||||||
const format = editor.formatter.get(formatName);
|
|
||||||
return format && format[0].inline;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (validFormats.length !== 0) {
|
|
||||||
editor.undoManager.transact(function () {
|
|
||||||
container = splitContainer(container, found.pattern, found.endOffset, found.startOffset, space);
|
|
||||||
formatArray.forEach(function (format) {
|
|
||||||
editor.formatter.apply(format, {}, container);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
return container;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Handles inline formats like *abc* and **abc**
|
|
||||||
const doApplyInlineFormat = function (editor, patterns, space) {
|
|
||||||
const rng = editor.selection.getRng(true);
|
|
||||||
const foundPattern = patternFromRng(patterns, rng, space);
|
|
||||||
|
|
||||||
if (foundPattern) {
|
|
||||||
return splitAndApply(editor, rng.startContainer, foundPattern, space);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const applyInlineFormatSpace = function (editor, patterns) {
|
|
||||||
return doApplyInlineFormat(editor, patterns, true);
|
|
||||||
};
|
|
||||||
const applyInlineFormatEnter = function (editor, patterns) {
|
|
||||||
return doApplyInlineFormat(editor, patterns, false);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Handles block formats like ##abc or 1. abc
|
|
||||||
const applyBlockFormat = function (editor, patterns) {
|
|
||||||
let selection, dom, container, firstTextNode, node, format, textBlockElm, pattern, walker, rng, offset;
|
|
||||||
|
|
||||||
selection = editor.selection;
|
|
||||||
dom = editor.dom;
|
|
||||||
|
|
||||||
if (!selection.isCollapsed()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
textBlockElm = dom.getParent(selection.getStart(), 'p');
|
|
||||||
if (textBlockElm) {
|
|
||||||
walker = new TreeWalker(textBlockElm, textBlockElm);
|
|
||||||
while ((node = walker.next())) {
|
|
||||||
if (node.nodeType === 3) {
|
|
||||||
firstTextNode = node;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (firstTextNode) {
|
|
||||||
pattern = Patterns.findPattern(patterns, firstTextNode.data);
|
|
||||||
if (!pattern) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
rng = selection.getRng(true);
|
|
||||||
container = rng.startContainer;
|
|
||||||
offset = rng.startOffset;
|
|
||||||
|
|
||||||
if (firstTextNode === container) {
|
|
||||||
offset = Math.max(0, offset - pattern.start.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Tools.trim(firstTextNode.data).length === pattern.start.length) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pattern.format) {
|
|
||||||
format = editor.formatter.get(pattern.format);
|
|
||||||
if (format && format[0].block) {
|
|
||||||
firstTextNode.deleteData(0, pattern.start.length);
|
|
||||||
editor.formatter.apply(pattern.format, {}, firstTextNode);
|
|
||||||
|
|
||||||
rng.setStart(container, offset);
|
|
||||||
rng.collapse(true);
|
|
||||||
selection.setRng(rng);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pattern.cmd) {
|
|
||||||
editor.undoManager.transact(function () {
|
|
||||||
firstTextNode.deleteData(0, pattern.start.length);
|
|
||||||
editor.execCommand(pattern.cmd);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
patternFromRng,
|
|
||||||
applyInlineFormatSpace,
|
|
||||||
applyInlineFormatEnter,
|
|
||||||
applyBlockFormat
|
|
||||||
};
|
|
||||||
|
|
@ -1,76 +0,0 @@
|
||||||
/**
|
|
||||||
* KeyHandler.js
|
|
||||||
*
|
|
||||||
* Released under LGPL License.
|
|
||||||
* Copyright (c) 1999-2017 Ephox Corp. All rights reserved
|
|
||||||
*
|
|
||||||
* License: http://www.tinymce.com/license
|
|
||||||
* Contributing: http://www.tinymce.com/contributing
|
|
||||||
*/
|
|
||||||
|
|
||||||
import VK from 'tinymce/core/api/util/VK';
|
|
||||||
import Formatter from './Formatter';
|
|
||||||
|
|
||||||
function handleEnter(editor, patterns) {
|
|
||||||
let wrappedTextNode, rng;
|
|
||||||
|
|
||||||
wrappedTextNode = Formatter.applyInlineFormatEnter(editor, patterns);
|
|
||||||
if (wrappedTextNode) {
|
|
||||||
rng = editor.dom.createRng();
|
|
||||||
rng.setStart(wrappedTextNode, wrappedTextNode.data.length);
|
|
||||||
rng.setEnd(wrappedTextNode, wrappedTextNode.data.length);
|
|
||||||
editor.selection.setRng(rng);
|
|
||||||
}
|
|
||||||
|
|
||||||
Formatter.applyBlockFormat(editor, patterns);
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleInlineKey(editor, patterns) {
|
|
||||||
let wrappedTextNode, lastChar, lastCharNode, rng, dom;
|
|
||||||
|
|
||||||
wrappedTextNode = Formatter.applyInlineFormatSpace(editor, patterns);
|
|
||||||
if (wrappedTextNode) {
|
|
||||||
dom = editor.dom;
|
|
||||||
lastChar = wrappedTextNode.data.slice(-1);
|
|
||||||
|
|
||||||
// Move space after the newly formatted node
|
|
||||||
if (/[\u00a0 ]/.test(lastChar)) {
|
|
||||||
wrappedTextNode.deleteData(wrappedTextNode.data.length - 1, 1);
|
|
||||||
lastCharNode = dom.doc.createTextNode(lastChar);
|
|
||||||
|
|
||||||
dom.insertAfter(lastCharNode, wrappedTextNode.parentNode);
|
|
||||||
|
|
||||||
rng = dom.createRng();
|
|
||||||
rng.setStart(lastCharNode, 1);
|
|
||||||
rng.setEnd(lastCharNode, 1);
|
|
||||||
editor.selection.setRng(rng);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const checkKeyEvent = function (codes, event, predicate) {
|
|
||||||
for (let i = 0; i < codes.length; i++) {
|
|
||||||
if (predicate(codes[i], event)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const checkKeyCode = function (codes, event) {
|
|
||||||
return checkKeyEvent(codes, event, function (code, event) {
|
|
||||||
return code === event.keyCode && VK.modifierPressed(event) === false;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const checkCharCode = function (chars, event) {
|
|
||||||
return checkKeyEvent(chars, event, function (chr, event) {
|
|
||||||
return chr.charCodeAt(0) === event.charCode;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
handleEnter,
|
|
||||||
handleInlineKey,
|
|
||||||
checkCharCode,
|
|
||||||
checkKeyCode
|
|
||||||
};
|
|
||||||
|
|
@ -1,67 +0,0 @@
|
||||||
/**
|
|
||||||
* Patterns.js
|
|
||||||
*
|
|
||||||
* Released under LGPL License.
|
|
||||||
* Copyright (c) 1999-2017 Ephox Corp. All rights reserved
|
|
||||||
*
|
|
||||||
* License: http://www.tinymce.com/license
|
|
||||||
* Contributing: http://www.tinymce.com/contributing
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Returns a sorted patterns list, ordered descending by start length
|
|
||||||
const sortPatterns = function (patterns) {
|
|
||||||
return patterns.sort(function (a, b) {
|
|
||||||
if (a.start.length > b.start.length) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (a.start.length < b.start.length) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// Finds a matching pattern to the specified text
|
|
||||||
const findPattern = function (patterns, text) {
|
|
||||||
for (let i = 0; i < patterns.length; i++) {
|
|
||||||
if (text.indexOf(patterns[i].start) !== 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (patterns[i].end && text.lastIndexOf(patterns[i].end) !== (text.length - patterns[i].end.length)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
return patterns[i];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const isMatchingPattern = function (pattern, text, offset, delta) {
|
|
||||||
const textEnd = text.substr(offset - pattern.end.length - delta, pattern.end.length);
|
|
||||||
return textEnd === pattern.end;
|
|
||||||
};
|
|
||||||
|
|
||||||
const hasContent = function (offset, delta, pattern) {
|
|
||||||
return (offset - delta - pattern.end.length - pattern.start.length) > 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Finds the best matching end pattern
|
|
||||||
const findEndPattern = function (patterns, text, offset, delta) {
|
|
||||||
let pattern, i;
|
|
||||||
const sortedPatterns = sortPatterns(patterns);
|
|
||||||
|
|
||||||
// Find best matching end
|
|
||||||
for (i = 0; i < sortedPatterns.length; i++) {
|
|
||||||
pattern = sortedPatterns[i];
|
|
||||||
if (pattern.end !== undefined && isMatchingPattern(pattern, text, offset, delta) && hasContent(offset, delta, pattern)) {
|
|
||||||
return pattern;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
findPattern,
|
|
||||||
findEndPattern
|
|
||||||
};
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
/**
|
|
||||||
* Guid.js
|
|
||||||
*
|
|
||||||
* Released under LGPL License.
|
|
||||||
* Copyright (c) 1999-2017 Ephox Corp. All rights reserved
|
|
||||||
*
|
|
||||||
* License: http://www.tinymce.com/license
|
|
||||||
* Contributing: http://www.tinymce.com/contributing
|
|
||||||
*/
|
|
||||||
|
|
||||||
const create = function (prefix) {
|
|
||||||
let counter = 0;
|
|
||||||
|
|
||||||
return function () {
|
|
||||||
const guid = new Date().getTime().toString(32);
|
|
||||||
return prefix + guid + (counter++).toString(32);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
create
|
|
||||||
};
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
/**
|
|
||||||
* Events.js
|
|
||||||
*
|
|
||||||
* Released under LGPL License.
|
|
||||||
* Copyright (c) 1999-2017 Ephox Corp. All rights reserved
|
|
||||||
*
|
|
||||||
* License: http://www.tinymce.com/license
|
|
||||||
* Contributing: http://www.tinymce.com/contributing
|
|
||||||
*/
|
|
||||||
|
|
||||||
const fireVisualBlocks = function (editor, state) {
|
|
||||||
editor.fire('VisualBlocks', { state });
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
fireVisualBlocks
|
|
||||||
};
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
/**
|
|
||||||
* Api.js
|
|
||||||
*
|
|
||||||
* Released under LGPL License.
|
|
||||||
* Copyright (c) 1999-2017 Ephox Corp. All rights reserved
|
|
||||||
*
|
|
||||||
* License: http://www.tinymce.com/license
|
|
||||||
* Contributing: http://www.tinymce.com/contributing
|
|
||||||
*/
|
|
||||||
|
|
||||||
const get = function (toggleState) {
|
|
||||||
const isEnabled = function () {
|
|
||||||
return toggleState.get();
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
isEnabled
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
get
|
|
||||||
};
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
/**
|
|
||||||
* Events.js
|
|
||||||
*
|
|
||||||
* Released under LGPL License.
|
|
||||||
* Copyright (c) 1999-2017 Ephox Corp. All rights reserved
|
|
||||||
*
|
|
||||||
* License: http://www.tinymce.com/license
|
|
||||||
* Contributing: http://www.tinymce.com/contributing
|
|
||||||
*/
|
|
||||||
|
|
||||||
const fireVisualChars = function (editor, state) {
|
|
||||||
return editor.fire('VisualChars', { state });
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
fireVisualChars
|
|
||||||
};
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
/**
|
|
||||||
* Html.js
|
|
||||||
*
|
|
||||||
* Released under LGPL License.
|
|
||||||
* Copyright (c) 1999-2017 Ephox Corp. All rights reserved
|
|
||||||
*
|
|
||||||
* License: http://www.tinymce.com/license
|
|
||||||
* Contributing: http://www.tinymce.com/contributing
|
|
||||||
*/
|
|
||||||
|
|
||||||
import Data from './Data';
|
|
||||||
|
|
||||||
const wrapCharWithSpan = function (value) {
|
|
||||||
return '<span data-mce-bogus="1" class="mce-' + Data.charMap[value] + '">' + value + '</span>';
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
wrapCharWithSpan
|
|
||||||
};
|
|
||||||
|
|
@ -1,54 +0,0 @@
|
||||||
/**
|
|
||||||
* Arr.js
|
|
||||||
*
|
|
||||||
* Released under LGPL License.
|
|
||||||
* Copyright (c) 1999-2016 Ephox Corp. All rights reserved
|
|
||||||
*
|
|
||||||
* License: http://www.tinymce.com/license
|
|
||||||
* Contributing: http://www.tinymce.com/contributing
|
|
||||||
*/
|
|
||||||
|
|
||||||
const each = function (o, cb, s?) {
|
|
||||||
let n, l;
|
|
||||||
|
|
||||||
if (!o) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
s = s || o;
|
|
||||||
|
|
||||||
if (o.length !== undefined) {
|
|
||||||
// Indexed arrays, needed for Safari
|
|
||||||
for (n = 0, l = o.length; n < l; n++) {
|
|
||||||
if (cb.call(s, o[n], n, o) === false) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Hashtables
|
|
||||||
for (n in o) {
|
|
||||||
if (o.hasOwnProperty(n)) {
|
|
||||||
if (cb.call(s, o[n], n, o) === false) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
const map = function (array, callback) {
|
|
||||||
const out = [];
|
|
||||||
|
|
||||||
each(array, function (item, index) {
|
|
||||||
out.push(callback(item, index, array));
|
|
||||||
});
|
|
||||||
|
|
||||||
return out;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
each,
|
|
||||||
map
|
|
||||||
};
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
/**
|
|
||||||
* Api.js
|
|
||||||
*
|
|
||||||
* Released under LGPL License.
|
|
||||||
* Copyright (c) 1999-2016 Ephox Corp. All rights reserved
|
|
||||||
*
|
|
||||||
* License: http://www.tinymce.com/license
|
|
||||||
* Contributing: http://www.tinymce.com/contributing
|
|
||||||
*/
|
|
||||||
|
|
||||||
import WordCount from '../text/WordCount';
|
|
||||||
|
|
||||||
const get = function (editor) {
|
|
||||||
const getCount = function () {
|
|
||||||
return WordCount.getCount(editor);
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
getCount
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
get
|
|
||||||
};
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
/**
|
|
||||||
* Arr.js
|
|
||||||
*
|
|
||||||
* Released under LGPL License.
|
|
||||||
* Copyright (c) 1999-2016 Ephox Corp. All rights reserved
|
|
||||||
*
|
|
||||||
* License: http://www.tinymce.com/license
|
|
||||||
* Contributing: http://www.tinymce.com/contributing
|
|
||||||
*/
|
|
||||||
|
|
||||||
const flatten = function (arr: any[]) {
|
|
||||||
return arr.reduce(function (results: any[], item) {
|
|
||||||
return Array.isArray(item) ? results.concat(flatten(item)) : results.concat(item);
|
|
||||||
}, []);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
flatten
|
|
||||||
};
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
import { Fun } from '@ephox/katamari';
|
|
||||||
|
|
||||||
const prefix = 'tinymce-mobile';
|
|
||||||
|
|
||||||
const resolve = function (p) {
|
|
||||||
return prefix + '-' + p;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
resolve,
|
|
||||||
prefix: Fun.constant(prefix)
|
|
||||||
};
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
import { Attr } from '@ephox/sugar';
|
|
||||||
|
|
||||||
const safeParse = function (element, attribute) {
|
|
||||||
const parsed = parseInt(Attr.get(element, attribute), 10);
|
|
||||||
return isNaN(parsed) ? 0 : parsed;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
safeParse
|
|
||||||
};
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "tinymce",
|
"name": "tinymce",
|
||||||
"version": "4.8.5",
|
"version": "4.9.2",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/tinymce/tinymce.git"
|
"url": "https://github.com/tinymce/tinymce.git"
|
||||||
|
|
@ -30,7 +30,8 @@
|
||||||
"@ephox/robin": "latest",
|
"@ephox/robin": "latest",
|
||||||
"@ephox/sand": "latest",
|
"@ephox/sand": "latest",
|
||||||
"@ephox/snooker": "latest",
|
"@ephox/snooker": "latest",
|
||||||
"@ephox/sugar": "latest"
|
"@ephox/sugar": "latest",
|
||||||
|
"tslib": "^1.9.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@ephox/agar": "latest",
|
"@ephox/agar": "latest",
|
||||||
|
|
@ -53,12 +54,13 @@
|
||||||
"less-plugin-autoprefix": "^1.5.1",
|
"less-plugin-autoprefix": "^1.5.1",
|
||||||
"load-grunt-tasks": "^4.0.0",
|
"load-grunt-tasks": "^4.0.0",
|
||||||
"moxie-zip": "~0.0.3",
|
"moxie-zip": "~0.0.3",
|
||||||
"tslint": "^5.9.1",
|
"rimraf": "^2.6.2",
|
||||||
|
"string-replace-loader": "^2.1.1",
|
||||||
"ts-loader": "^5.3.0",
|
"ts-loader": "^5.3.0",
|
||||||
|
"tslint": "^5.9.1",
|
||||||
"typescript": "^3.1.5",
|
"typescript": "^3.1.5",
|
||||||
"webpack": "^4.8.3",
|
"webpack": "^4.8.3",
|
||||||
"webpack-dev-server": "^3.1.5",
|
"webpack-dev-server": "^3.1.5",
|
||||||
"webpack-livereload-plugin": "^2.1.1",
|
"webpack-livereload-plugin": "^2.1.1"
|
||||||
"rimraf": "^2.6.2"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
# trunkImages TinyMCE Plugin
|
||||||
|
|
||||||
|
Welcome stranger! This is a repo containing the trunkImages TinyMCE plugin.
|
||||||
|
|
||||||
|
## The development server
|
||||||
|
|
||||||
|
By running the `npm start` command you start the development server and open a browser window with an instance of TinyMCE with your plugin added to it. This window will reload automatically whenever a change is detected in the `index.html` file in the `static` folder or in one of the TypeScript files in the `src` directory.
|
||||||
|
|
||||||
|
## The production build
|
||||||
|
|
||||||
|
By running the `npm run build` command Webpack will create a `dist` directory with a child directory with the name of your plugin (trunk-images) containing three files:
|
||||||
|
|
||||||
|
* `plugin.js` - the bundled plugin
|
||||||
|
* `plugin.min.js` - the bundles, uglified and minified plugin
|
||||||
|
* `LICENSE` - a file explaining the license of your plugin (copied over from `src/LICENSE`)
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
const path = require("path");
|
||||||
|
const webpack = require("webpack");
|
||||||
|
const CopyWebpackPlugin = require("copy-webpack-plugin");
|
||||||
|
|
||||||
|
const pluginName = "ccm-cms-images";
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
entry: {
|
||||||
|
plugin: "./src/index.ts",
|
||||||
|
"plugin.min": "./src/index.ts"
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
path: path.join(__dirname, "../../../../../ccm-core/web/assets/tinymce/js/tinymce/plugins", pluginName),
|
||||||
|
filename: "[name].js"
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
extensions: [".webpack.js", ".web.js", ".ts", ".js"]
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
rules: [{
|
||||||
|
test: /\.ts$/,
|
||||||
|
use: "ts-loader"
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
new webpack.optimize.UglifyJsPlugin({
|
||||||
|
include: /\.min\.js$/,
|
||||||
|
minimize: true
|
||||||
|
}),
|
||||||
|
new CopyWebpackPlugin([{
|
||||||
|
from: path.join(__dirname, "../src/LICENSE"),
|
||||||
|
to: path.join(__dirname, "../dist", pluginName)
|
||||||
|
}])
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
const path = require("path");
|
||||||
|
const webpack = require("webpack");
|
||||||
|
const CopyWebpackPlugin = require("copy-webpack-plugin");
|
||||||
|
|
||||||
|
const pluginName = "ccm-cms-images";
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
entry: {
|
||||||
|
plugin: "./src/index.ts",
|
||||||
|
"plugin.min": "./src/index.ts"
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
path: path.join(__dirname, "../../../../../runtime/apache-tomcat-8.5.15/webapps/ROOT/assets/tinymce/js/tinymce/plugins", pluginName),
|
||||||
|
filename: "[name].js"
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
extensions: [".webpack.js", ".web.js", ".ts", ".js"]
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
rules: [{
|
||||||
|
test: /\.ts$/,
|
||||||
|
use: "ts-loader"
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
new webpack.optimize.UglifyJsPlugin({
|
||||||
|
include: /\.min\.js$/,
|
||||||
|
minimize: true
|
||||||
|
}),
|
||||||
|
new CopyWebpackPlugin([{
|
||||||
|
from: path.join(__dirname, "../src/LICENSE"),
|
||||||
|
to: path.join(__dirname, "../dist", pluginName)
|
||||||
|
}])
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
{
|
||||||
|
"name": "ccm-cms-images",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "CCM CMS Images TinyMCE plugin",
|
||||||
|
"main": "index.js",
|
||||||
|
"watch": {
|
||||||
|
"build": "src/*.ts"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"postinstall": "typings install",
|
||||||
|
"start": "webpack-dev-server --config config/webpack.config.dev.js --progress --open --inline",
|
||||||
|
"lint": "tslint 'src/**/*.js'",
|
||||||
|
"build": "webpack --config config/webpack.config.prod.js --progress",
|
||||||
|
"test": "webpack --config config/webpack.config.test.js --progress",
|
||||||
|
"watch": "npm-watch"
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "MIT",
|
||||||
|
"devDependencies": {
|
||||||
|
"copy-webpack-plugin": "^4.0.1",
|
||||||
|
"html-webpack-plugin": "^2.26.0",
|
||||||
|
"ts-loader": "^1.3.3",
|
||||||
|
"tslint": "^4.2.0",
|
||||||
|
"typescript": "^2.1.4",
|
||||||
|
"typings": "^2.1.0",
|
||||||
|
"webpack": "^2.2.0",
|
||||||
|
"webpack-dev-server": "^1.16.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"lodash": "^4.17.4",
|
||||||
|
"npm-watch": "^0.4.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,305 @@
|
||||||
|
declare var tinymce: any;
|
||||||
|
|
||||||
|
export default function(editor) {
|
||||||
|
function getImageData(editor) {
|
||||||
|
const elem = editor.selection.getNode();
|
||||||
|
const imgDiv = editor.dom.getParent(elem, "div.image");
|
||||||
|
const img = editor.dom.select("img", imgDiv)[0];
|
||||||
|
if (imgDiv != null) {
|
||||||
|
let imageData = {
|
||||||
|
file: img.getAttribute("src"),
|
||||||
|
width: img.getAttribute("width").slice(0, -2),
|
||||||
|
height: img.getAttribute("height").slice(0, -2),
|
||||||
|
alt: img.getAttribute("alt"),
|
||||||
|
align: imgDiv.classList[1],
|
||||||
|
fancy: imgDiv.childNodes[0].classList[0].slice(0, -1),
|
||||||
|
title: imgDiv.childNodes[0].title,
|
||||||
|
caption: imgDiv.childNodes[1].localName == "span",
|
||||||
|
parent: imgDiv
|
||||||
|
};
|
||||||
|
console.log(imageData);
|
||||||
|
return imageData;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function open() {
|
||||||
|
const imageData = getImageData(editor);
|
||||||
|
let image_name = "";
|
||||||
|
|
||||||
|
// ================== File Chooser ====================
|
||||||
|
let fileChooseContainer = new tinymce.ui.Container({
|
||||||
|
type: "container",
|
||||||
|
layout: "flex",
|
||||||
|
direction: "row",
|
||||||
|
align: "center",
|
||||||
|
padding: 5,
|
||||||
|
spacing: 15,
|
||||||
|
margin: 5
|
||||||
|
});
|
||||||
|
|
||||||
|
let imagePathTextBox = new tinymce.ui.TextBox({
|
||||||
|
name: "file",
|
||||||
|
label: "File:",
|
||||||
|
disabled: true
|
||||||
|
});
|
||||||
|
|
||||||
|
fileChooseContainer.add(imagePathTextBox);
|
||||||
|
|
||||||
|
let browseButton = new tinymce.ui.Button({
|
||||||
|
name: "browse_images",
|
||||||
|
text: "Browse Images",
|
||||||
|
onclick: function() {
|
||||||
|
let baseURL = window.location.href;
|
||||||
|
let offset = baseURL.lastIndexOf("/");
|
||||||
|
let destURL = baseURL.slice(0, offset + 1) + "image_select.jsp";
|
||||||
|
let selectWindow = window.open(
|
||||||
|
destURL,
|
||||||
|
"_blank",
|
||||||
|
"scrollbars=yes,directories=no,toolbar=no,width=800,height=600,status=no,menubar=no"
|
||||||
|
);
|
||||||
|
(<any>window).openCCM = new Object();
|
||||||
|
(<any>window).openCCM.imageSet = selectedImage => {
|
||||||
|
imagePathTextBox.text(selectedImage.src);
|
||||||
|
win
|
||||||
|
.find("#file")
|
||||||
|
.value(selectedImage.src)
|
||||||
|
.fire("change");
|
||||||
|
win
|
||||||
|
.find("#width")
|
||||||
|
.value(selectedImage.width)
|
||||||
|
.fire("change");
|
||||||
|
win
|
||||||
|
.find("#height")
|
||||||
|
.value(selectedImage.height)
|
||||||
|
.fire("change");
|
||||||
|
image_name = selectedImage.name;
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
fileChooseContainer.add(browseButton);
|
||||||
|
// ================== File Chooser ====================
|
||||||
|
|
||||||
|
// ================== Alternate Text ==================
|
||||||
|
let alternateTextBox = new tinymce.ui.TextBox({
|
||||||
|
name: "alternate",
|
||||||
|
label: "Alternate:"
|
||||||
|
});
|
||||||
|
// ================== Alternate Text ==================
|
||||||
|
|
||||||
|
// ================== Title Text ======================
|
||||||
|
let titleTextBox = new tinymce.ui.TextBox({
|
||||||
|
name: "title",
|
||||||
|
label: "Title:"
|
||||||
|
});
|
||||||
|
// ================== Title Text ======================
|
||||||
|
|
||||||
|
// ================== Alignment =======================
|
||||||
|
let alignmentContainer = new tinymce.ui.Container({
|
||||||
|
type: "container",
|
||||||
|
layout: "flex",
|
||||||
|
direction: "row"
|
||||||
|
});
|
||||||
|
|
||||||
|
let alginLabel = new tinymce.ui.Label({
|
||||||
|
text: "Alignment:"
|
||||||
|
});
|
||||||
|
|
||||||
|
let alignListBox = new tinymce.ui.ListBox({
|
||||||
|
name: "alignment",
|
||||||
|
values: [
|
||||||
|
{ text: "Not set", value: "" },
|
||||||
|
{ text: "Left", value: "left" },
|
||||||
|
{ text: "Center", value: "center" },
|
||||||
|
{ text: "Right", value: "right" }
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
alignmentContainer.add(alginLabel);
|
||||||
|
alignmentContainer.add(alignListBox);
|
||||||
|
// ================== Alignment =======================
|
||||||
|
|
||||||
|
// ================== Fancy Box =======================
|
||||||
|
let fancyBoxContainer = new tinymce.ui.Container({
|
||||||
|
type: "container",
|
||||||
|
layout: "flex",
|
||||||
|
direction: "row"
|
||||||
|
});
|
||||||
|
|
||||||
|
let fancyBoxLabel = new tinymce.ui.Label({
|
||||||
|
text: "Fancy Box:"
|
||||||
|
});
|
||||||
|
|
||||||
|
let fancyBoxListBox = new tinymce.ui.ListBox({
|
||||||
|
name: "fancybox",
|
||||||
|
values: [
|
||||||
|
{ text: "None", value: "" },
|
||||||
|
{ text: "Zoom", value: "imageZoom" },
|
||||||
|
{ text: "Gallery", value: "imageGallery" }
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
fancyBoxContainer.add(fancyBoxLabel);
|
||||||
|
fancyBoxContainer.add(fancyBoxListBox);
|
||||||
|
// ================== Fancy Box =======================
|
||||||
|
|
||||||
|
// ================== Caption =========================
|
||||||
|
let captionCheckBox = new tinymce.ui.Checkbox({
|
||||||
|
label: "Caption:",
|
||||||
|
name: "caption"
|
||||||
|
});
|
||||||
|
// ================== Caption =========================
|
||||||
|
|
||||||
|
// ================== Dimension Box ===================
|
||||||
|
let dimensionContainer = new tinymce.ui.Container({
|
||||||
|
label: "Dimension",
|
||||||
|
layout: "flex",
|
||||||
|
direction: "row",
|
||||||
|
align: "center",
|
||||||
|
padding: 5,
|
||||||
|
spacing: 15,
|
||||||
|
margin: 5
|
||||||
|
});
|
||||||
|
|
||||||
|
let widthTextBox = new tinymce.ui.TextBox({
|
||||||
|
name: "width",
|
||||||
|
label: "Width"
|
||||||
|
});
|
||||||
|
|
||||||
|
let heightTextBox = new tinymce.ui.TextBox({
|
||||||
|
name: "height",
|
||||||
|
label: "Height"
|
||||||
|
});
|
||||||
|
|
||||||
|
dimensionContainer.add(widthTextBox);
|
||||||
|
dimensionContainer.add({ type: "label", text: "X" });
|
||||||
|
dimensionContainer.add(heightTextBox);
|
||||||
|
// ================== Dimension Box ===================
|
||||||
|
|
||||||
|
const win = editor.windowManager.open({
|
||||||
|
title: "Insert/Modify Image",
|
||||||
|
width: 800,
|
||||||
|
height: 600,
|
||||||
|
body: [
|
||||||
|
fileChooseContainer,
|
||||||
|
alternateTextBox,
|
||||||
|
titleTextBox,
|
||||||
|
alignmentContainer,
|
||||||
|
fancyBoxContainer,
|
||||||
|
captionCheckBox,
|
||||||
|
dimensionContainer
|
||||||
|
],
|
||||||
|
onsubmit: function() {
|
||||||
|
let src = win.find("#file").value();
|
||||||
|
let alternate = win.find("#alternate").value();
|
||||||
|
let width = win.find("#width").value();
|
||||||
|
let height = win.find("#height").value();
|
||||||
|
let title = win.find("#title").value();
|
||||||
|
let alignment = win.find("#alignment").value();
|
||||||
|
let fancy_box = win.find("#fancybox").value();
|
||||||
|
|
||||||
|
if (src != null) {
|
||||||
|
let img =
|
||||||
|
"<img src=" +
|
||||||
|
src +
|
||||||
|
' alt="' +
|
||||||
|
alternate +
|
||||||
|
'" name="' +
|
||||||
|
image_name +
|
||||||
|
'" width="' +
|
||||||
|
width +
|
||||||
|
'px"' +
|
||||||
|
' height="' +
|
||||||
|
height +
|
||||||
|
'px"' +
|
||||||
|
" />";
|
||||||
|
|
||||||
|
let fancy_box_wrap =
|
||||||
|
"<a class=" +
|
||||||
|
fancy_box +
|
||||||
|
'" href="' +
|
||||||
|
src +
|
||||||
|
'" title="' +
|
||||||
|
title +
|
||||||
|
'" data-mce-href="' +
|
||||||
|
src +
|
||||||
|
'"> ' +
|
||||||
|
img +
|
||||||
|
"</a>";
|
||||||
|
let span = "";
|
||||||
|
if (win.find("#caption").value()) {
|
||||||
|
span =
|
||||||
|
'<span class="caption" style="width: ' +
|
||||||
|
width +
|
||||||
|
'px;" data-mce-style="width: ' +
|
||||||
|
width +
|
||||||
|
'px;">' +
|
||||||
|
image_name +
|
||||||
|
"</span>";
|
||||||
|
}
|
||||||
|
let img_div =
|
||||||
|
'<div class="image ' +
|
||||||
|
alignment +
|
||||||
|
'">' +
|
||||||
|
fancy_box_wrap +
|
||||||
|
span +
|
||||||
|
"</div>";
|
||||||
|
if (imageData != null) {
|
||||||
|
editor.dom.replace(
|
||||||
|
editor.dom.createFragment(img_div),
|
||||||
|
imageData.parent
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
editor.insertContent(img_div);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// ================== Fill with selection =============
|
||||||
|
if (imageData != null) {
|
||||||
|
win
|
||||||
|
.find("#file")
|
||||||
|
.value(imageData.file)
|
||||||
|
.fire("change");
|
||||||
|
win
|
||||||
|
.find("#alternate")
|
||||||
|
.value(imageData.alt)
|
||||||
|
.fire("change");
|
||||||
|
win
|
||||||
|
.find("#width")
|
||||||
|
.value(imageData.width)
|
||||||
|
.fire("change");
|
||||||
|
win
|
||||||
|
.find("#height")
|
||||||
|
.value(imageData.height)
|
||||||
|
.fire("change");
|
||||||
|
if (imageData.align != undefined) {
|
||||||
|
win
|
||||||
|
.find("#alignment")
|
||||||
|
.value(imageData.align)
|
||||||
|
.fire("change");
|
||||||
|
}
|
||||||
|
if (imageData.fancy != undefined) {
|
||||||
|
win
|
||||||
|
.find("#fancybox")
|
||||||
|
.value(imageData.fancy)
|
||||||
|
.fire("change");
|
||||||
|
}
|
||||||
|
win
|
||||||
|
.find("#title")
|
||||||
|
.value(imageData.title)
|
||||||
|
.fire("change");
|
||||||
|
win
|
||||||
|
.find("#caption")
|
||||||
|
.value(imageData.caption)
|
||||||
|
.fire("change");
|
||||||
|
}
|
||||||
|
// ================== Fill with selection =============
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
open
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2018 Yannick Bülter <yannick.buelter@yabue.de>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
import plugin from "./plugin";
|
||||||
|
|
||||||
|
declare var tinymce: any;
|
||||||
|
|
||||||
|
tinymce.PluginManager.add("ccm-cms-images", plugin);
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
import Dialog from "./Dialog";
|
||||||
|
declare var tinymce: any;
|
||||||
|
|
||||||
|
const plugin = (editor: any, url: String) => {
|
||||||
|
editor.addButton("ccm-cms-images-button", {
|
||||||
|
icon: "image",
|
||||||
|
tooltip: "Insert/Edit image",
|
||||||
|
onlick: Dialog(editor).open,
|
||||||
|
stateSelector: "div.image"
|
||||||
|
});
|
||||||
|
|
||||||
|
editor.addMenuItem("ccm-cms-images-menu", {
|
||||||
|
icon: "image",
|
||||||
|
text: "Insert/Edit Images",
|
||||||
|
onclick: Dialog(editor).open,
|
||||||
|
stateSelector: "image",
|
||||||
|
context: "insert",
|
||||||
|
prependToContext: true
|
||||||
|
});
|
||||||
|
};
|
||||||
|
export default plugin;
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<script src="//cdn.tinymce.com/4/tinymce.min.js"></script>
|
||||||
|
<script>
|
||||||
|
tinymce.init({
|
||||||
|
selector: 'textarea',
|
||||||
|
plugins: 'trunk-images',
|
||||||
|
toolbar: 'trunk-images'
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<textarea>Testing trunk-images.</textarea>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"noImplicitAny": false,
|
||||||
|
"removeComments": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,101 @@
|
||||||
|
{
|
||||||
|
"jsRules": {
|
||||||
|
"class-name": true,
|
||||||
|
"comment-format": [
|
||||||
|
true,
|
||||||
|
"check-space"
|
||||||
|
],
|
||||||
|
"indent": [
|
||||||
|
true,
|
||||||
|
"spaces"
|
||||||
|
],
|
||||||
|
"no-duplicate-variable": true,
|
||||||
|
"no-eval": true,
|
||||||
|
"no-trailing-whitespace": true,
|
||||||
|
"no-unsafe-finally": true,
|
||||||
|
"one-line": [
|
||||||
|
true,
|
||||||
|
"check-open-brace",
|
||||||
|
"check-whitespace"
|
||||||
|
],
|
||||||
|
"quotemark": [
|
||||||
|
true,
|
||||||
|
"double"
|
||||||
|
],
|
||||||
|
"semicolon": [
|
||||||
|
true,
|
||||||
|
"always"
|
||||||
|
],
|
||||||
|
"triple-equals": [
|
||||||
|
true,
|
||||||
|
"allow-null-check"
|
||||||
|
],
|
||||||
|
"variable-name": [
|
||||||
|
true,
|
||||||
|
"ban-keywords"
|
||||||
|
],
|
||||||
|
"whitespace": [
|
||||||
|
true,
|
||||||
|
"check-branch",
|
||||||
|
"check-decl",
|
||||||
|
"check-operator",
|
||||||
|
"check-separator",
|
||||||
|
"check-type"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"rules": {
|
||||||
|
"class-name": true,
|
||||||
|
"comment-format": [
|
||||||
|
true,
|
||||||
|
"check-space"
|
||||||
|
],
|
||||||
|
"indent": [
|
||||||
|
true,
|
||||||
|
"spaces"
|
||||||
|
],
|
||||||
|
"no-eval": true,
|
||||||
|
"no-internal-module": true,
|
||||||
|
"no-trailing-whitespace": true,
|
||||||
|
"no-unsafe-finally": true,
|
||||||
|
"no-var-keyword": true,
|
||||||
|
"one-line": [
|
||||||
|
true,
|
||||||
|
"check-open-brace",
|
||||||
|
"check-whitespace"
|
||||||
|
],
|
||||||
|
"quotemark": [
|
||||||
|
true,
|
||||||
|
"double"
|
||||||
|
],
|
||||||
|
"semicolon": [
|
||||||
|
true,
|
||||||
|
"always"
|
||||||
|
],
|
||||||
|
"triple-equals": [
|
||||||
|
true,
|
||||||
|
"allow-null-check"
|
||||||
|
],
|
||||||
|
"typedef-whitespace": [
|
||||||
|
true,
|
||||||
|
{
|
||||||
|
"call-signature": "nospace",
|
||||||
|
"index-signature": "nospace",
|
||||||
|
"parameter": "nospace",
|
||||||
|
"property-declaration": "nospace",
|
||||||
|
"variable-declaration": "nospace"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"variable-name": [
|
||||||
|
true,
|
||||||
|
"ban-keywords"
|
||||||
|
],
|
||||||
|
"whitespace": [
|
||||||
|
true,
|
||||||
|
"check-branch",
|
||||||
|
"check-decl",
|
||||||
|
"check-operator",
|
||||||
|
"check-separator",
|
||||||
|
"check-type"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"dependencies": {
|
||||||
|
"lodash": "registry:npm/lodash#4.0.0+20161015015725"
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue