package CKEDITOR UI configurable Toolbar

References #148

The js and css config files are directly placed in /htmlarea directory. The old ones downunder are not reset with this commit, until we give OK to go.
The lang constant will be placed to addlang.txt in a 2cd commit, since this may change and there is already a pending constant.
I have not added another option by now to explicitly choose the s9y configs in htmlarea, if someone has custom ones in 2k11/admin and wants to switch back to the origins. Is this really a real and valid user case?
This commit is contained in:
Ian 2014-11-17 18:07:54 +01:00
parent f3b2e9fe69
commit 885f064b61
55 changed files with 5895 additions and 16 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

View File

@ -0,0 +1,25 @@
/**
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md or http://ckeditor.com/license
*/
CKEDITOR.dialog.add( 'cheatsheet', function( editor ) {
var lang = "Cheatsheet",
imagePath = CKEDITOR.plugins.get( 'cheatsheet' ).path + 'dialogs/' + ( CKEDITOR.env.hidpi ? 'hidpi/' : '' ) + 'CheatSheetIcon.png';
return {
title: 'shortcuts',
contents: [{
id: 'tab1',
label: '',
title: '',
expand: true,
padding: 0,
elements: [{
type: 'html',
html: '<h1>Keyboard Shortcuts</h1>blahblah'
}]
}],
buttons: [ CKEDITOR.dialog.cancelButton ]
};
} );

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

View File

@ -0,0 +1,77 @@
<div id="cke-cheatsheet">
<h1>Keyboard Shortcuts</h1>
<div id="mw-content-text" dir="ltr" class="mw-content-ltr" lang="en">
<p>Many functions in CKEditor have their equivalent keyboard shortcuts. This is one of the reasons why working with the editor is simple and efficient.</p>
<p>The list below contains available keyboard shortcuts grouped by problem areas.</p>
<h2> <span class="mw-headline" id="Working_with_a_Document"> Working with a Document </span></h2>
<ul>
<li> <i>Esc</i> closes a CKEditor dialog window, drop-down list, or context menu. Also moves from the context menu submenu to the parent option.</li>
<li> <i>Enter</i> selects a CKEditor function from the toolbar, drop-down list, or context menu. Equivalent to the <b>OK</b> button in a dialog window.</li>
<li> <i>Shift+F10</i>, <i>Menu/Application</i> key opens the element's context menu.</li>
</ul>
<h3> <span class="mw-headline" id="Navigation"> Navigation </span></h3>
<ul>
<li> <i>Home</i> jumps to the beginning of the line.</li>
<li> <i>Ctrl+Home</i> jumps to the beginning of the document.</li>
<li> <i>End</i> jumps to the end of the line.</li>
<li> <i>Ctrl+End</i> jumps to the end of the document.</li>
<li> <i>PgDn</i> scrolls down the document, approximately by the length of the editing area. </li>
<li> <i>PgUp</i> scrolls up the document, approximately by the length of the editing area.</li>
</ul>
<h3> <span class="mw-headline" id="Writing"> Writing </span></h3>
<ul>
<li> <i>Enter</i> (<i>Return</i>) ends a paragraph and starts a new one.</li>
<li> <i>Shift+Enter</i> adds a line break.</li>
<li> <i>Backspace</i>, <i>Del</i> deletes a character.</li>
<li> <i>Ctrl+Backspace</i>, <i>Ctrl+Del</i> deletes a word.</li>
</ul>
<h3> <span class="mw-headline" id="Undo_and_Redo"> Undo and Redo </span></h3>
<ul>
<li> <i>Ctrl+Z</i> performs the undo operation.</li>
<li> <i>Ctrl+Y</i> performs the redo operation.</li>
</ul>
<h3> <span class="mw-headline" id="Cut.2C_Copy_and_Paste"> Cut, Copy and Paste </span></h3>
<ul>
<li> <i>Ctrl+X</i>, <i>Shift+Del</i> cuts a text fragment to clipboard.</li>
<li> <i>Ctrl+C</i> copies a text fragment to clipboard.</li>
<li> <i>Ctrl+V</i>, <i>Shift+Insert</i> pastes a text fragment from clipboard.</li>
</ul>
<h3> <span class="mw-headline" id="Text_Selection"> Text Selection </span></h3>
<ul>
<li> <i>Ctrl+A</i> selects all document contents.</li>
<li> <i>Shift+Arrow</i> selects a text fragment by letters.</li>
<li> <i>Ctrl+Shift+Arrow</i> selects a text fragment by words.</li>
<li> <i>Shift+Home</i> selects a text fragment from the cursor to the beginning of the line.</li>
<li> <i>Shift+End</i> selects a text fragment from the cursor to the end of the line.</li>
<li> <i>Ctrl+Shift+Home</i> selects a text fragment from the cursor to the beginning of the document.</li>
<li> <i>Ctrl+Shift+End</i> selects a text fragment from the cursor to the end of the document.</li>
<li> <i>Shift+PgDn</i> selects a text fragment of approximately the length of the editing area starting from the cursor and going down.</li>
<li> <i>Shift+PgUp</i> selects a text fragment of approximately the length of the editing area starting from the cursor and going up.</li>
</ul>
<h2> <span class="mw-headline" id="Text_Styling"> Text Styling </span></h2>
<ul>
<li> <i>Ctrl+B</i> applies <b>bold</b> formatting to a text fragment.</li>
<li> <i>Ctrl+I</i> applies <i>italics</i> formatting to a text fragment.</li>
<li> <i>Ctrl+U</i> applies <ins>underline</ins> formatting to a text fragment.</li>
</ul>
<h2> <span class="mw-headline" id="Rich_Text"> Rich Text </span></h2>
<ul>
<li> <i>Ctrl+L</i> opens the <b>Link</b> dialog window.</li>
</ul>
<h2> <span class="mw-headline" id="Accessibility"> Accessibility </span></h2>
<p>On entering the toolbar you can use the <i>Tab</i> and <i>Shift+Tab</i> shortcuts to navigate between button groups and the <i>Arrow</i> keys to navigate between the buttons <i>within a group</i>.<p>
<ul>
<li> <i>Alt+0</i> opens <b>Help</b>.</li>
<li> <i>Alt+-</i> (<i>minus</i>) collapses and restores the toolbar.</li>
<li> <i>Alt+F10</i> enters the toolbar or the tab list of the currently open dialog window.</li>
<li> <i>Alt+F11</i> enters the elements path.</li>
<li> <i>Tab</i> moves to the next toolbar button group, context menu suboption, elements path element, dialog window element, or dialog window tab while in the tab list.</li>
<li> <i>Right Arrow</i> moves to the next toolbar button within the group, context menu suboption, elements path element, dialog window element, or dialog window tab while in the tab list.</li>
<li> <i>Tab</i> or <i>Down Arrow</i> moves to the next drop-down list or context menu option.</li>
<li> <i>Shift+Tab</i> moves to the previous toolbar button group, context menu parent option, elements path element, dialog window element, or dialog window tab while in the tab list.</li>
<li> <i>Left Arrow</i> moves to the previous toolbar button within the group, context menu parent option, elements path element, dialog window element, or dialog window tab while in the tab list.</li>
<li> <i>Shift+Tab</i> or <i>Up Arrow</i> moves to the previous drop-down list or context menu option.</li>
<li> <i>Space</i> or <i>Enter</i> activates a toolbar button, a context menu option, a drop-down list option, an elements path element, or a dialog window tab once selected. Also enters a context menu submenu, if it is available.</li>
</ul>
<div id="contentfooter">This page was last modified on 11 May 2011, at 14:28.</div>
</div>

Binary file not shown.

After

Width:  |  Height:  |  Size: 511 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 511 B

View File

@ -0,0 +1,188 @@
/**
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md or http://ckeditor.com/license
*/
/**
* @fileOverview A Serendipity CKE-Cheatsheet plugin: cheatsheet, v. 1.2 - 2014-09-02
*/
CKEDITOR.plugins.add( 'cheatsheet', {
icons: 'CheatSheetIcon', // %REMOVE_LINE_CORE%
hidpi: true, // %REMOVE_LINE_CORE%
init: function( editor ) {
var command = editor.addCommand( 'CheatSheet', new CKEDITOR.dialogCommand( 'CheatSheetDialog' ) );
command.modes = { wysiwyg: 1, source: 1 };
command.canUndo = false;
command.readOnly = 1;
editor.ui.addButton && editor.ui.addButton( 'CheatSheet', {
label: 'CKEDITOR Cheat Sheet',
icon : this.path + "icons/CheatSheetIcon.png",
command: 'CheatSheet',
toolbar: 'cheatsheet'
});
CKEDITOR.dialog.add( 'CheatSheetDialog', function( api )
{
// CKEDITOR.dialog.definition
var dialogDefinition =
{
title : 'CKEDITOR Cheat Sheet',
minWidth: 390,
minHeight: 230,
maxWidth: 600,
maxHeight: 400,
contents : [
{
id : 'tab1',
label : 'Cheat Sheet',
title : 'Title',
expand : true,
padding : 0,
elements :
[
{
type : 'html',
html: '<style type="text/css">' +
'#cke-cheatsheet' +
'{' +
'overflow: auto;' +
'width: 600px;' +
'height: 400px;' +
'}' +
'#cke-cheatsheet p' +
'{' +
'font: 13px Arial,Helvetica,Tahoma,Verdana,Sans-Serif;' +
'line-height: 1.6;' +
'margin: 0 0 1em;' +
'white-space: pre-line;' +
'}' +
'#cke-cheatsheet li' +
'{' +
'font: 13px Arial,Helvetica,Tahoma,Verdana,Sans-Serif;' +
'}' +
'#cke-cheatsheet h1, #cke-cheatsheet h2, #cke-cheatsheet h3 {' +
'line-height: 1.05em;' +
'font-weight: bold;' +
'}' +
'#cke-cheatsheet h1 {' +
'font-size: 200%;' +
'margin: 0.55em 0;' +
'}' +
'#cke-cheatsheet h2 {' +
'font-size: 160%;' +
'}' +
'#cke-cheatsheet h3 {' +
'font-size: 140%;' +
'}' +
'#cke-cheatsheet ul' +
'{' +
'list-style: none;' +
'margin: 1em 0px 1em 1.5em;' +
'border: 1px solid #bbb;' +
'background-color: #fefcfc;' +
'padding: 0.5em;' +
'width: 94%;' +
'overflow: auto;' +
'}' +
'#cke-cheatsheet ul li' +
'{' +
'line-height: 2em;' +
'}' +
'#cke-cheatsheet i, #cke-cheatsheet em' +
'{' +
'font: 20px monochrome italic;' +
'}' +
'#contentfooter' +
'{' +
'margin-top: 2em;' +
'font-size:smaller;' +
'}' +
'</style>' +
'<div id="cke-cheatsheet" class="cheatsheet">' +
'<h1>Keyboard Shortcuts</h1>' +
'<div id="mw-content-text" dir="ltr" class="mw-content-ltr" lang="en">' +
'<p>Many functions in CKEditor have their equivalent keyboard shortcuts. This is one of the reasons why working with the editor is simple and efficient.</p>' +
'<p>The list below contains available keyboard shortcuts grouped by problem areas.</p>' +
'<h2> Working with a Document </h2>' +
'<ul>' +
'<li> <em>Esc</em> closes a CKEditor dialog window, drop-down list, or context menu. Also moves from the context menu submenu to the parent option.</li>' +
'<li> <em>Enter</em> selects a CKEditor function from the toolbar, drop-down list, or context menu. Equivalent to the <b>OK</b> button in a dialog window.</li>' +
'<li> <em>Shift+F10</em>, <em>Menu/Application</em> key opens the element\'s context menu.</li>' +
'</ul>' +
'<h3> Navigation </h3>' +
'<ul>' +
'<li> <em>Home</em> jumps to the beginning of the line.</li>' +
'<li> <em>Ctrl+Home</em> jumps to the beginning of the document.</li>' +
'<li> <em>End</em> jumps to the end of the line.</li>' +
'<li> <em>Ctrl+End</em> jumps to the end of the document.</li>' +
'<li> <em>PgDn</em> scrolls down the document, approximately by the length of the editing area. </li>' +
'<li> <em>PgUp</em> scrolls up the document, approximately by the length of the editing area.</li>' +
'</ul>' +
'<h3> Writing </h3>' +
'<ul>' +
'<li> <em>Enter</em> (<em>Return</em>) ends a paragraph and starts a new one.</li>' +
'<li> <em>Shift+Enter</em> adds a line break.</li>' +
'<li> <em>Backspace</em>, <em>Del</em> deletes a character.</li>' +
'<li> <em>Ctrl+Backspace</em>, <em>Ctrl+Del</em> deletes a word.</li>' +
'</ul>' +
'<h3> Undo and Redo </h3>' +
'<ul>' +
'<li> <em>Ctrl+Z</em> performs the undo operation.</li>' +
'<li> <em>Ctrl+Y</em> performs the redo operation.</li>' +
'</ul>' +
'<h3> Cut, Copy and Paste </h3>' +
'<ul>' +
'<li> <em>Ctrl+X</em>, <em>Shift+Del</em> cuts a text fragment to clipboard.</li>' +
'<li> <em>Ctrl+C</em> copies a text fragment to clipboard.</li>' +
'<li> <em>Ctrl+V</em>, <em>Shift+Insert</em> pastes a text fragment from clipboard.</li>' +
'</ul>' +
'<h3> Text Selection </h3>' +
'<ul>' +
'<li> <em>Ctrl+A</em> selects all document contents.</li>' +
'<li> <em>Shift+Arrow</em> selects a text fragment by letters.</li>' +
'<li> <em>Ctrl+Shift+Arrow</em> selects a text fragment by words.</li>' +
'<li> <em>Shift+Home</em> selects a text fragment from the cursor to the beginning of the line.</li>' +
'<li> <em>Shift+End</em> selects a text fragment from the cursor to the end of the line.</li>' +
'<li> <em>Ctrl+Shift+Home</em> selects a text fragment from the cursor to the beginning of the document.</li>' +
'<li> <em>Ctrl+Shift+End</em> selects a text fragment from the cursor to the end of the document.</li>' +
'<li> <em>Shift+PgDn</em> selects a text fragment of approximately the length of the editing area starting from the cursor and going down.</li>' +
'<li> <em>Shift+PgUp</em> selects a text fragment of approximately the length of the editing area starting from the cursor and going up.</li>' +
'</ul>' +
'<h2> Text Styling </h2>' +
'<ul>' +
'<li> <em>Ctrl+B</em> applies <b>bold</b> formatting to a text fragment.</li>' +
'<li> <em>Ctrl+I</em> applies <em>italics</em> formatting to a text fragment.</li>' +
'<li> <em>Ctrl+U</em> applies <ins>underline</ins> formatting to a text fragment.</li>' +
'</ul>' +
'<h2> Rich Text </h2>' +
'<ul>' +
'<li> <em>Ctrl+L</em> opens the <b>Link</b> dialog window.</li>' +
'</ul>' +
'<h2> Accessibility </h2>' +
'<p>On entering the toolbar you can use the <em>Tab</em> and <em>Shift+Tab</em> shortcuts to navigate between button groups and the <em>Arrow</em> keys to navigate between the buttons <em>within a group</em>.<p>' +
'<ul>' +
'<li> <em>Alt+0</em> opens <b>Help</b>.</li>' +
'<li> <em>Alt+-</em> (<em>minus</em>) collapses and restores the toolbar.</li>' +
'<li> <em>Alt+F10</em> enters the toolbar or the tab list of the currently open dialog window.</li>' +
'<li> <em>Alt+F11</em> enters the elements path.</li>' +
'<li> <em>Tab</em> moves to the next toolbar button group, context menu suboption, elements path element, dialog window element, or dialog window tab while in the tab list.</li>' +
'<li> <em>Right Arrow</em> moves to the next toolbar button within the group, context menu suboption, elements path element, dialog window element, or dialog window tab while in the tab list.</li>' +
'<li> <em>Tab</em> or <em>Down Arrow</em> moves to the next drop-down list or context menu option.</li>' +
'<li> <em>Shift+Tab</em> moves to the previous toolbar button group, context menu parent option, elements path element, dialog window element, or dialog window tab while in the tab list.</li>' +
'<li> <em>Left Arrow</em> moves to the previous toolbar button within the group, context menu parent option, elements path element, dialog window element, or dialog window tab while in the tab list.</li>' +
'<li> <em>Shift+Tab</em> or <em>Up Arrow</em> moves to the previous drop-down list or context menu option.</li>' +
'<li> <em>Space</em> or <em>Enter</em> activates a toolbar button, a context menu option, a drop-down list option, an elements path element, or a dialog window tab once selected. Also enters a context menu submenu, if it is available.</li>' +
'</ul>' +
'<div id="contentfooter">This pages content was last modified on 11 May 2011, at 14:28.</div>' +
'</div>'
}]
}],
buttons: [ CKEDITOR.dialog.cancelButton ]
};
return dialogDefinition;
});
}
});

View File

@ -0,0 +1,933 @@
/**
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md or http://ckeditor.com/license
*/
/**
* @fileOverview A set of utilities to find and make horizontal spaces in edited contents.
*/
'use strict';
( function() {
CKEDITOR.plugins.add( 'lineutils' );
/**
* Determines a position relative to an element in DOM (before).
*
* @readonly
* @property {Number} [=0]
* @member CKEDITOR
*/
CKEDITOR.LINEUTILS_BEFORE = 1;
/**
* Determines a position relative to an element in DOM (after).
*
* @readonly
* @property {Number} [=2]
* @member CKEDITOR
*/
CKEDITOR.LINEUTILS_AFTER = 2;
/**
* Determines a position relative to an element in DOM (inside).
*
* @readonly
* @property {Number} [=4]
* @member CKEDITOR
*/
CKEDITOR.LINEUTILS_INSIDE = 4;
/**
* An utility that traverses DOM tree and discovers elements
* (relations) matching user-defined lookups.
*
* @private
* @class CKEDITOR.plugins.lineutils.finder
* @constructor Creates a Finder class instance.
* @param {CKEDITOR.editor} editor Editor instance that Finder belongs to.
* @param {Object} def Finder's definition.
* @since 4.3
*/
function Finder( editor, def ) {
CKEDITOR.tools.extend( this, {
editor: editor,
editable: editor.editable(),
doc: editor.document,
win: editor.window
}, def, true );
this.frame = this.win.getFrame();
this.inline = this.editable.isInline();
this.target = this[ this.inline ? 'editable' : 'doc' ];
}
Finder.prototype = {
/**
* Initializes searching for elements with every mousemove event fired.
* To stop searching use {@link #stop}.
*
* @param {Function} [callback] Function executed on every iteration.
*/
start: function( callback ) {
var that = this,
editor = this.editor,
doc = this.doc,
el, x, y;
var moveBuffer = CKEDITOR.tools.eventsBuffer( 50, function() {
if ( editor.readOnly || editor.mode != 'wysiwyg' )
return;
that.relations = {};
el = new CKEDITOR.dom.element( doc.$.elementFromPoint( x, y ) );
that.traverseSearch( el );
if ( !isNaN( x + y ) )
that.pixelSearch( el, x, y );
callback && callback( that.relations, x, y );
} );
// Searching starting from element from point on mousemove.
this.listener = this.editable.attachListener( this.target, 'mousemove', function( evt ) {
x = evt.data.$.clientX;
y = evt.data.$.clientY;
moveBuffer.input();
} );
this.editable.attachListener( this.inline ? this.editable : this.frame, 'mouseout', function( evt ) {
moveBuffer.reset();
} );
},
/**
* Stops observing mouse events attached by {@link #start}.
*/
stop: function() {
if ( this.listener )
this.listener.removeListener();
},
/**
* Returns a range representing the relation, according to its element
* and type.
*
* @param {Object} location Location containing unique identifier and type.
* @returns {CKEDITOR.dom.range} Range representing the relation.
*/
getRange: ( function() {
var where = {};
where[ CKEDITOR.LINEUTILS_BEFORE ] = CKEDITOR.POSITION_BEFORE_START;
where[ CKEDITOR.LINEUTILS_AFTER ] = CKEDITOR.POSITION_AFTER_END;
where[ CKEDITOR.LINEUTILS_INSIDE ] = CKEDITOR.POSITION_AFTER_START;
return function( location ) {
var range = this.editor.createRange();
range.moveToPosition( this.relations[ location.uid ].element, where[ location.type ] );
return range;
};
} )(),
/**
* Stores given relation in {@link #relations} object. Processes the relation
* to normalize and avoid duplicates.
*
* @param {CKEDITOR.dom.element} el Element of the relation.
* @param {Number} type Relation, one of `CKEDITOR.LINEUTILS_AFTER`, `CKEDITOR.LINEUTILS_BEFORE`, `CKEDITOR.LINEUTILS_INSIDE`.
*/
store: ( function() {
function merge( el, type, relations ) {
var uid = el.getUniqueId();
if ( uid in relations )
relations[ uid ].type |= type;
else
relations[ uid ] = { element: el, type: type };
}
return function( el, type ) {
var alt;
// Normalization to avoid duplicates:
// CKEDITOR.LINEUTILS_AFTER becomes CKEDITOR.LINEUTILS_BEFORE of el.getNext().
if ( is( type, CKEDITOR.LINEUTILS_AFTER ) && isStatic( alt = el.getNext() ) && alt.isVisible() ) {
merge( alt, CKEDITOR.LINEUTILS_BEFORE, this.relations );
type ^= CKEDITOR.LINEUTILS_AFTER;
}
// Normalization to avoid duplicates:
// CKEDITOR.LINEUTILS_INSIDE becomes CKEDITOR.LINEUTILS_BEFORE of el.getFirst().
if ( is( type, CKEDITOR.LINEUTILS_INSIDE ) && isStatic( alt = el.getFirst() ) && alt.isVisible() ) {
merge( alt, CKEDITOR.LINEUTILS_BEFORE, this.relations );
type ^= CKEDITOR.LINEUTILS_INSIDE;
}
merge( el, type, this.relations );
};
} )(),
/**
* Traverses DOM tree towards root, checking all ancestors
* with lookup rules, avoiding duplicates. Stores positive relations
* in {@link #relations} object.
*
* @param {CKEDITOR.dom.element} el Element which is the starting point.
*/
traverseSearch: function( el ) {
var l, type, uid;
// Go down DOM towards root (or limit).
do {
uid = el.$[ 'data-cke-expando' ];
// This element was already visited and checked.
if ( uid && uid in this.relations )
continue;
if ( el.equals( this.editable ) )
return;
if ( isStatic( el ) ) {
// Collect all addresses yielded by lookups for that element.
for ( l in this.lookups ) {
if ( ( type = this.lookups[ l ]( el ) ) )
this.store( el, type );
}
}
} while ( !isLimit( el ) && ( el = el.getParent() ) )
},
/**
* Iterates vertically pixel-by-pixel within given element starting
* from given coordinates, searching for elements in the neighbourhood.
* Once an element is found it is processed by {@link #traverseSearch}.
*
* @param {CKEDITOR.dom.element} el Element which is the starting point.
* @param {Number} [x] Horizontal mouse coordinate relative to the viewport.
* @param {Number} [y] Vertical mouse coordinate relative to the viewport.
*/
pixelSearch: ( function() {
var contains = CKEDITOR.env.ie || CKEDITOR.env.webkit ?
function( el, found ) {
return el.contains( found );
}
:
function( el, found ) {
return !!( el.compareDocumentPosition( found ) & 16 );
};
// Iterates pixel-by-pixel from starting coordinates, moving by defined
// step and getting elementFromPoint in every iteration. Iteration stops when:
// * A valid element is found.
// * Condition function returns false (i.e. reached boundaries of viewport).
// * No element is found (i.e. coordinates out of viewport).
// * Element found is ascendant of starting element.
//
// @param {Object} doc Native DOM document.
// @param {Object} el Native DOM element.
// @param {Number} xStart Horizontal starting coordinate to use.
// @param {Number} yStart Vertical starting coordinate to use.
// @param {Number} step Step of the algorithm.
// @param {Function} condition A condition relative to current vertical coordinate.
function iterate( el, xStart, yStart, step, condition ) {
var y = yStart,
tryouts = 0,
found, uid;
while ( condition( y ) ) {
y += step;
// If we try and we try, and still nothing's found, let's end
// that party.
if ( ++tryouts == 25 )
return;
found = this.doc.$.elementFromPoint( xStart, y );
// Nothing found. This is crazy... but...
// It might be that a line, which is in different document,
// covers that pixel (elementFromPoint is doc-sensitive).
// Better let's have another try.
if ( !found )
continue;
// Still in the same element.
else if ( found == el ) {
tryouts = 0;
continue;
}
// Reached the edge of an element and found an ancestor or...
// A line, that covers that pixel. Better let's have another try.
else if ( !contains( el, found ) )
continue;
tryouts = 0;
// Found a valid element. Stop iterating.
if ( isStatic( ( found = new CKEDITOR.dom.element( found ) ) ) )
return found;
}
}
return function( el, x, y ) {
var paneHeight = this.win.getViewPaneSize().height,
// Try to find an element iterating *up* from the starting point.
neg = iterate.call( this, el.$, x, y, -1, function( y ) {
return y > 0;
} ),
// Try to find an element iterating *down* from the starting point.
pos = iterate.call( this, el.$, x, y, 1, function( y ) {
return y < paneHeight;
} );
if ( neg ) {
this.traverseSearch( neg );
// Iterate towards DOM root until neg is a direct child of el.
while ( !neg.getParent().equals( el ) )
neg = neg.getParent();
}
if ( pos ) {
this.traverseSearch( pos );
// Iterate towards DOM root until pos is a direct child of el.
while ( !pos.getParent().equals( el ) )
pos = pos.getParent();
}
// Iterate forwards starting from neg and backwards from
// pos to harvest all children of el between those elements.
// Stop when neg and pos meet each other or there's none of them.
// TODO (?) reduce number of hops forwards/backwards.
while ( neg || pos ) {
if ( neg )
neg = neg.getNext( isStatic );
if ( !neg || neg.equals( pos ) )
break;
this.traverseSearch( neg );
if ( pos )
pos = pos.getPrevious( isStatic );
if ( !pos || pos.equals( neg ) )
break;
this.traverseSearch( pos );
}
};
} )(),
/**
* Unline {@link #traverseSearch}, it collects **all** elements from editable's DOM tree
* and runs lookups for every one of them, collecting relations.
*
* @returns {Object} {@link #relations}.
*/
greedySearch: function() {
this.relations = {};
var all = this.editable.getElementsByTag( '*' ),
i = 0,
el, type, l;
while ( ( el = all.getItem( i++ ) ) ) {
// Don't consider editable, as it might be inline,
// and i.e. checking it's siblings is pointless.
if ( el.equals( this.editable ) )
continue;
// Don't visit non-editable internals, for example widget's
// guts (above wrapper, below nested). Still check editable limits,
// as they are siblings with editable contents.
if ( !el.hasAttribute( 'contenteditable' ) && el.isReadOnly() )
continue;
if ( isStatic( el ) && el.isVisible() ) {
// Collect all addresses yielded by lookups for that element.
for ( l in this.lookups ) {
if ( ( type = this.lookups[ l ]( el ) ) )
this.store( el, type );
}
}
}
return this.relations;
}
/**
* Relations express elements in DOM that match user-defined {@link #lookups}.
* Every relation has its own `type` that determines whether
* it refers to the space before, after or inside of `element`.
* This object stores relations found by {@link #traverseSearch} or {@link #greedySearch}, structured
* in the following way:
*
* relations: {
* // Unique identifier of the element.
* Number: {
* // Element of this relation.
* element: {@link CKEDITOR.dom.element}
* // Conjunction of CKEDITOR.LINEUTILS_BEFORE, CKEDITOR.LINEUTILS_AFTER and CKEDITOR.LINEUTILS_INSIDE.
* type: Number
* },
* ...
* }
*
* @property {Object} relations
* @readonly
*/
/**
* A set of user-defined functions used by Finder to check if an element
* is a valid relation, belonging to {@link #relations}.
* When the criterion is met, lookup returns a logical conjunction of `CKEDITOR.LINEUTILS_BEFORE`,
* `CKEDITOR.LINEUTILS_AFTER` or `CKEDITOR.LINEUTILS_INSIDE`.
*
* Lookups are passed along with Finder's definition.
*
* lookups: {
* 'some lookup': function( el ) {
* if ( someCondition )
* return CKEDITOR.LINEUTILS_BEFORE;
* },
* ...
* }
*
* @property {Object} lookups
*/
};
/**
* An utility that analyses relations found by
* CKEDITOR.plugins.lineutils.finder and locates them
* in the viewport as horizontal lines of specific coordinates.
*
* @private
* @class CKEDITOR.plugins.lineutils.locator
* @constructor Creates a Locator class instance.
* @param {CKEDITOR.editor} editor Editor instance that Locator belongs to.
* @since 4.3
*/
function Locator( editor, def ) {
CKEDITOR.tools.extend( this, def, {
editor: editor
}, true );
}
Locator.prototype = {
/**
* Localizes Y coordinate for all types of every single relation and stores
* them in the object.
*
* @param {Object} relations {@link CKEDITOR.plugins.lineutils.finder#relations}.
* @returns {Object} {@link #locations}.
*/
locate: ( function() {
var rel, uid;
function locateSibling( rel, type ) {
var sib = rel.element[ type === CKEDITOR.LINEUTILS_BEFORE ? 'getPrevious' : 'getNext' ]();
// Return the middle point between siblings.
if ( sib && isStatic( sib ) ) {
rel.siblingRect = sib.getClientRect();
if ( type == CKEDITOR.LINEUTILS_BEFORE )
return ( rel.siblingRect.bottom + rel.elementRect.top ) / 2;
else
return ( rel.elementRect.bottom + rel.siblingRect.top ) / 2;
}
// If there's no sibling, use the edge of an element.
else {
if ( type == CKEDITOR.LINEUTILS_BEFORE )
return rel.elementRect.top;
else
return rel.elementRect.bottom;
}
}
return function( relations ) {
this.locations = {};
for ( uid in relations ) {
rel = relations[ uid ];
rel.elementRect = rel.element.getClientRect();
if ( is( rel.type, CKEDITOR.LINEUTILS_BEFORE ) )
this.store( uid, CKEDITOR.LINEUTILS_BEFORE, locateSibling( rel, CKEDITOR.LINEUTILS_BEFORE ) );
if ( is( rel.type, CKEDITOR.LINEUTILS_AFTER ) )
this.store( uid, CKEDITOR.LINEUTILS_AFTER, locateSibling( rel, CKEDITOR.LINEUTILS_AFTER ) );
// The middle point of the element.
if ( is( rel.type, CKEDITOR.LINEUTILS_INSIDE ) )
this.store( uid, CKEDITOR.LINEUTILS_INSIDE, ( rel.elementRect.top + rel.elementRect.bottom ) / 2 );
}
return this.locations;
};
} )(),
/**
* Calculates distances from every location to given vertical coordinate
* and sorts locations according to that distance.
*
* @param {Number} y The vertical coordinate used for sorting, used as a reference.
* @param {Number} [howMany] Determines the number "closest locations" to be returned.
* @returns {Array} Sorted, array representation of {@link #locations}.
*/
sort: ( function() {
var locations, sorted,
dist, uid, type, i;
function distance( y ) {
return Math.abs( y - locations[ uid ][ type ] );
}
return function( y, howMany ) {
locations = this.locations;
sorted = [];
for ( uid in locations ) {
for ( type in locations[ uid ] ) {
dist = distance( y );
// An array is empty.
if ( !sorted.length )
sorted.push( { uid: +uid, type: type, dist: dist } );
else {
// Sort the array on fly when it's populated.
for ( i = 0; i < sorted.length; i++ ) {
if ( dist < sorted[ i ].dist ) {
sorted.splice( i, 0, { uid: +uid, type: type, dist: dist } );
break;
}
}
// Nothing was inserted, so the distance is bigger than
// any of already calculated: push to the end.
if ( i == sorted.length )
sorted.push( { uid: +uid, type: type, dist: dist } );
}
}
}
if ( typeof howMany != 'undefined' )
return sorted.slice( 0, howMany );
else
return sorted;
};
} )(),
/**
* Stores the location in a collection.
*
* @param {Number} uid Unique identifier of the relation.
* @param {Number} type One of `CKEDITOR.LINEUTILS_BEFORE`, `CKEDITOR.LINEUTILS_AFTER` and `CKEDITOR.LINEUTILS_INSIDE`.
* @param {Number} y Vertical position of the relation.
*/
store: function( uid, type, y ) {
if ( !this.locations[ uid ] )
this.locations[ uid ] = {};
this.locations[ uid ][ type ] = y;
}
/**
* @readonly
* @property {Object} locations
*/
};
var tipCss = {
display: 'block',
width: '0px',
height: '0px',
'border-color': 'transparent',
'border-style': 'solid',
position: 'absolute',
top: '-6px'
},
lineStyle = {
height: '0px',
'border-top': '1px dashed red',
position: 'absolute',
'z-index': 9999
},
lineTpl =
'<div data-cke-lineutils-line="1" class="cke_reset_all" style="{lineStyle}">' +
'<span style="{tipLeftStyle}">&nbsp;</span>' +
'<span style="{tipRightStyle}">&nbsp;</span>' +
'</div>';
/**
* An utility that draws horizontal lines in DOM according to locations
* returned by CKEDITOR.plugins.lineutils.locator.
*
* @private
* @class CKEDITOR.plugins.lineutils.liner
* @constructor Creates a Liner class instance.
* @param {CKEDITOR.editor} editor Editor instance that Liner belongs to.
* @param {Object} def Liner's definition.
* @since 4.3
*/
function Liner( editor, def ) {
var editable = editor.editable();
CKEDITOR.tools.extend( this, {
editor: editor,
editable: editable,
doc: editor.document,
win: editor.window,
container: CKEDITOR.document.getBody(),
winTop: CKEDITOR.document.getWindow()
}, def, true );
this.hidden = {};
this.visible = {};
this.inline = editable.isInline();
if ( !this.inline )
this.frame = this.win.getFrame();
this.queryViewport();
// Callbacks must be wrapped. Otherwise they're not attached
// to global DOM objects (i.e. topmost window) for every editor
// because they're treated as duplicates. They belong to the
// same prototype shared among Liner instances.
var queryViewport = CKEDITOR.tools.bind( this.queryViewport, this ),
hideVisible = CKEDITOR.tools.bind( this.hideVisible, this ),
removeAll = CKEDITOR.tools.bind( this.removeAll, this );
editable.attachListener( this.winTop, 'resize', queryViewport );
editable.attachListener( this.winTop, 'scroll', queryViewport );
editable.attachListener( this.winTop, 'resize', hideVisible );
editable.attachListener( this.win, 'scroll', hideVisible );
editable.attachListener( this.inline ? editable : this.frame, 'mouseout', function( evt ) {
var x = evt.data.$.clientX,
y = evt.data.$.clientY;
this.queryViewport();
// Check if mouse is out of the element (iframe/editable).
if ( x <= this.rect.left || x >= this.rect.right || y <= this.rect.top || y >= this.rect.bottom )
this.hideVisible();
// Check if mouse is out of the top-window vieport.
if ( x <= 0 || x >= this.winTopPane.width || y <= 0 || y >= this.winTopPane.height )
this.hideVisible();
}, this );
editable.attachListener( editor, 'resize', queryViewport );
editable.attachListener( editor, 'mode', removeAll );
editor.on( 'destroy', removeAll );
this.lineTpl = new CKEDITOR.template( lineTpl ).output( {
lineStyle: CKEDITOR.tools.writeCssText(
CKEDITOR.tools.extend( {}, lineStyle, this.lineStyle, true )
),
tipLeftStyle: CKEDITOR.tools.writeCssText(
CKEDITOR.tools.extend( {}, tipCss, {
left: '0px',
'border-left-color': 'red',
'border-width': '6px 0 6px 6px'
}, this.tipCss, this.tipLeftStyle, true )
),
tipRightStyle: CKEDITOR.tools.writeCssText(
CKEDITOR.tools.extend( {}, tipCss, {
right: '0px',
'border-right-color': 'red',
'border-width': '6px 6px 6px 0'
}, this.tipCss, this.tipRightStyle, true )
)
} );
}
Liner.prototype = {
/**
* Permanently removes all lines (both hidden and visible) from DOM.
*/
removeAll: function() {
var l;
for ( l in this.hidden ) {
this.hidden[ l ].remove();
delete this.hidden[ l ];
}
for ( l in this.visible ) {
this.visible[ l ].remove();
delete this.visible[ l ];
}
},
/**
* Hides a given line.
*
* @param {CKEDITOR.dom.element} line The line to be hidden.
*/
hideLine: function( line ) {
var uid = line.getUniqueId();
line.hide();
this.hidden[ uid ] = line;
delete this.visible[ uid ];
},
/**
* Shows a given line.
*
* @param {CKEDITOR.dom.element} line The line to be shown.
*/
showLine: function( line ) {
var uid = line.getUniqueId();
line.show();
this.visible[ uid ] = line;
delete this.hidden[ uid ];
},
/**
* Hides all visible lines.
*/
hideVisible: function() {
for ( var l in this.visible )
this.hideLine( this.visible[ l ] );
},
/**
* Shows a line at given location.
*
* @param {Object} location Location object containing unique identifier of the relation
* and its type. Usually returned by {@link CKEDITOR.plugins.lineutils.locator#sort}.
* @param {Function} [callback] A callback to be called once the line is shown.
*/
placeLine: function( location, callback ) {
var styles, line, l;
// No style means that line would be out of viewport.
if ( !( styles = this.getStyle( location.uid, location.type ) ) )
return;
// Search for any visible line of a different hash first.
// It's faster to re-position visible line than to show it.
for ( l in this.visible ) {
if ( this.visible[ l ].getCustomData( 'hash' ) !== this.hash ) {
line = this.visible[ l ];
break;
}
}
// Search for any hidden line of a different hash.
if ( !line ) {
for ( l in this.hidden ) {
if ( this.hidden[ l ].getCustomData( 'hash' ) !== this.hash ) {
this.showLine( ( line = this.hidden[ l ] ) );
break;
}
}
}
// If no line available, add the new one.
if ( !line )
this.showLine( ( line = this.addLine() ) );
// Mark the line with current hash.
line.setCustomData( 'hash', this.hash );
// Mark the line as visible.
this.visible[ line.getUniqueId() ] = line;
line.setStyles( styles );
callback && callback( line );
},
/**
* Creates style set to be used by the line, representing a particular
* relation (location).
*
* @param {Number} uid Unique identifier of the relation.
* @param {Number} type Type of the relation.
* @returns {Object} An object containing styles.
*/
getStyle: function( uid, type ) {
var rel = this.relations[ uid ],
loc = this.locations[ uid ][ type ],
styles = {},
hdiff;
// Line should be between two elements.
if ( rel.siblingRect )
styles.width = Math.max( rel.siblingRect.width, rel.elementRect.width );
// Line is relative to a single element.
else
styles.width = rel.elementRect.width;
// Let's calculate the vertical position of the line.
if ( this.inline )
styles.top = loc + this.winTopScroll.y;
else
styles.top = this.rect.top + this.winTopScroll.y + loc;
// Check if line would be vertically out of the viewport.
if ( styles.top - this.winTopScroll.y < this.rect.top || styles.top - this.winTopScroll.y > this.rect.bottom )
return false;
// Now let's calculate the horizontal alignment (left and width).
if ( this.inline )
styles.left = rel.elementRect.left;
else {
if ( rel.elementRect.left > 0 )
styles.left = this.rect.left + rel.elementRect.left;
// H-scroll case. Left edge of element may be out of viewport.
else {
styles.width += rel.elementRect.left;
styles.left = this.rect.left;
}
// H-scroll case. Right edge of element may be out of viewport.
if ( ( hdiff = styles.left + styles.width - ( this.rect.left + this.winPane.width ) ) > 0 )
styles.width -= hdiff;
}
// Finally include horizontal scroll of the global window.
styles.left += this.winTopScroll.x;
// Append 'px' to style values.
for ( var style in styles )
styles[ style ] = CKEDITOR.tools.cssLength( styles[ style ] );
return styles;
},
/**
* Adds a new line to DOM.
*
* @returns {CKEDITOR.dom.element} A brand-new line.
*/
addLine: function() {
var line = CKEDITOR.dom.element.createFromHtml( this.lineTpl );
line.appendTo( this.container );
return line;
},
/**
* Assigns an unique hash to the instance that is later utilized
* to tell unwanted lines from new ones. This method **must** be called
* before a new set of relations is to be visualized so {@link #cleanup}
* eventually hides obsolete lines. This is because lines
* are re-used between {@link #placeLine} calls and the number of
* necessary ones may vary according to the number of relations.
*
* @param {Object} relations {@link CKEDITOR.plugins.lineutils.finder#relations}.
* @param {Object} locations {@link CKEDITOR.plugins.lineutils.locator#locations}.
*/
prepare: function( relations, locations ) {
this.relations = relations;
this.locations = locations;
this.hash = Math.random();
},
/**
* Hides all visible lines that don't belong to current hash
* and no-longer represent relations (locations).
*
* See also: {@link #prepare}.
*/
cleanup: function() {
var line;
for ( var l in this.visible ) {
line = this.visible[ l ];
if ( line.getCustomData( 'hash' ) !== this.hash )
this.hideLine( line );
}
},
/**
* Queries dimensions of the viewport, editable, frame etc.
* that are used for correct positioning of the line.
*/
queryViewport: function() {
this.winPane = this.win.getViewPaneSize();
this.winTopScroll = this.winTop.getScrollPosition();
this.winTopPane = this.winTop.getViewPaneSize();
if ( this.inline )
this.rect = this.editable.getClientRect();
else
this.rect = this.frame.getClientRect();
}
};
function is( type, flag ) {
return type & flag;
}
var floats = { left: 1, right: 1, center: 1 },
positions = { absolute: 1, fixed: 1 };
function isElement( node ) {
return node && node.type == CKEDITOR.NODE_ELEMENT;
}
function isFloated( el ) {
return !!( floats[ el.getComputedStyle( 'float' ) ] || floats[ el.getAttribute( 'align' ) ] );
}
function isPositioned( el ) {
return !!positions[ el.getComputedStyle( 'position' ) ];
}
function isLimit( node ) {
return isElement( node ) && node.getAttribute( 'contenteditable' ) == 'true';
}
function isStatic( node ) {
return isElement( node ) && !isFloated( node ) && !isPositioned( node );
}
/**
* Global namespace holding definitions and global helpers for the lineutils plugin.
*
* @private
* @class
* @singleton
* @since 4.3
*/
CKEDITOR.plugins.lineutils = {
finder: Finder,
locator: Locator,
liner: Liner
};
} )();

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1,169 @@
/**
* @license Copyright (c) from 2013, Author: Ian. All rights reserved.
*/
/**
* @fileOverview A Serendipity wysiwyg-mode-placeholder plugin: procurator, v. 1.4
*/
(function (pluginName) {
var pluginName = 'procurator';
function createFakeElement(editor, realElement, displayName) {
if (!displayName) var displayName = '';
// API createFakeParserElement(realElement, className, realElementType, isResizable) - realElementType can be flash,iframe,and? (these set their own title attribute),
var fakeElement = editor.createFakeParserElement( realElement, 'cke_procurator', 'iframe', false ), fakeStyle = fakeElement.attributes.style || '';
// set the needed [img object] attributes
//fakeElement.attributes[ 'align' ] = 'right'; // '' is default, uncomment to default
fakeElement.attributes[ 'title' ] = 'Serendipity "' + realElement.name + '" tag placeholder';
fakeElement.attributes[ 'alt' ] = realElement.name;
fakeElement.attributes[ 'placeholder' ] = realElement.name;
//fakeElement.attributes[ 'data-cke-real-element-type' ] = "div";
//fakeElement.attributes[ 'contenteditable'] = "false"; // disabled, since CKEDITOR 4.3.2 must have had changed something, that the mediainsert block was replaced by an img procurator/placeholder code
//fakeElement.attributes['src'] = realElement.name+'.png'; // could be used to add an specific element name placeholder, else the /plugins/fakeobjects/images/spacer.gif is used and overruled by addCss
//console.log(fakeElement);
return fakeElement;
}
function thisFakeElement(editor, fakeWrapper, realData, elObject) {
var fakeElement = createFakeElement(editor, fakeWrapper);
fakeElement.attributes['data-cke-realelement'] = realData;
//fakeElement.attributes['data-cke-real-element-type' ] = "div";
if ( fakeElement ) {
delete elObject.value;
return fakeElement;
}
return elObject.value;
}
CKEDITOR.plugins.add( pluginName, {
requires: ['fakeobjects'],
onLoad: function() {
// CHANGES IN CKEDITOR 4
// The "additional CSS" feature provided by CKEDITOR.editor#addCss has moved to a global CKEDITOR.addCss, with specified style rules applies document wide.
// Thus the proper way for a plugin to style it's editable content is to call CKEDITOR.addCss inside of the plugin's onLoad function, rather than it's init function in v3.
// Adds a piece of CSS code to the editor, which will be applied to the WYSIWYG editing document. This CSS would not be added to the output, and is there mainly for editor-specific editing requirements.
// Note: This function should be called before the editor is loaded to take effect.
CKEDITOR.addCss(
'.cke_procurator' +
'{' +
'background-color: #FAFAFA;' +
// 'background-image: url(' + CKEDITOR.getUrl( this.path + 'images/procurator.png' ) + ');' +#a9a9a9
'background-image: url(' + CKEDITOR.tools.transparentImageData + ');' +
'background-position: center center;' +
'background-repeat: no-repeat;' +
'border: 1px solid #000f2d;' +
'border-radius: 0.3em;' +
// 'width: 220px;' +
'height: 37px;' +
'margin: auto 0.5em;' +
'box-shadow: 0px 0px 5px 0px #06F;' +
'z-index: 1;' +
'}'
);
},
init: function (editor) {
// This happens on switch wysiwyg-mode to source view only and is used to remove special wysiwyg changes to the source
editor.on( 'mode', function() {
if ( editor.mode == 'source' ) {
var source = editor.getData();
source = source.replace( /[\t]/g, ' '); // replace ckeditor added tabulators with 4 spaces
source = source.replace( /&amp;quot;/g, '"'); // replace smarty tags quote to " switching wysiwyg to source view
source = source.replace( /&amp;#39;/g, "'"); // replace smarty tags quote to ' switching wysiwyg to source view
//source = source.replace( /\r?\n|\r/gm, ""); // replace all newlines for
// set data back into source mode textarea
editor.setData(source);
}
});
},
afterInit: function (editor) {
// Special script tags work by default, without any changes (commenting out the script to protected replavements) in ckeditor.js file,
// but we can not access (fake and replace with placeholders) these <!--{cke_protected} .* --> comments via the dataFilter rule element.
// This is why we have to fake it by comment dataFilter rule first
// The dataProcessor handles data coming in to the editor and out from the editor.
var dataProcessor = editor.dataProcessor;
// The dataProcessor.dataFilter handles incoming data, like pasting:
// filter applied to the input data when transforming it to HTML to be loaded into the editor ("on input").
// Ckeditor in this state is enabled.
var dataFilter = dataProcessor && dataProcessor.dataFilter;
// The dataProcessor.htmlFilter handles outgoing data, like saving, viewing the source button, or generally calling updateElement on the editor:
// filter applied to the HTML available in the editor when transforming it on the XHTML outputted by the editor ("on output").
// If you have a rule within the htmlFilter that strips out the href attribute, then on save it will be stripped.
// Ckeditor in this state is disabled.
// var htmlFilter = dataProcessor && dataProcessor.htmlFilter;
// var writer = editor.dataProcessor.writer;
// The way to close self closing tags inside add rules, like
// writer.selfClosingEnd = '>';
if (dataFilter) {
// Here we want to add a new filter rule... if the source matches this property, it will be converted
// Note the num at the end, which defines the filter priority. Higher number = higher Priority.
dataFilter.addRules({
// comment reads html comments <!-- (.*) --> and adds fakes to the income-data to be displayed in wysiwyg-mode,
// which was already filtered by ckeditor - see script, noscript (and php?) tags as example
comment : function( elString, elObject ) {
var trimedStr = elString.replace(/^\s\s*/, '').replace(/\s\s*$/, ''); // trim whitespaces at start and end
var cutstr = trimedStr.split(':'); //cut by ':' - match by array
var displayName = 'protected';
var protectedSourceMarker = '{cke_protected}';
// this is case {cke_protected}{C} data
if (cutstr[0].match('quickblog')) {
var realData = '<!--'+trimedStr+'-->'; // return the original snipped to preserve
var fakeWrapper = new CKEDITOR.htmlParser.element( displayName ); // creates the new object
fakeWrapper.name = cutstr[0];
elObject.value = thisFakeElement(editor, fakeWrapper, realData, elObject);
}
// this is case {cke_protected} data
if ( elString.substr( 0, protectedSourceMarker.length ) == protectedSourceMarker ) {
var realData = elString.replace(/\{cke_protected\}([\s\S]+?)/g, "$1"); // cuts the snippet from {cke_protected}(.*) to preserve
// < <? !-- {
var tagName = realData.replace( /([%3C|%3C%3F|\!%2D%2D|%7B]?([a-z]+))%+(.*)$/, "$1"); // get the real tag name to set as real tag name title to object fakeElement.attributes
tagName = tagName.replace( '%3C', '' ).replace( '%3F', '' ); // tweak a little more, since this upper regex drives me crazy
if ( tagName.substr( 0, 3) == '%7B' ) tagName = 'smarty'; // []{
if ( !tagName.match("script|mediainsert|quickblog|audio|smarty") ) tagName = 'unknown';
var fakeWrapper = new CKEDITOR.htmlParser.element( displayName ); // creates the new object
fakeWrapper.name = tagName; // to give this to createFakeElement(), set name value to displayName, else it is the cke_protected script value
elObject.value = thisFakeElement(editor, fakeWrapper, realData, elObject);
}
return elObject.value;
},
// this are real tag elements only
elements: {
/*
'protected': function (element) {
var fake = createFakeElement(editor, element);
if ( element.attributes.src ) {
fake.attributes.alt = element.attributes.src;
fake.attributes["data-cke-realelement"] = fake.attributes["data-cke-realelement"].replace(/%26amp%3B/gi, '%26'); //fix double encoding on ampersands in src
}
return fake;
},*/
}
}, 16); // This is ckeditor priority [1-10] and ACF [11-14], but set to 1 does not conflict here, since we don't hit internal priority rules
// http://docs.ckeditor.com/?_escaped_fragment_=/api/CKEDITOR.editor-event-toDataFormat#!/api/CKEDITOR.editor-event-toDataFormat
// toHtml( evt )
// This event is fired by the CKEDITOR.htmlDataProcessor when input HTML is to be purified by the CKEDITOR.htmlDataProcessor.toHtml method.
// By adding listeners with different priorities it is possible to process input HTML on different stages:
// 1-4: Data is available in the original string format.
// 5: Data is initially filtered with regexp patterns and parsed to CKEDITOR.htmlParser.fragment CKEDITOR.htmlParser.element.
// 5-9: Data is available in the parsed format, but CKEDITOR.htmlDataProcessor.dataFilter is not applied yet.
// 10: Data is filtered with CKEDITOR.htmlDataProcessor.dataFilter.
// 10-14: Data is available in the parsed format and CKEDITOR.htmlDataProcessor.dataFilter has already been applied.
// 15: Data is written back to an HTML string.
// 15-*: Data is available in an HTML string.
// Available since: 4.1
}
}
});
})('procurator');

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 B

View File

@ -0,0 +1,7 @@
/**
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md or http://ckeditor.com/license
*/
CKEDITOR.plugins.setLang( 'widget', 'ar', {
'move': 'Click and drag to move' // MISSING
} );

View File

@ -0,0 +1,7 @@
/**
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md or http://ckeditor.com/license
*/
CKEDITOR.plugins.setLang( 'widget', 'ca', {
'move': 'Clicar i arrossegar per moure'
} );

View File

@ -0,0 +1,7 @@
/**
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md or http://ckeditor.com/license
*/
CKEDITOR.plugins.setLang( 'widget', 'cs', {
'move': 'Klepněte a táhněte pro přesunutí'
} );

View File

@ -0,0 +1,7 @@
/**
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md or http://ckeditor.com/license
*/
CKEDITOR.plugins.setLang( 'widget', 'cy', {
'move': 'Clcio a llusgo i symud'
} );

View File

@ -0,0 +1,7 @@
/**
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md or http://ckeditor.com/license
*/
CKEDITOR.plugins.setLang( 'widget', 'de', {
'move': 'Zum verschieben anwählen und ziehen'
} );

View File

@ -0,0 +1,7 @@
/**
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md or http://ckeditor.com/license
*/
CKEDITOR.plugins.setLang( 'widget', 'el', {
'move': 'Κάνετε κλικ και σύρετε το ποντίκι για να μετακινήστε'
} );

View File

@ -0,0 +1,7 @@
/**
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md or http://ckeditor.com/license
*/
CKEDITOR.plugins.setLang( 'widget', 'en-gb', {
'move': 'Click and drag to move'
} );

View File

@ -0,0 +1,7 @@
/**
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md or http://ckeditor.com/license
*/
CKEDITOR.plugins.setLang( 'widget', 'en', {
'move': 'Click and drag to move'
} );

View File

@ -0,0 +1,7 @@
/**
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md or http://ckeditor.com/license
*/
CKEDITOR.plugins.setLang( 'widget', 'eo', {
'move': 'klaki kaj treni por movi'
} );

View File

@ -0,0 +1,7 @@
/**
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md or http://ckeditor.com/license
*/
CKEDITOR.plugins.setLang( 'widget', 'es', {
'move': 'Dar clic y arrastrar para mover'
} );

View File

@ -0,0 +1,7 @@
/**
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md or http://ckeditor.com/license
*/
CKEDITOR.plugins.setLang( 'widget', 'fa', {
'move': 'کلیک و کشیدن برای جابجایی'
} );

View File

@ -0,0 +1,7 @@
/**
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md or http://ckeditor.com/license
*/
CKEDITOR.plugins.setLang( 'widget', 'fi', {
'move': 'Siirrä klikkaamalla ja raahaamalla'
} );

View File

@ -0,0 +1,7 @@
/**
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md or http://ckeditor.com/license
*/
CKEDITOR.plugins.setLang( 'widget', 'fr', {
'move': 'Cliquer et glisser pour déplacer'
} );

View File

@ -0,0 +1,7 @@
/**
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md or http://ckeditor.com/license
*/
CKEDITOR.plugins.setLang( 'widget', 'gl', {
'move': 'Prema e arrastre para mover'
} );

View File

@ -0,0 +1,7 @@
/**
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md or http://ckeditor.com/license
*/
CKEDITOR.plugins.setLang( 'widget', 'he', {
'move': 'לחץ וגרור להזזה'
} );

View File

@ -0,0 +1,7 @@
/**
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md or http://ckeditor.com/license
*/
CKEDITOR.plugins.setLang( 'widget', 'hr', {
'move': 'Klikni i povuci da pomakneš'
} );

View File

@ -0,0 +1,7 @@
/**
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md or http://ckeditor.com/license
*/
CKEDITOR.plugins.setLang( 'widget', 'hu', {
'move': 'Kattints és húzd a mozgatáshoz'
} );

View File

@ -0,0 +1,7 @@
/**
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md or http://ckeditor.com/license
*/
CKEDITOR.plugins.setLang( 'widget', 'it', {
'move': 'Fare clic e trascinare per spostare'
} );

View File

@ -0,0 +1,7 @@
/**
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md or http://ckeditor.com/license
*/
CKEDITOR.plugins.setLang( 'widget', 'ja', {
'move': 'ドラッグして移動'
} );

View File

@ -0,0 +1,7 @@
/**
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md or http://ckeditor.com/license
*/
CKEDITOR.plugins.setLang( 'widget', 'km', {
'move': 'ចុច​ហើយ​ទាញ​ដើម្បី​ផ្លាស់​ទី'
} );

View File

@ -0,0 +1,7 @@
/**
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md or http://ckeditor.com/license
*/
CKEDITOR.plugins.setLang( 'widget', 'ko', {
'move': '움직이려면 클릭 후 드래그 하세요'
} );

View File

@ -0,0 +1,7 @@
/**
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md or http://ckeditor.com/license
*/
CKEDITOR.plugins.setLang( 'widget', 'nb', {
'move': 'Klikk og dra for å flytte'
} );

View File

@ -0,0 +1,7 @@
/**
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md or http://ckeditor.com/license
*/
CKEDITOR.plugins.setLang( 'widget', 'nl', {
'move': 'Klik en sleep om te verplaatsen'
} );

View File

@ -0,0 +1,7 @@
/**
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md or http://ckeditor.com/license
*/
CKEDITOR.plugins.setLang( 'widget', 'no', {
'move': 'Klikk og dra for å flytte'
} );

View File

@ -0,0 +1,7 @@
/**
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md or http://ckeditor.com/license
*/
CKEDITOR.plugins.setLang( 'widget', 'pl', {
'move': 'Kliknij i przeciągnij, by przenieść.'
} );

View File

@ -0,0 +1,7 @@
/**
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md or http://ckeditor.com/license
*/
CKEDITOR.plugins.setLang( 'widget', 'pt-br', {
'move': 'Click e arraste para mover'
} );

View File

@ -0,0 +1,7 @@
/**
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md or http://ckeditor.com/license
*/
CKEDITOR.plugins.setLang( 'widget', 'pt', {
'move': 'Clique e arraste para mover'
} );

View File

@ -0,0 +1,7 @@
/**
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md or http://ckeditor.com/license
*/
CKEDITOR.plugins.setLang( 'widget', 'ru', {
'move': 'Нажмите и перетащите'
} );

View File

@ -0,0 +1,7 @@
/**
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md or http://ckeditor.com/license
*/
CKEDITOR.plugins.setLang( 'widget', 'sk', {
'move': 'Kliknite a potiahnite pre presunutie'
} );

View File

@ -0,0 +1,7 @@
/**
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md or http://ckeditor.com/license
*/
CKEDITOR.plugins.setLang( 'widget', 'sl', {
'move': 'Kliknite in povlecite, da premaknete'
} );

View File

@ -0,0 +1,7 @@
/**
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md or http://ckeditor.com/license
*/
CKEDITOR.plugins.setLang( 'widget', 'sv', {
'move': 'Klicka och drag för att flytta'
} );

View File

@ -0,0 +1,7 @@
/**
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md or http://ckeditor.com/license
*/
CKEDITOR.plugins.setLang( 'widget', 'tr', {
'move': 'Taşımak için, tıklayın ve sürükleyin'
} );

View File

@ -0,0 +1,7 @@
/**
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md or http://ckeditor.com/license
*/
CKEDITOR.plugins.setLang( 'widget', 'tt', {
'move': 'Күчереп куер өчен басып шудырыгыз'
} );

View File

@ -0,0 +1,7 @@
/**
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md or http://ckeditor.com/license
*/
CKEDITOR.plugins.setLang( 'widget', 'uk', {
'move': 'Клікніть і потягніть для переміщення'
} );

View File

@ -0,0 +1,7 @@
/**
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md or http://ckeditor.com/license
*/
CKEDITOR.plugins.setLang( 'widget', 'vi', {
'move': 'Nhấp chuột và kéo để di chuyển'
} );

View File

@ -0,0 +1,7 @@
/**
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md or http://ckeditor.com/license
*/
CKEDITOR.plugins.setLang( 'widget', 'zh-cn', {
'move': '点击并拖拽以移动'
} );

View File

@ -0,0 +1,7 @@
/**
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md or http://ckeditor.com/license
*/
CKEDITOR.plugins.setLang( 'widget', 'zh', {
'move': '拖曳以移動'
} );

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,272 @@
/**
* @fileOverview The Serendipity CKEDITOR custom config file:
* ckeditor_s9y_config.js, v. 1.7, last modified 2014-11-17 by Ian
*/
/**
* Substitute every config option to CKEDITOR in here,
* rename the file to ckeditor_custom_config.js and
* copy it to /templates/2k11/admin.
* In there change anything to be upgrade independent
* NOTE: Use at own risk! Be careful!
*/
CKEDITOR.editorConfig = function( config ) {
// ACF - Advanced Content Filter works in two modes:
// automatic the filter is configured by editor features (like plugins, buttons, and commands) that are enabled with configuration options
// such as CKEDITOR.config.plugins, CKEDITOR.config.extraPlugins, and CKEDITOR.config.toolbar,
// custom the filter is configured by the CKEDITOR.config.allowedContent option and only features that match this setting are activated.
// In both modes it is possible to extend the filter configuration by using the CKEDITOR.config.extraAllowedContent setting.
// If you want to disable Advanced Content Filter, set CKEDITOR.config.allowedContent to true.
// All available editor features will be activated and input data will not be filtered.
// Allowed content rules. This setting is used when instantiating CKEDITOR.editor.filter.
// The following values are accepted:
// CKEDITOR.filter.allowedContentRules defined rules will be added to the CKEDITOR.editor.filter.
// true will disable the filter (data will not be filtered, all features will be activated).
// default the filter will be configured by loaded features (toolbar items, commands, etc.).
// In all cases filter configuration may be extended by extraAllowedContent. This option may be especially useful,
// when you want to use the default allowedContent value along with some additional rules.
//
// List of regular expressions to be executed on ***input HTML***, indicating HTML source code that, when matched, must not be available in the WYSIWYG mode for editing.
// allow <script> tags
//config.protectedSource.push( /<(script)[^>]*>.*<\/script>/ig ); // set already as default in ckeditor.js, by [/<script[\s\S]*?<\/script>/gi,/<noscript[\s\S]*?<\/noscript>/gi]
// allow S9y imageselectorplus plugin mediainsert tag codes
config.protectedSource.push( /<(mediainsert)[^>]*>[\s\S]*?<\/mediainsert>/img );
// allow a Smarty like {} tag syntax without inner whitespace, which would be some other code part.
config.protectedSource.push( /\{[a-zA-Z\$].*?\}/gi );
// allow wp like [[mytag]] [[{$mytag}]] widget tags
config.protectedSource.push(/\[\[([^\[\]])+\]\]/g);
// CKEDITOR.protectedSource patterns used regex Escape sequences
// \s any whitespace character;
// \S any character that is not a whitespace character
// \t tab (hex 09);
// \r carriage return (hex 0D);
// \n newline (hex 0A);
// Pattern Modifiers
// /i caseless, match both upper and lower case letters
// /m treat as multiline
// /g be greedy
// Set placeholder tag cases - elements [attributes]{styles}(classes) to protect ACF removements.
// Allowed <mediainsert>, <gallery>, <media> tags (imageselectorplus galleries) - which tells ACF to not touch the code!
// Allowed <div> is a need for Media Library inserts - which tells ACF to not touch the code!
// <img[height,width]> This Media Library image is even needed to avoid ACF OFF removement of height attributes.
// <pre[*attributes](*classes)> for previous used prettyprints by ckeditor plugin pbckcode
config.extraAllowedContent = 'mediainsert[*]{*}(*);gallery[*]{*}(*);media[*]{*}(*);script[*]{*}(*);audio[*]{*}(*);div[*]{*}(*);img[height,width];pre[*](*);';
// Prevent filler nodes in all empty blocks. - case switching source and wysiwyg mode multiple times
//config.fillEmptyBlocks = false; // default (true) - switches <p>&nbsp;</p> to <p></p>
//config.ignoreEmptyParagraph = false; // default(true) - Whether the editor must output an empty value ('') if it's contents is made by an empty paragraph only. (Extends to config.fillEmptyBlocks)
// It will still generate an empty <p></p> though.
//config.autoParagraph = false; // defaults(true)
// DEV NOTES: Please note that since CKEditor 4.4.5 the config.autoParagraph configuration option was marked deprecated, since changing the default value might introduce unpredictable usability issues and so it is highly unrecommended.
// The configuration setting that controls the ENTER mode is "config.enterMode" and it offers three options:
// (1) The default creates a paragraph element each time the "enter" key is pressed:
//config.enterMode = CKEDITOR.ENTER_P; // inserts <p></p>
// (2) You can choose to create a "div" element instead of a paragraph:
//config.enterMode = CKEDITOR.ENTER_DIV; // inserts <div></div>
// (3) If you prefer to not wrap the text in anything, you can choose to insert a line break tag:
//config.enterMode = CKEDITOR.ENTER_BR; // inserts <br />
// You can always use SHIFT+ENTER to set a br in the P-mode default option or change the SHIFT-mode to something else
//config.shiftEnterMode = CKEDITOR.ENTER_BR;
// Better learn to do it via keyboard commands, see cheatsheet toolbar button.
// Whether to use HTML entities in the output.
//config.entities = false; // defaults(true)
//config.htmlEncodeOutput = false; // defaults(true)
// UI configurations - just some examples
//config.uiColor = 'transparent'; // standard, but better disable config.uiColor all
//config.uiColor = '#CFD1CF'; // standard grey
//config.uiColor = '#f5f5f5'; // standard light grey
//config.uiColor = '#E6EDF3'; // extreme light blue
//config.uiColor = '#DFE8F6'; // very light blue
//config.uiColor = '#9AB8F3'; // light blue/violet
//config.uiColor = '#AADC6E'; // light green
//config.uiColor = '#FFDC6E'; // light gold
//config.uiColor = '#FF8040'; // mango
//config.uiColor = '#FF2400'; // scarlet red
//config.uiColor = '#14B8C4'; // light turquoise
config.skin = 'moono'; // this is default
config.height = 400; // dito
// Allow certain font sizes, eg.
//config.fontSize_sizes = '8/8px;9/9px;10/10px;11/11px;12/12px;14/14px;15/15px;16/16px;18/18px;20/20px;22/22px;24/24px;26/26px;28/28px;36/36px;48/48px;72/72px' ;
// Allow one(!) default font label, eg.
//config.font_defaultLabel = 'Arial';
// Add other font names to the list of fonts names to be displayed in the Font combo in the toolbar. - eg.
//config.font_names = config.font_names +
// 'Arial/Arial, Helvetica, sans-serif;' +
// 'Times New Roman/Times New Roman, Times, serif;' +
// 'Verdana';
// Add custom Serendipity styles to ckeditor wysiwyg-mode, to repect css image floats
// we can not use templates/yourTemplate/admin/ as a path here, since we would need template and userTemplate path parts as dynamic vars
config.contentsCss = 'htmlarea/wysiwyg-style.css';
// Native spell check functionality is by default disabled in the editor, use disableNativeSpellChecker to enable it:
//config.disableNativeSpellChecker = false;
// Remove custom toolbar buttons and plugins from all toolbars
// A list of plugins that must not be loaded. This setting makes it possible to avoid loading some plugins defined in the CKEDITOR.config.plugins setting, without having to touch it and potentially break it.
config.removePlugins = 'flash,iframe,forms'; // possible strict suggestions: 'flash,iframe,elementspath,save,font,showblocks,div,liststyle,pagebreak,smiley,specialchar,horizontalrule,indentblock,justify,pastefromword,newpage,preview,print,stylescombo'
config.removeButtons = 'Preview,Styles'; // these buttons are useless in Serendipity and therefore not set. Without even the toolbar Groups break better on screens.
// We cheat ckeditor instances by adding all available button names (in s9ypluginbuttons) to "both" toolbar instances, in case of having two textareas.
// The instanciation will only take the ones being currently initiated in wysiwyg_init.tpl output, in the source code.
// The hooked and added extraPlugins in wysiwyg_init become not automatically true for preset toolbars (Basic, Standard, Full) like this, but do for the fallback toolbarGroups later on.
var s9ypluginbuttonsAll = s9ymediabuttons.concat(s9ypluginbuttons);
//console.log('is ckeditor_s9y_config.js');
// in case of toolbar : Basic (keep inser:image, else s9ymediabutton does not work!)
config.toolbar_Basic = [
{ name: 'basicstyles', items : [ 'Bold','Italic','Underline','Superscript' ] },
{ name: 'paragraph', items : [ 'NumberedList', 'BulletedList', 'Blockquote' ] },
{ name: 'styles', items : [ 'Format', ] },
{ name: 's9yml', items : s9ymediabuttons },
{ name: 'insert', items : [ 'Image' ] },
{ name: 'links', items : [ 'Link','Unlink' ] },
{ name: 'document', items : [ 'Source' ] },
{ name: 'codesnippet', items : [ 'CodeSnippet' ] },
{ name: 'mediaembed', items : [ 'MediaEmbed' ] },
{ name: 'others', items : s9ypluginbuttons }
];
// console.log(JSON.stringify(config.toolbar_Basic));
// in case of toolbar : Standard
config.toolbar_Standard = [
{ name: 'basicstyles', items : [ 'Format','-','Bold','Italic','Underline','Strike','Subscript','Superscript','-','RemoveFormat' ] },
{ name: 'clipboard', items : [ 'Cut', 'Copy', 'Paste', 'PasteText', '-', 'Undo', 'Redo'] },
{ name: 'insert', items : [ 'Image', '-', 'Table', 'HorizontalRule', 'SpecialChar'] },
{ name: 'paragraph', groups : [ 'list', 'blocks', 'align' ], items: [ 'NumberedList', 'BulletedList', '-', 'Blockquote' ] },
{ name: 'links', items : [ 'Link','Unlink','Anchor' ] },
{ name: 'editing', groups: [ 'find', 'selection', 'spellchecker' ], items: [ 'Scayt' ] },
{ name: 'codesnippet', items : [ 'CodeSnippet' ] },
{ name: 'mediaembed', items : [ 'MediaEmbed' ] },
{ name: 'others', items : s9ypluginbuttonsAll },
{ name: 'document', groups: [ 'mode', 'document', 'doctools' ], items: [ 'Source' ] },
{ name: 'about', items : [ 'About', ] },
{ name: 'cheatsheet', items : ['CheatSheet'] }
];
// console.log(JSON.stringify(config.toolbar_Standard));
// in case of toolbar : Full (moved 'Source' and removed 'Font','Preview' buttons)
config.toolbar_Full = [
{ name: 'styles', items : [ 'Styles','Format',/*'Font',*/'FontSize' ] },
{ name: 'basicstyles', items : [ 'Bold','Italic','Underline','Strike','Subscript','Superscript','-','RemoveFormat' ] },
{ name: 'clipboard', items : [ 'Cut','Copy','Paste','PasteText','PasteFromWord','-','Undo','Redo' ] },
{ name: 'document', items : [ /*'Source','-',*/'Save','NewPage','DocProps',/*'Preview',*/'Print','-','Templates' ] },
{ name: 'editing', items : [ 'Find','Replace','-','SelectAll','-','SpellChecker', 'Scayt' ] },
{ name: 'forms', items : [ 'Form', 'Checkbox', 'Radio', 'TextField', 'Textarea', 'Select', 'Button', 'ImageButton', 'HiddenField' ] },
{ name: 'paragraph', items : [ 'NumberedList','BulletedList','-','Outdent','Indent','-','Blockquote','CreateDiv','-','JustifyLeft','JustifyCenter','JustifyRight','JustifyBlock','-','BidiLtr','BidiRtl' ] },
{ name: 'links', items : [ 'Link','Unlink','Anchor' ] },
{ name: 'insert', items : [ 'Image','Flash','Table','HorizontalRule','Smiley','SpecialChar','PageBreak' ] },
{ name: 'colors', items : [ 'TextColor','BGColor' ] },
{ name: 'codesnippet', items : [ 'CodeSnippet' ] },
{ name: 'mediaembed', items : [ 'MediaEmbed' ] },
{ name: 'others', items : s9ypluginbuttonsAll },
{ name: 'tools', items : [ 'Maximize', 'ShowBlocks','-','About' ] },
{ name: 'document', groups : [ 'mode', 'document', 'doctools' ], items : [ 'Source' ] },
{ name: 'cheatsheet', items : ['CheatSheet'] }
];
// console.log(JSON.stringify(config.toolbar_Full));
// in case of toolbar : Default S9y
config.toolbar_Default = [
{ name: 'tools', items: [ 'Maximize' ] },
{ name: 'styles', items: [ 'Format' ] },
{ name: 'basicstyles', groups: [ 'basicstyles', 'cleanup' ], items: [ 'Bold', 'Italic', 'RemoveFormat' ] },
{ name: 'paragraph', groups: [ 'list', 'indent', 'blocks', 'align' ], items: [ 'NumberedList', 'BulletedList', '-', 'Outdent', 'Indent', '-', 'Blockquote' ] },
{ name: 'links', items: [ 'Link', 'Unlink', 'Anchor' ] },
{ name: 's9yml', items : s9ymediabuttons },
{ name: 'insert', items: [ 'insert', 'Image', '-', 'Table', 'HorizontalRule', 'SpecialChar' ] },
{ name: 'clipboard', groups: [ 'clipboard', 'undo' ], items: [ 'Cut', 'Copy', 'Paste', 'PasteText', '-', 'Undo', 'Redo' ] },
{ name: 'editing', groups: [ 'find', 'selection', 'spellchecker' ], items: [ 'Scayt' ] },
{ name: 'codesnippet', items : [ 'CodeSnippet' ] },
{ name: 'others', items: s9ypluginbuttons },
{ name: 'document', groups: [ 'mode', 'document', 'doctools' ], items: [ 'Source' ] },
{ name: 'about', items: [ 'About' ] }
];
// console.log(JSON.stringify(config.toolbar_s9y));
// This is the 'CKE PRESET' toolbar select name with CKE 'Default' values, also acting as a fallback in order. Do not touch!
// Note: There is another (internal) fallback toolbar in case of errors, which appearance looks like a re-arranged 4-liner toolbar,
// which will provide the 'others' group, but no additionally added plugins (like mediaembed and cheatsheet).
// This is the official Toolbar configuration generated automatically by the editor, based on config.toolbarGroups.
config.toolbar_CKE = [
{ name: 'document', groups: [ 'mode', 'document', 'doctools' ], items: [ 'Source', '-', 'Save', 'NewPage', /*'Preview', */'Print', '-', 'Templates' ] },
{ name: 'clipboard', groups: [ 'clipboard', 'undo' ], items: [ 'Cut', 'Copy', 'Paste', 'PasteText', 'PasteFromWord', '-', 'Undo', 'Redo' ] },
{ name: 'editing', groups: [ 'find', 'selection', 'spellchecker' ], items: [ 'Find', 'Replace', '-', 'SelectAll', '-', 'Scayt' ] },
{ name: 'forms', items: [ 'Form', 'Checkbox', 'Radio', 'TextField', 'Textarea', 'Select', 'Button', 'ImageButton', 'HiddenField' ] },
'/',
{ name: 'basicstyles', groups: [ 'basicstyles', 'cleanup' ], items: [ 'Bold', 'Italic', 'Underline', 'Strike', 'Subscript', 'Superscript', '-', 'RemoveFormat' ] },
{ name: 'paragraph', groups: [ 'list', 'indent', 'blocks', 'align', 'bidi' ], items: [ 'NumberedList', 'BulletedList', '-', 'Outdent', 'Indent', '-', 'Blockquote', 'CreateDiv', '-', 'JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyBlock', '-', 'BidiLtr', 'BidiRtl', 'Language' ] },
{ name: 'links', items: [ 'Link', 'Unlink', 'Anchor' ] },
{ name: 'insert', items: [ 'Image', 'Flash', 'Table', 'HorizontalRule', 'Smiley', 'SpecialChar', 'PageBreak', 'Iframe' ] },
'/',
{ name: 'styles', items: [ 'Styles', 'Format', 'Font', 'FontSize' ] },
{ name: 'colors', items: [ 'TextColor', 'BGColor' ] },
{ name: 'tools', items: [ 'Maximize', 'ShowBlocks' ] },
{ name: 'others', items : s9ypluginbuttonsAll },
{ name: 'about', items: [ 'About' ] }
];
// This is the official Toolbar groups and order configuration.
/*config.toolbarGroups = [
{ name: 'document', groups: [ 'mode', 'document', 'doctools' ] },
{ name: 'clipboard', groups: [ 'clipboard', 'undo' ] },
{ name: 'editing', groups: [ 'find', 'selection', 'spellchecker' ] },
{ name: 'forms' },
'/',
{ name: 'basicstyles', groups: [ 'basicstyles', 'cleanup' ] },
{ name: 'paragraph', groups: [ 'list', 'indent', 'blocks', 'align', 'bidi' ] },
{ name: 'links' },
{ name: 'insert' },
'/',
{ name: 'styles' },
{ name: 'colors' },
{ name: 'tools' },
{ name: 'others' },
{ name: 'about' }
];*/
// This is the Serendipity tweaked toolbarGroups fallback, which does not need any extras manually filled in 'others', since done automatically by ckeditor.js or by the other named toolbars
config.toolbarGroups = [
{ name: 'styles' },
{ name: 'basicstyles', groups: [ 'basicstyles', 'cleanup' ] },
// { name: 'forms' },
{ name: 'colors' },
{ name: 'paragraph', groups: [ 'list', 'indent', 'blocks', 'align', 'bidi' ] },
{ name: 'links' },
{ name: 's9yml' },
{ name: 'insert' },
// { name: 'ident' },
{ name: 'document', groups: [ /*'mode', */'document', 'doctools' ] },
{ name: 'clipboard', groups: [ 'clipboard', 'undo' ] },
{ name: 'editing', groups: [ 'find', 'selection', 'spellchecker' ] },
{ name: 'snippet', groups: [ 'codesnippet', 'snippet' ] },
{ name: 'mediaembed' },
{ name: 'others' },
{ name: 'tools' },
{ name: 'about' },
{ name: 'mode' },
{ name: 'cheatsheet' }
];
// Adding additional CKEDITOR Plugins to the config
// Download the Plugin, check version matching to this ckeditor version and drop the plugin to /htmlarea/ckeditor/chkeditor/plugins, copy the directories plugin name, eg 'mediaembed'.
// Open your personal /templates/2k11/admin/custom/ckeditor_custom_plugin.js or the default /htmlarea/ckeditor_s9y_plugin.js file
// and add the plugin name to the "extraPlugins" string.
// Now add this name to upper config.toolbarGroup also, wherever you like it to have, eg. "{ name: 'mediaembed' }," if that plugin emits a button to be placed into the toolbar.
// Or as { name: 'pluginname', items: 'PluginName' } eg { name: 'mediaembed', items: 'MediaEmbed' } in one of the upper toolbars, if that plugin emits a button to be placed into the toolbar.
// After a browser reload, the newly added plugin should load into your textareas toolbars.
// PLEASE NOTE:
// Do not use any customized CKEditor Downloads, since this will only work with the CKE PRESET toolbar!
};

View File

@ -0,0 +1,77 @@
/**
* @fileOverview A Serendipity custom CKEDITOR additional plugin creator file:
* ckeditor_s9y_plugin.js, v. 1.4, last modified 2014-11-17, by Ian
* To use a custom plugin.js file, copy this file to templates/2k11/admin and rename it to ckeditor_custom_plugin.js
*/
// init custom button arrays
var s9ypluginbuttons = [];
var s9ymediabuttons = [];
// Init CKEDITOR added plugins
// Seperate by comma, no whitespace allowed, and keep last comma, since later on concatenated with Serendipity hooked plugins, eg MediaLibrary!
// For some CKEDITOR plugin you need the widget plugin, which is added here.
// Plugin Dependencies: widget Add-on Dependencies: Line Utilities and Clipboard
// mediaembed is a fast and simple YouTube code CKEditor-Plugin: v. 0.5+ (https://github.com/frozeman/MediaEmbed, 2013-09-12) to avoid ACF restrictions
// procurator and cheatsheet are S9y only plugins
var customplugins = 'mediaembed,procurator,cheatsheet,';
// for any new instance when it is created - listen on load
CKEDITOR.on('instanceReady', function(evt){
var editor = evt.editor,
rules = {
elements: {
// for serendipity_event_imageselectorplus plugin galleries
mediainsert: function( element ) {
// XHTML output instead of HTML - but this does not react on trailing slash eg <media "blah" />
// editor.dataProcessor.writer.selfClosingEnd = ' />';
// avoid line breaks with special block elements
var tags = ['mediainsert', 'gallery', 'media'];
for (var key in tags) {
editor.dataProcessor.writer.setRules(tags[key],
{
// Indicates that this tag causes indentation on line breaks inside of it.
indent : true,
// Inserts a line break before the element opening tag.
breakBeforeOpen : true,
// Inserts a line break after the element opening tag.
breakAfterOpen : false,
// Inserts a line break before the element closing tag.
breakBeforeClose : true,
// Inserts a line break after the element closing tag.
breakAfterClose : false
});
}
},
// for S9y blog entry MediaLibrary added images
// Output dimensions of w/h images, since we either need an unchanged MediaLibrary image code for responsive templates or tweak some replacements!
img: function( element ) {
var style = element.attributes.style;
if ( style )
{
// Get the height from the style.
var match = /(?:^|\s)height\s*:\s*(\d+)px/i.exec( style );
var height = match && match[1];
if ( height )
{
element.attributes.style = element.attributes.style.replace( /(?:^|\s)height\s*:\s*(\d+)px;?/i , '' );
//element.attributes.height = height;
// Do not add to element attribute height, since then the height will be automatically (re-) added to style again by ckeditor or image js
// The current result is now: img alt class src style{width}. That is the only working state to get arround this issue in a relative simple way!
// Remember: Turning ACF OFF, will leave code alone, but still removes the height="" attribute! (workaround in extraAllowedContent added img[height]!)
}
}
}
}
};
// It's good to set both filters - dataFilter is used when loading data and htmlFilter when retrieving.
editor.dataProcessor.htmlFilter.addRules( rules );
editor.dataProcessor.dataFilter.addRules( rules );
});

View File

@ -0,0 +1,98 @@
/**
* Adds custom Serendipity image float styles to CKEDITOR wysiwyg-mode v.1.0 on 2014-08-28
*/
img { border: 0; -ms-interpolation-mode: bicubic; vertical-align: middle; }
img,
audio, video,
embed, object { max-width: 100%; }
img, video { height: auto; }
.serendipity_image_left,
.serendipity_image_right,
.serendipity_image_center,
.serendipity_imageComment_center,
.serendipity_imageComment_left,
.serendipity_imageComment_right {
background: transparent;
border: 0 none;
padding: 0!important;
}
.serendipity_image_left,
.serendipity_image_right,
.serendipity_imageComment_left,
.serendipity_imageComment_right {
display: block;
float: none;
margin: 0 0 1em;
}
.serendipity_image_center {
display: block;
margin: 0 auto 1em auto;
}
.plain-images .serendipity_image_left,
.plain-images .serendipity_image_right,
.plain-images .serendipity_image_center,
.plain-images .serendipity_imageComment_center,
.plain-images .serendipity_imageComment_left,
.plain-images .serendipity_imageComment_right {
border: 1px solid #aaa;
}
.plain-images .serendipity_imageComment_txt {
background: #ddd;
}
.fancy-images .serendipity_image_left,
.fancy-images .serendipity_image_right,
.fancy-images .serendipity_image_center,
.fancy-images .serendipity_imageComment_img {
-webkit-box-shadow: 0 0 2px 1px rgba(0,0,0,.5);
-moz-box-shadow: 0 0 2px 1px rgba(0,0,0,.5);
box-shadow: 0 0 2px 1px rgba(0,0,0,.5);
}
.no-boxshadow .fancy-images .serendipity_image_left,
.no-boxshadow .fancy-images .serendipity_image_right,
.no-boxshadow .fancy-images .serendipity_image_center,
.no-boxshadow .fancy-images .serendipity_imageComment_img {
border: 1px solid #aaa;
}
.serendipity_imageComment_center,
.serendipity_imageComment_left,
.serendipity_imageComment_right {
height: auto;
max-width: 100%;
}
.serendipity_imageComment_center {
margin: auto !important;
}
.serendipity_image_left {
float: left;
margin: 0 2em 1em 0;
}
.serendipity_image_right {
float: right;
margin: 0 0 1em 2em;
}
.serendipity_imageComment_left {
display: inline;
float: left;
margin: 0 2em 1em 0;
}
.serendipity_imageComment_right {
display: inline;
float: right;
margin: 0 0 1em 2em;
}

View File

@ -1025,6 +1025,18 @@ function serendipity_smarty_init($vars = array()) {
}
}
if (defined('IN_serendipity_admin') && $serendipity['wysiwyg']) {
$wysiwyg_customPlugin = $serendipity['serendipityHTTPPath'] . 'htmlarea/ckeditor_s9y_plugin.js';
$wysiwyg_customConfig = $serendipity['serendipityHTTPPath'] . 'htmlarea/ckeditor_s9y_config.js';
if (file_exists($serendipity['serendipityPath'] . $serendipity['templatePath'] . $serendipity['defaultTemplate'] . '/admin/ckeditor_custom_plugin.js') ) {
$wysiwyg_customPlugin = $serendipity['serendipityHTTPPath'] . $serendipity['templatePath'] . $serendipity['defaultTemplate'] . '/admin/ckeditor_custom_plugin.js';
}
if (file_exists($serendipity['serendipityPath'] . $serendipity['templatePath'] . $serendipity['defaultTemplate'] . '/admin/ckeditor_custom_config.js') ) {
$wysiwyg_customConfig = $serendipity['serendipityHTTPPath'] . $serendipity['templatePath'] . $serendipity['defaultTemplate'] . '/admin/ckeditor_custom_config.js';
}
}
$serendipity['smarty']->assign(
array(
'head_charset' => LANG_CHARSET,
@ -1060,6 +1072,9 @@ function serendipity_smarty_init($vars = array()) {
'category_info' => $category_info,
'template' => $serendipity['template'],
'template_backend' => $serendipity['template_backend'],
'wysiwygToolbar' => $serendipity['wysiwygToolbar'],
'wysiwyg_customPlugin' => $wysiwyg_customPlugin,
'wysiwyg_customConfig' => $wysiwyg_customConfig,
'use_autosave' => (serendipity_db_bool($serendipity['use_autosave']) ? 'true' : 'false'),
'dateRange' => (!empty($serendipity['range']) ? $serendipity['range'] : array())

View File

@ -1,4 +1,4 @@
<?php # $Id$
<?php
# Copyright (c) 2003-2005, Jannis Hermanns (on behalf the Serendipity Developer Team)
# All rights reserved. See LICENSE file for licensing details
@ -77,6 +77,19 @@
'permission' => 'personalConfiguration',
'flags' => array('config')),
array('var' => 'wysiwygToolbar',
'title' => USERCONF_USE_CORE_WYSIWYG_TOOLBAR,
'description' => USERCONF_USE_CORE_WYSIWYG_TOOLBAR_DESC,
'type' => 'list',
'permission' => 'personalConfiguration',
'default' => array(
'Default' => S9Y,
'Basic' => BASIC,
'Standard' => STANDARD,
'Full' => FULL,
'CKE' => CKEPRESET),
'flags' => array('config')),
array('var' => 'mail_comments',
'title' => USERCONF_SENDCOMMENTS,
'description' => USERCONF_SENDCOMMENTS_DESC,

View File

@ -1,26 +1,29 @@
{if $init == false}
<script src="{$serendipityHTTPPath}htmlarea/ckeditor/ckeditor/ckeditor.js"></script>
<script src="{$wysiwyg_customPlugin}"></script>
{/if}
<script>
$('document').ready(function() {
CKEDITOR.plugins.add('s9y_medialibrary{$item}', {
CKEDITOR.plugins.add('s9y_medialibrary_{$item}', {
init: function( editor ) {
editor.addCommand( 'openML', {
exec : function( editor ) {
serendipity.openPopup('serendipity_admin.php?serendipity[adminModule]=media&serendipity[noBanner]=true&serendipity[noSidebar]=true&serendipity[noFooter]=true&serendipity[showMediaToolbar]=false&serendipity[showUpload]=true&serendipity[textarea]={$item}');
}
});
editor.ui.addButton('s9y_medialibrary{$item}', {
editor.ui.addButton('s9y_medialibrary_{$item}', {
label: '{$CONST.MEDIA_LIBRARY}',
command: 'openML',
icon: '{serendipity_getFile file="admin/img/thumbnail.png"}',
toolbar: 'insert'
icon: '{serendipity_getFile file="admin/img/thumbnail.png"}'
});
}
});
s9ymediabuttons.push('s9y_medialibrary_{$item}');
{foreach $buttons as $button}
CKEDITOR.plugins.add('{$button.id}', {
init: function( editor ) {
editor.addCommand( '{$button.name}', {
@ -36,20 +39,24 @@
icon: '{$button.img_url}',
iconName: '{$button.id}_icon'
});
}
});
s9ypluginbuttons.push('{$button.id}');
{/foreach}
ckeitem = '{$item}';
CKEDITOR.replace($('#'+serendipity.escapeBrackets(ckeitem)).get(0), {
customConfig : '{$serendipityHTTPPath}htmlarea/ckeditor/serendipity_config.js',
extraPlugins : 's9y_medialibrary{$item}{foreach $buttons as $button},{$button.id}{/foreach}',
var s9yplugins = customplugins.concat('s9y_medialibrary_{$item}{foreach $buttons as $button},{$button.id}{/foreach}');
CKEDITOR.replace($('#'+serendipity.escapeBrackets('{$item}')).get(0), {
extraPlugins : s9yplugins,
toolbar : '{$wysiwygToolbar}',
customConfig : '{$wysiwyg_customConfig}',
{if $use_autosave == 'true'}
on: {
instanceReady: function( evt ) {
if(Modernizr.indexeddb && {$use_autosave}) {
if(Modernizr.indexeddb) {
CKEDITOR.instances["{$item}"].document.once('keyup', function() {
setInterval(function() {
serendipity.cache("{$item}", CKEDITOR.instances["{$item}"].getData());
@ -58,6 +65,8 @@
}
}
}
{/if}
});
});
</script>
</script>