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.
|
||||
|
||||
## 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)
|
||||
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
|
||||
|
|
@ -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",
|
||||
"version": "4.8.5",
|
||||
"version": "4.9.2",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/tinymce/tinymce.git"
|
||||
|
|
@ -30,7 +30,8 @@
|
|||
"@ephox/robin": "latest",
|
||||
"@ephox/sand": "latest",
|
||||
"@ephox/snooker": "latest",
|
||||
"@ephox/sugar": "latest"
|
||||
"@ephox/sugar": "latest",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@ephox/agar": "latest",
|
||||
|
|
@ -53,12 +54,13 @@
|
|||
"less-plugin-autoprefix": "^1.5.1",
|
||||
"load-grunt-tasks": "^4.0.0",
|
||||
"moxie-zip": "~0.0.3",
|
||||
"tslint": "^5.9.1",
|
||||
"rimraf": "^2.6.2",
|
||||
"string-replace-loader": "^2.1.1",
|
||||
"ts-loader": "^5.3.0",
|
||||
"tslint": "^5.9.1",
|
||||
"typescript": "^3.1.5",
|
||||
"webpack": "^4.8.3",
|
||||
"webpack-dev-server": "^3.1.5",
|
||||
"webpack-livereload-plugin": "^2.1.1",
|
||||
"rimraf": "^2.6.2"
|
||||
"webpack-livereload-plugin": "^2.1.1"
|
||||
}
|
||||
}
|
||||
|
|
@ -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