Skip to content
This repository has been archived by the owner on Jun 26, 2020. It is now read-only.

Commit

Permalink
Merge pull request #13 from ckeditor/i/5802
Browse files Browse the repository at this point in the history
Feature: Allow pasting content into exception areas in the restricted editing mode. Closes ckeditor/ckeditor5#5802.
  • Loading branch information
Reinmar authored Jan 3, 2020
2 parents 612a2be + e99b73e commit 6704d21
Show file tree
Hide file tree
Showing 4 changed files with 293 additions and 66 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@
},
"devDependencies": {
"@ckeditor/ckeditor5-basic-styles": "^16.0.0",
"@ckeditor/ckeditor5-block-quote": "^16.0.0",
"@ckeditor/ckeditor5-clipboard": "^16.0.0",
"@ckeditor/ckeditor5-editor-classic": "^16.0.0",
"@ckeditor/ckeditor5-engine": "^16.0.0",
"@ckeditor/ckeditor5-link": "^16.0.0",
"@ckeditor/ckeditor5-paragraph": "^16.0.0",
"@ckeditor/ckeditor5-table": "^16.0.0",
"@ckeditor/ckeditor5-typing": "^16.0.0",
Expand Down
15 changes: 14 additions & 1 deletion src/restrictededitingmode.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ export default class RestrictedEditingMode extends Plugin {
* ClassicEditor
* .create( {
* restrictedEditing: {
* allowedCommands: [ 'bold', 'italic' ]
* allowedCommands: [ 'bold', 'link', 'unlink' ],
* allowedAttributes: [ 'bold', 'linkHref' ]
* }
* } )
* .then( ... )
Expand All @@ -83,3 +84,15 @@ export default class RestrictedEditingMode extends Plugin {
*
* @member {Array.<String>} module:restricted-editing/restrictededitingmode~RestrictedEditingModeConfig#allowedCommands
*/

/**
* The text attribute names allowed when pasting content ot non-restricted areas.
*
* The default value is:
*
* const restrictedEditingConfig = {
* allowedAttributes: [ 'bold', 'italic', 'linkHref' ]
* };
*
* @member {Array.<String>} module:restricted-editing/restrictededitingmode~RestrictedEditingModeConfig#allowedAttributes
*/
65 changes: 48 additions & 17 deletions src/restrictededitingmodeediting.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ export default class RestrictedEditingModeEditing extends Plugin {
super( editor );

editor.config.define( 'restrictedEditing', {
allowedCommands: [ 'bold', 'italic', 'link', 'unlink' ]
allowedCommands: [ 'bold', 'italic', 'link', 'unlink' ],
allowedAttributes: [ 'bold', 'italic', 'linkHref' ]
} );

/**
Expand Down Expand Up @@ -69,7 +70,7 @@ export default class RestrictedEditingModeEditing extends Plugin {
*/
init() {
const editor = this.editor;

const editingView = editor.editing.view;
const allowedCommands = editor.config.get( 'restrictedEditing.allowedCommands' );

allowedCommands.forEach( commandName => this._allowedInException.add( commandName ) );
Expand All @@ -84,18 +85,8 @@ export default class RestrictedEditingModeEditing extends Plugin {
editor.keystrokes.set( 'Tab', getCommandExecuter( editor, 'goToNextRestrictedEditingException' ) );
editor.keystrokes.set( 'Shift+Tab', getCommandExecuter( editor, 'goToPreviousRestrictedEditingException' ) );

// Block clipboard completely in restricted mode.
this.listenTo( this.editor.editing.view.document, 'clipboardInput', evt => {
evt.stop();
}, { priority: 'highest' } );
this.listenTo( this.editor.editing.view.document, 'clipboardOutput', ( evt, data ) => {
if ( data.method == 'cut' ) {
evt.stop();
}
}, { priority: 'highest' } );

editor.editing.view.change( writer => {
for ( const root of editor.editing.view.document.roots ) {
editingView.change( writer => {
for ( const root of editingView.document.roots ) {
writer.addClass( 'ck-restricted-editing_mode_restricted', root );
}
} );
Expand Down Expand Up @@ -174,22 +165,48 @@ export default class RestrictedEditingModeEditing extends Plugin {
}

/**
* Setups additional editing restrictions beyond command toggling.
* Setups additional editing restrictions beyond command toggling:
*
* * delete content range trimming
* * disabling input command outside exception marker
* * restricting clipboard holder to text only
* * restricting text attributes in content
*
* @private
*/
_setupRestrictions() {
const editor = this.editor;
const model = editor.model;
const selection = model.document.selection;
const viewDoc = editor.editing.view.document;

this.listenTo( editor.model, 'deleteContent', restrictDeleteContent( editor ), { priority: 'high' } );
this.listenTo( model, 'deleteContent', restrictDeleteContent( editor ), { priority: 'high' } );

const inputCommand = this.editor.commands.get( 'input' );
const inputCommand = editor.commands.get( 'input' );

// The restricted editing might be configured without input support - ie allow only bolding or removing text.
// This check is bit synthetic since only tests are used this way.
if ( inputCommand ) {
this.listenTo( inputCommand, 'execute', disallowInputExecForWrongRange( editor ), { priority: 'high' } );
}

// Block clipboard outside exception marker on paste.
this.listenTo( viewDoc, 'clipboardInput', function( evt ) {
if ( !isRangeInsideSingleMarker( editor, selection.getFirstRange() ) ) {
evt.stop();
}
}, { priority: 'high' } );

// Block clipboard outside exception marker on cut.
this.listenTo( viewDoc, 'clipboardOutput', ( evt, data ) => {
if ( data.method == 'cut' && !isRangeInsideSingleMarker( editor, selection.getFirstRange() ) ) {
evt.stop();
}
}, { priority: 'high' } );

const allowedAttributes = editor.config.get( 'restrictedEditing.allowedAttributes' );
model.schema.addAttributeCheck( onlyAllowAttributesFromList( allowedAttributes ) );
model.schema.addChildCheck( allowTextOnlyInClipboardHolder );
}

/**
Expand Down Expand Up @@ -406,3 +423,17 @@ function ensureNewMarkerIsFlat( editor ) {
}
};
}

function onlyAllowAttributesFromList( allowedAttributes ) {
return ( context, attributeName ) => {
if ( context.startsWith( '$clipboardHolder' ) ) {
return allowedAttributes.includes( attributeName );
}
};
}

function allowTextOnlyInClipboardHolder( context, childDefinition ) {
if ( context.startsWith( '$clipboardHolder' ) ) {
return childDefinition.name === '$text';
}
}
Loading

0 comments on commit 6704d21

Please sign in to comment.