How do i limit my own element to contain only plain text? - javascript

How do I create a block element, which can only contain plain text? (No bold, italic and so on).
I have registered my element as:
model.schema.register(mtHeaderLine, {
// Changing inheritAllFrom to '$block' creates an editable element
// but then it can contain bold text.
inheritAllFrom: '$text',
allowIn: mtHeaderDiv,
isBlock: true
});
And then I downcast with:
editor.conversion.for('downcast').add(downcastElementToElement( { model: mtHeaderLine, view: 'div' }
But that creates an element which I can't edit.
I also tried to downcast with:
view: (modelElement, viewWriter ) => {
const viewElement=viewWriter.createEditableElement('div',{ 'class': (mtHeaderLine) ,isghost: isGhost });
return viewElement;
}
But that did not give me an editable element either.

You need to use Schema#addAttributeCheck(). That method allows you to register a callback which will disallow all attributes on $text which is in some context (e.g. a child of a model <plaintext> element):
function MyPlugin( editor ) {
editor.model.schema.register( 'plaintext', {
inheritAllFrom: '$block'
} );
editor.model.schema.addAttributeCheck( ( ctx, attrName ) => {
if ( ctx.endsWith( 'plaintext $text' ) ) {
return false;
}
} );
editor.conversion.elementToElement( {
model: 'plaintext',
view: 'div'
} );
}
ClassicEditor
.create( document.getElementById( 'editor' ), {
plugins: [ ...ClassicEditor.builtinPlugins, MyPlugin ]
} )
.then( editor => {
window.editor = editor;
} )
.catch( error => {
console.error( error );
} );
DEMO: https://jsfiddle.net/rvas7pLn/1/

Related

Error returning value when editing message

I've been thinking about how to do this for days and if you could help me.
I expose you, I have followed the CKEditor 5 tutorial to the point of including the mentions, this is where my problem begins.
Following the tutorial we come to the part of the output of the mention, this as they do in the tutorial I have transformed it from <span> to <a> together with its class, its URL and its data. Well the editor shows it fine until you want to edit the post.
That is, imagine this message:
Hello world I am the first code of #undercover
Well when I include it in the database everything is correct, but when we return that same message to the editor it becomes:
Hello world I am the first code of #undercover
Investigating and as my Javascript is quite low I have been trying things.
The conversion. I've tried but there is something I can't understand and it's like passing the values ​​to the function. Let me explain, when I pass that <a> that I save in the database, if I transform it into a <span> and then insert it if it tries to make the change to mention but the class attribute and the href attribute are "orphaned".
Well, I have 3 ideas and I can't do any of them at some point I get stuck, so I ask you for help.
My idea is to return the text I have in the database and the editor reads it fine.
Idea 1: Put the text in Javascript and identify and exchange the mentions that are in the database by the function of the mentions command, this is really complicated for me because it is very abstract, even so I am still looking for how to do it.
Idea 2: Save the value in the database in another way, this has been a last idea, how to search and put the of the mention but with the custom values. Even if {mention: {id: #undercover}} were saved in the database, I wouldn't care as long as it was later transformed correctly in the editor.
Idea 3: The use of conversions, I have managed to understand this and it has cost me that its function is to identify the mention within the editor and exchange it for the data you want. In this idea I can't understand how to pass the values ​​other than manually, that is, how to pass the class and href attributes.
Here I leave you the section of the code, I hope you can give me a hand and thank you very much.
function MentionCustomization( editor ) {
// The upcast converter will convert <a class="mention" href="" data-user-id="">
// elements to the model 'mention' attribute.
editor.conversion.for( 'upcast' ).elementToAttribute( {
view: {
name: 'a',
key: 'data-mention',
classes: 'mention',
attributes: {
href: true,
'data-user-id': true,
}
},
model: {
key: 'mention',
value: viewItem => {
// The mention feature expects that the mention attribute value
// in the model is a plain object with a set of additional attributes.
// In order to create a proper object, use the toMentionAttribute helper method:
const mentionAttribute = editor.plugins.get( 'Mention' ).toMentionAttribute( viewItem, {
// Add any other properties that you need.
link: viewItem.getAttribute( 'href' ),
userId: viewItem.getAttribute( 'data-user-id' )
} );
return mentionAttribute;
}
},
converterPriority: 'high'
} );
// Downcast the model 'mention' text attribute to a view <a> element.
editor.conversion.for( 'downcast' ).attributeToElement( {
model: 'mention',
view: ( modelAttributeValue, { writer } ) => {
// Do not convert empty attributes (lack of value means no mention).
if ( !modelAttributeValue ) {
return;
}
return writer.createAttributeElement( 'a', {
class: 'group-color-'+modelAttributeValue.group,
'data-mention': modelAttributeValue.id,
// 'data-user-id': modelAttributeValue.userId,
'href': '/member/profile/'+modelAttributeValue.user_id,
}, {
// Make mention attribute to be wrapped by other attribute elements.
priority: 20,
// Prevent merging mentions together.
id: modelAttributeValue.uid,
} );
},
converterPriority: 'high'
} );
}
$.ajax({
type: "POST",
dataType: "json",
url: "/members/list_json",
success: function(info){
ClassicEditor
.create( document.querySelector( '#comment' ), {
extraPlugins: [ MentionCustomization ],
updateSourceElementOnDestroy: true,
language: 'es',
toolbar: [ 'bold', 'italic', '|' , 'link', '|', 'bulletedList'],
mention: {
feeds: [
{
marker: '#',
feed: getFeedItems,
minimumCharacters: 2,
itemRenderer: customItemRenderer,
}
]
}
} )
.then( editor => {
window.editor = editor;
/*
*/
} )
.catch( err => {
console.error( err.stack );
} );
let list_members = [];
for(let i = 0; i < info.length; i++){
var member = info[i];
list_members.push(member);
}
function getFeedItems( queryText ) {
return new Promise( resolve => {
setTimeout( () => {
const itemsToDisplay = list_members
.filter( isItemMatching )
.slice( 0, 10 );
resolve( itemsToDisplay );
}, 100 );
} );
function isItemMatching( item ) {
const searchString = queryText.toLowerCase();
return (
item.username.toLowerCase().includes( searchString )
);
}
}
},
});
function customItemRenderer( item ) {
const itemElement = document.createElement( 'span' );
const avatar = document.createElement( 'img' );
const userNameElement = document.createElement( 'span' );
itemElement.classList.add( 'mention__item');
avatar.src = `${ item.avatar }`;
avatar.classList.add('image-fluid', 'img-thumbnail', 'rounded-circle');
userNameElement.classList.add( 'mention__item__user-name' );
userNameElement.style.cssText = 'color: '+ item.group_color +';';
userNameElement.textContent = item.id;
itemElement.appendChild( avatar );
itemElement.appendChild( userNameElement );
return itemElement;
}

How can i check whether an element can host Shadow DOM?

Elements that allow Shadow DOM are specified here:
https://docs.w3cub.com/dom/element/attachshadow/
How can i validate if an element supports Shadow DOM or not ?
if (myElement.attachShadow) {
...
}
does not seem to work.
You could try and catch if unsupported.
try {
let shadowRoot = elem.attachShadow( { mode: "open" } );
shadowRoot.innerHTML = ...;
return true;
} catch( err ) {
return false;
}
You could also turn this into a helper, but if you need to use it several times, it might then be a good idea to store the results after checking each element.
function canAttachShadow( elem ) {
try {
elem.cloneNode().attachShadow( { mode: "open" } );
return true;
}
catch( err ) {
return false;
}
}
console.log( "a", canAttachShadow( document.createElement( "a" ) ) );
console.log( "article", canAttachShadow( document.createElement( "article" ) ) );
If you really wish, you could also use the specs algorithm, which is a combination of
valid-custom-element-name and
the white list in your article (i.e today, "article", "aside",
"blockquote", "body", "div", "footer", "h1", "h2", "h3", "h4", "h5", "h6", "header", "main", "nav", "p", "section", or
"span"), however this white list may change in the future, so any code using it would need to get updated along with
the specs.
You can try do it like this:
if (document.myElement.createShadowRoot || document.myElement.attachShadow) {
// support shadow DOM
} else {
// not support
}

Cannot get instance of CKEditor

I have several fields which need to be initialized with CKEditor, for this I have created an helper class that contains the initEditor method.
The method below should return the initialized editor but it doesn't:
window.CKEditorHelper = window.CKEditorHelper || {};
(function (exports) {
exports.initEditor = function (input, myEditor) {
ClassicEditor
.create(document.querySelector(input), {
language: {
ui: 'en'
content: 'en'
}
})
.then(editor => {
myEditor = editor;
});
};
})(window.CKEditorHelper);
this is called in the following way:
let editor = null;
CKEditorHelper.initEditor('#description', editor);
so when I click on a button:
$('#save').on('click', function(){
console.log(editor.getData());
});
I get:
Cannot read property 'getData' of null
what I did wrong?
There are some issues on your code
let editor = null;
the let keyword only define a variable within function scope, when you use editor on another scope (your click handle event), it could be undefined
Another line
myEditor = editor;
This just simple made the reference to your original editor object will gone
Here is my solution to fix it
Change the way you init an editor like bellow
window.editorInstance = {editor: null};
CKEditorHelper.initEditor('#description', editorInstance);
Change your CKEditorHelper to
window.CKEditorHelper = window.CKEditorHelper || {};
(function (exports) {
exports.initEditor = function (input, myEditorInstance) {
ClassicEditor
.create(document.querySelector(input), {
language: {
ui: 'en'
content: 'en'
}
})
.then(editor => {
myEditorInstance.editor = editor;
});
};
})(window.CKEditorHelper);
And when you want to use your editor
console.log(editorInstance.editor.getData());
You can give this in javascript
$(document).ready(function () {
CKEDITOR.replace('tmpcontent', { height: '100px' })
})
take the value by using following
$('#save').on('click', function(){
var textareaValue = CKEDITOR.instances.tmpcontent.getData();
});
<label class="control-label">Message</label>
<textarea name="tmpcontent" id="tmpcontent" class="form-control"></textarea>
//OR in latest version
var myEditor;
ClassicEditor
.create( document.querySelector( '#description' ) )
.then( editor => {
console.log( 'Editor was initialized', editor );
myEditor = editor;
} )
.catch( err => {
console.error( err.stack );
} );
and then get data using
myEditor.getData();

What is el() function? ReferenceError: "el is not defined"

I am writing a block in wordpress gutenberg but wordpress showing el( is not defined?
my edit: function is
edit: function( props ) {
function onChange( event ) {
props.setAttributes( { author: event.target.value } );
}
return el( 'input', {
value: props.attributes.author,
onChange: onChange,
} );
},
how to include el support in my plugin ?
You should define el first which contains the block element.
var el = element.createElement;

wp.mce.views gallery override default 'editor-gallery' template

Prior to 4.2 we could override the default MCE gallery template with this code:
var galleryview = wp.mce.views.get('gallery');
galleryview.getContent = function(){
this.template = media.template( 'editor-gallery-dtbaker-flexslider' );
return this.template(this.shortcode.attrs.named);
}
this no longer works. Is there a way to override the default 'gallery' view without re-registering it? This works (by copying and modifying the default code from mce-view.js) but I feel there should be a better way than re-registering the entire view.
Is this possible after the mce view rewrite? https://core.trac.wordpress.org/ticket/31412
Here's code that works in 4.2:
add_action( 'admin_print_footer_scripts', 'my_admin_footer_scripts', 100 );
function my_admin_footer_scripts(){ ?>
<script type="text/javascript">
( function( $ ) {
// start code copied from mce-view.js
var postID = $( '#post_ID' ).val() || 0;
var custom_gallery = _.extend( {}, {
edit: function( text, update ) {
var media = wp.media[ this.type ],
frame = media.edit( text );
this.pausePlayers && this.pausePlayers();
_.each( this.state, function( state ) {
frame.state( state ).on( 'update', function( selection ) {
update( media.shortcode( selection ).string() );
} );
} );
frame.on( 'close', function() {
frame.detach();
} );
frame.open();
},
state: [ 'gallery-edit' ],
template: wp.media.template( 'editor-gallery' ),
initialize: function() {
var attachments = wp.media.gallery.attachments( this.shortcode, postID ),
attrs = this.shortcode.attrs.named,
self = this;
if(typeof attrs.slider != 'undefined'){
switch(attrs.slider){
case 'flexslider':
this.template = wp.media.template( 'editor-gallery-dtbaker-flexslider' );
break;
case 'flex':
this.template = wp.media.template( 'editor-gallery-dtbaker-flex' );
break;
default:
// leave the existing template (editor-gallery)
}
}
attachments.more()
.done( function() {
attachments = attachments.toJSON();
_.each( attachments, function( attachment ) {
if ( attachment.sizes ) {
if ( attrs.size && attachment.sizes[ attrs.size ] ) {
attachment.thumbnail = attachment.sizes[ attrs.size ];
} else if ( attachment.sizes.thumbnail ) {
attachment.thumbnail = attachment.sizes.thumbnail;
} else if ( attachment.sizes.full ) {
attachment.thumbnail = attachment.sizes.full;
}
}
} );
self.render( self.template( {
attachments: attachments,
columns: attrs.columns ? parseInt( attrs.columns, 10 ) : wp.media.galleryDefaults.columns
} ) );
} )
.fail( function( jqXHR, textStatus ) {
self.setError( textStatus );
} );
}
} );
wp.mce.views.unregister('gallery');
wp.mce.views.register('gallery',custom_gallery);
})(jQuery);
<?php }
I have tried this as well and no go:
var dtbaker_gallery = wp.mce.views.get('gallery');
dtbaker_gallery = dtbaker_gallery.extend({
template: wp.media.template( 'editor-gallery-dtbaker-flexslider' )
});

Categories

Resources