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

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
}

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;
}

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;

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

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/

How to select a disabled node in jstree?

i can select a node and disable them. But after them i can't click on the the disabled node for enable them.
how can i get the selected node id, when it's disabled and not selecable?
to enable i can use this code:
$("#jstree").jstree().enable_node(node.id);
I hope you can help me with my problem. If you need any further information about what I want to get or if anything is not clear, I am happy to explain it to you in more detail
Best regards!
You can use contextmenu plugin and enable/disable nodes with right click menu items.
Like this.
$( function() {
$( "#jstree" ).jstree( {
plugins: [ "contextmenu" ],
"contextmenu": {
"items": function( $node ) {
return {
"Enable": {
"label": "Enable",
"action": function( obj ) {
$( "#jstree" ).jstree( "enable_node", $node );
}
},
"Disable": {
"label": "Disable",
"action": function( obj ) {
$( "#jstree" ).jstree( "disable_node", $node );
}
}
};
}
}
} );
} );

Mithril: defer route configuration until DOM is ready

My app has div in its view, which will be used as mounting point for pages of my app.
app.view = function(ctrl) {
return [
appHeader.view(),
appNav.view(),
m("#page")
];
};
The following doesn't seem to work:
m.mount(document.getElementById("app"), app);
m.route.mode = "hash";
m.route(document.getElementById("page"), "", {
"select_company": admin.SelectCompany
});
It works if I include <div id="page"></div> directly in app.html.
How to solve the above issue, without writing html directly?
I was told by #ArthurClemens and #barneycarroll through Gitter chat that using m.mount() and m.route() both in one application is not recommended approach. One solution provided by #barneycarroll is to only use m.route(), and use a function that will return page view along with other common parts of the application like below (jsbin is here):
var header = {
view : function(){
return m( "h1", "This is the persistent site header" )
}
}
var nav = {
controller : function(){
this.links = [
[ "/", "Home" ],
[ "/select_company", "Companies" ]
]
},
view : function( ctrl ){
return m( "ul",
ctrl.links.map( function( link ){
return m( "li",
m( "a", {
config : m.route,
href : link[ 0 ]
}, link[ 1 ] )
)
} )
)
}
}
function furnish( component ){
return {
view : function(){
return [
header,
nav,
component
]
}
}
}
var home = {
view : function(){
return m( "h2", "Welcome!" )
}
}
var selectCompany = {
view : function(){
return m( "h2", "Please select a company" )
}
}
m.route.mode = "hash";
m.route( document.body, "/", {
"/" : furnish( home ),
"/select_company": furnish( selectCompany )
} );

Categories

Resources