Fixing some remarks for CKEditor PR#2770

This commit is contained in:
Emanuel Schütze 2016-12-16 21:02:12 +01:00
parent 08cb6a3d1b
commit 82396a784d
7 changed files with 99 additions and 55 deletions

View File

@ -24,6 +24,8 @@ Core:
- Added support for multiple projectors.
- Added an overlay for the current list of speakers.
- Added button to clear the chatbox.
- Switched editor back from TinyMCE to CKEditor which provides a
better copy/paste support from MS Word.
Motions:
- Added origin field.

View File

@ -196,7 +196,7 @@ OpenSlides uses the following projects or parts of them:
* `bootstrap <http://getbootstrap.com>`_, License: MIT
* `bootstrap-ui-datetime-picker <https://github.com/Gillardo/bootstrap-ui-datetime-picker>`_, License: MIT
* `chosen <http://harvesthq.github.io/chosen/>`_, License: MIT
* `ckeditor <http://ckeditor.com>`_, License: For licensing, see LICENSE.md or http://ckeditor.com/license.
* `ckeditor <http://ckeditor.com>`_, License: GPL 2+, LGPL 2.1+ or MPL 1.1.
* `font-awesome-bower <https://github.com/tdg5/font-awesome-bower>`_, License: MIT
* `jquery <https://jquery.com>`_, License: MIT
* `jquery.cookie <https://plugins.jquery.com/cookie>`_, License: MIT
@ -211,8 +211,6 @@ OpenSlides uses the following projects or parts of them:
* `open-sans-fontface <https://github.com/FontFaceKit/open-sans>`_, License: Apache License version 2.0
* `pdfjs-dist <http://mozilla.github.io/pdf.js/>`_, License: Apache-2.0
* `roboto-condensed <https://github.com/davidcunningham/roboto-condensed>`_, License: Apache 2.0
* `tinymce <http://www.tinymce.com>`_, License: LGPL-2.1
* `tinymce-i18n <https://github.com/OpenSlides/tinymce-i18n>`_, License: LGPL-2.1
License and authors

View File

@ -55,30 +55,6 @@
"fonts/Roboto-Condensed/Roboto-Condensed-Regular.woff",
"fonts/Roboto-Condensed/Roboto-Condensed-Light.woff"
]
},
"ckeditor": {
"main": [
"ckeditor.js",
"skins/moono-lisa/*",
"lang/en.js",
"lang/de.js",
"lang/pt.js",
"lang/es.js",
"lang/fr.js",
"lang/cs.js",
"plugins/about/*",
"plugins/clipboard/*",
"plugins/dialog/*",
"plugins/find/*",
"plugins/image/*",
"plugins/justify/*",
"plugins/liststyle/*",
"plugins/magicline/*",
"plugins/pastefromword/*",
"plugins/showblocks/*",
"plugins/table/*",
"plugins/tabletools/*"
]
}
},
"resolutions": {

View File

@ -108,12 +108,59 @@ gulp.task('angular-chosen-img', function () {
.pipe(gulp.dest(path.join(output_directory, 'css')));
});
// Extra task only for CKEditor
gulp.task('ckeditor', function () {
return gulp.src(path.join('bower_components', 'ckeditor', '**'))
// CKEditor defaults
gulp.task('ckeditor-defaults', function () {
return gulp.src([
path.join('bower_components', 'ckeditor', 'styles.js'),
path.join('bower_components', 'ckeditor', 'contents.css'),
])
.pipe(gulp.dest(path.join(output_directory, 'ckeditor')));
});
// CKEditor skins
gulp.task('ckeditor-skins', function () {
return gulp.src([
path.join('bower_components', 'ckeditor', 'skins', 'moono-lisa', '**', '*'),
],{ base: path.join('bower_components', 'ckeditor', 'skins') })
.pipe(gulp.dest(path.join(output_directory, 'ckeditor', 'skins')));
});
// CKEditor plugins
gulp.task('ckeditor-plugins', function () {
return gulp.src([
path.join('bower_components', 'ckeditor', 'plugins', 'clipboard', '**', '*'),
path.join('bower_components', 'ckeditor', 'plugins', 'colorbutton', '**', '*'),
path.join('bower_components', 'ckeditor', 'plugins', 'dialog', '**', '*'),
path.join('bower_components', 'ckeditor', 'plugins', 'find', '**', '*'),
path.join('bower_components', 'ckeditor', 'plugins', 'image', '**', '*'),
path.join('bower_components', 'ckeditor', 'plugins', 'justify', '**', '*'),
path.join('bower_components', 'ckeditor', 'plugins', 'liststyle', '**', '*'),
path.join('bower_components', 'ckeditor', 'plugins', 'magicline', '**', '*'),
path.join('bower_components', 'ckeditor', 'plugins', 'pastefromword', '**', '*'),
path.join('bower_components', 'ckeditor', 'plugins', 'panelbutton', '**', '*'),
path.join('bower_components', 'ckeditor', 'plugins', 'showblocks', '**', '*'),
path.join('bower_components', 'ckeditor', 'plugins', 'sourcedialog', '**', '*'),
path.join('bower_components', 'ckeditor', 'plugins', 'table', '**', '*'),
path.join('bower_components', 'ckeditor', 'plugins', 'tabeltools', '**', '*'),
],{ base: path.join('bower_components', 'ckeditor', 'plugins') })
.pipe(gulp.dest(path.join(output_directory, 'ckeditor', 'plugins')));
});
// CKEditor languages
gulp.task('ckeditor-lang', function () {
return gulp.src([
path.join('bower_components', 'ckeditor', 'lang', 'en.js'),
path.join('bower_components', 'ckeditor', 'lang', 'de.js'),
path.join('bower_components', 'ckeditor', 'lang', 'pt.js'),
path.join('bower_components', 'ckeditor', 'lang', 'es.js'),
path.join('bower_components', 'ckeditor', 'lang', 'fr.js'),
path.join('bower_components', 'ckeditor', 'lang', 'cs.js'),
])
.pipe(gulp.dest(path.join(output_directory, 'ckeditor', 'lang')));
});
// Combines all CKEditor related tasks.
gulp.task('ckeditor', ['ckeditor-defaults', 'ckeditor-skins', 'ckeditor-plugins', 'ckeditor-lang'], function () {});
// Compiles translation files (*.po) to *.json and saves them in the directory
// openslides/static/i18n/.
@ -126,7 +173,16 @@ gulp.task('translations', function () {
});
// Gulp default task. Runs all other tasks before.
gulp.task('default', ['js', 'js-libs', 'templates', 'css-libs', 'fonts-libs', 'ckeditor', 'angular-chosen-img', 'translations'], function () {});
gulp.task('default', [
'js',
'js-libs',
'templates',
'css-libs',
'fonts-libs',
'ckeditor',
'angular-chosen-img',
'translations'
], function () {});
/**

View File

@ -548,18 +548,29 @@ angular.module('OpenSlidesApp.core', [
}
])
// Configs for CKEditor which has to set while startup of OpenSlides
.config(
function() {
CKEDITOR.disableAutoInline = true;
}
)
// Options for CKEditor used in various create and edit views.
// Required in core/base.js because MotionComment factory which used this
// factory has to placed in motions/base.js.
.factory('Editor', [
'gettextCatalog',
function(gettextCatalog) {
function (gettextCatalog) {
return {
getOptions: function (images) {
return {
on: {
instanceReady: function() {
// add a listener to ckeditor that parses the clipboard content and, after the regular filter,
// additionally strips out all empty <p> paragraphs
// TODO: check all kind of clipboard html content if "isEmpty" is a reliable property
// This adds a listener to ckeditor to remove unwanted blank lines on import.
// Clipboard content varies heavily in structure and html code, depending on the "sender".
// Here it is first parsed into a pseudo-DOM (two lines taken from a ckeditor
// paste example on the ckeditor site).
this.on('paste', function(evt) {
if (evt.data.type == 'html') {
var fragment = CKEDITOR.htmlParser.fragment.fromHtml(evt.data.dataValue);
@ -567,31 +578,37 @@ angular.module('OpenSlidesApp.core', [
// html content will now be in a dom-like structure inside 'fragment'.
this.filter.applyTo(fragment);
if (fragment.children) {
// If this fragment is DOM-like, it may contain nested properties
// (being html nodes). Traverse the children and check if it is a
// child only containing empty <br> or <p>.
// new_content_children will finally contain all nodes that are
// not empty.
var new_content_children = [];
for (var i = 0; i < fragment.children.length; i++) {
_.forEach(fragment.children, function (child) {
var empty = true;
if (fragment.children[i].children){
for (var j = 0; j < fragment.children[i].children.length; j++) {
var child = fragment.children[i].children[j];
if (child.name != 'p' && child.name != 'br') {
if (child.children){
_.forEach(child.children, function(grandchild) {
if (grandchild.name != 'p' && grandchild.name != 'br') {
empty = false;
} else if (child.isEmpty !== true) {
} else if (grandchild.isEmpty !== true) {
empty = false;
}
}
});
if (empty === false) {
new_content_children.push(fragment.children[i]);
new_content_children.push(child);
}
} else {
if (fragment.children[i].name != 'p' && fragment.children[i].name != 'br' &&
fragment.children[i].isEmpty !== true){
new_content_children.push(fragment.children[i]);
}
if (child.name != 'p' && child.name != 'br' &&
child.isEmpty !== true){
new_content_children.push(child);
}
}
});
fragment.children = new_content_children;
}
fragment.writeHtml(writer);
// Return the re-created fragment without the empty <p> and <br> into the
// editor import processing (same as at the begin of the function: by ckeditor)
evt.data.dataValue = writer.getHtml();
}
});

View File

@ -10,19 +10,14 @@
<link rel="stylesheet" href="static/css/openslides-libs.css">
<link rel="stylesheet" href="static/css/app.css">
<link rel="icon" href="/static/img/favicon.png">
<!-- TODO: there is probably a better place for it:-->
<!-- TODO (#2787): move into openslides-libs-->
<script>
window.CKEDITOR_BASEPATH = '/static/ckeditor/';
</script>
<!-- -->
<script src="static/js/openslides-libs.js"></script>
<script src="static/js/openslides.js"></script>
<script src="static/js/openslides-templates.js"></script>
<!-- TODO: move inside openslides-libs (?):-->
<script>
CKEDITOR.disableAutoInline = true;
</script>
<!-- -->
<div id="wrapper" ng-cloak>
<!-- Header -->

View File

@ -82,7 +82,7 @@ angular.module('OpenSlidesApp.motions.lineNumbering', [])
node.setAttribute('class', 'os-line-number line-number-' + lineNumber);
node.setAttribute('data-line-number', lineNumber + '');
node.setAttribute('contenteditable', 'false');
node.innerHTML = '&nbsp;'; // Prevent tinymce from stripping out empty span's
node.innerHTML = '&nbsp;'; // Prevent ckeditor from stripping out empty span's
return node;
};