CKEditor 5 Find Model Element By Attibute - ckeditor

A custom html dom element exists inside my editor:
<content id="1">
<p>Paragraf is here and link text exists</p>
</content>
I want to find this element in the model using it's attributes. I can find it using a recursive method starting from root. But is there a simpler method like querySelectorAll?

I've not found an out-of-the-box helper method which does this, but if anyone's just looking for a function definition they can use, try this:
function findDescendant (modelElement, predicate) {
if (predicate(modelElement)) {
return modelElement
}
if (modelElement.getChildren) {
for (let child of modelElement.getChildren()) {
const found = findDescendantByName(child, name)
if (found) {
return found
}
}
}
}
...
...
const descendant = findDescendant(element, (element) => element.hasAttribute('foobar'))

Related

Cypress - How to use if statement with contains

so I have to use cy.contains to find the element I want, but all I can find online is how to use if() with cy.find or cy.get if there a way to do this with contains?
Example code:
if(cy.contains('div.name', 'Test 1').length > 0) {
//Type in name
cy.get('input.newName').click().type('Test 1');
cy.wait(2000);
//Click Add Name
cy.get('div.createNewName> a').click();
cy.wait(2000);
}
What I am trying to do there is:
if(Name doesnt exist){
Create it
}
I'm not sure if I have explained myself too well, if any more clarifications are needed feel free to ask
You can also do like this:
cy.get('body').then(($body) => {
if ($body.find('div.name:contains("Test 1")').length > 0) {
//Element Found
} else {
//Element not found
}
})
The general pattern for this would be as follows:
const element = Cypress.$('div.name:contains(Test 1)')
if (element.length > 0) {
...
Make sure the DOM is stable when you run this code, there is no retry built in as there is with cy.contains()
If the code inside if() is creating the name, then maybe the logic would be
const element = Cypress.$('div.name:contains(Test 1)')
if (element.length === 0) {
// not found so create it
...
You can also do it like this
cy.get('div.name').then($div => {
const found = $div.find(':contains("Test 1")')
if (found.length === 0) {
// create...
}
})

How can I verify which class name in the element?

I have element. And I need verify which class in this element and do something after that. How can I do it?
cy.get('element')
.should('have.class', 'Enabled')
.log('Enabled')
or
.log('Disabled')
Using a .then() function to yield the element found by cy.get(), and then using the JQuery function hasClass to determine if the yielded element has the Enabled class should work.
cy.get('element').then(($el) => {
cy.log($el.hasClass('Enabled') ? 'Enabled' : 'Disabled');
if ($el.hasClass('Enabled')) {
// some code
} else {
// some other code
}
})

cypress: How can manage the application flow, if the element xpath is not present

I have the following scenario:
if the element is present, i have to do one activity and if not present will do another activity.
cy.xpath("//div[text()= 'button').its('length').then(res=> {
if (res > 0) {
return 1;
}
else {
cy.log ("Element is not present")
}
}
)} '''
if element is present = Code is working fine,
if the element xpath is not present = it try to search the element xpath (//div[text()= 'button') and throwing the error as 'Timed out retrying: Expected to find element: undefined, but never found it.'
if element is not present, Is there any way, i can handle the code ,
When using xpath you can (sort of) make it conditional by wrapping the xpath selector with count().
cy.xpath("count(//div[text()= 'button'])") // ok with async content
.then(count => {
if (count) {
//return 1; // not useful, returns a "chainer"
// ...but you can perform the required test here, e.g
cy.xpath("//div[text()= 'button']").click()
} else {
cy.log('not found')
}
})
The shorter syntax using built-in jQuery might be
const exists = !!Cypress.$("div:contains('button')").length
if (exists) {
cy.xpath("//div[text()= 'button']").click()
} else {
cy.log('not found')
}
Note that this is a partial match to 'button', where-as the xpath syntax is an exact match.
Also note - using Cypress.$ by-passes retry-ability, so it should not be used where the text is asynchronous.
From docs
This is a great way to synchronously query for elements when debugging from Developer Tools.
The implication is that it's more for debugging after the page has loaded.
The best practice is to try to construct the test and the app's data in such a way that you know that the button is present.
You can do something like this. With Cypress.$, you can validate the presence of the element with the help of the length attribute and then do further actions.
cy.get('body').then($body => {
const ele = $body.find('selector');
if (Cypress.$(ele).length == 0) {
//Do Something element is not present
}
else if (Cypress.$(ele).length > 0) {
//Do Something when element is present
}
})

Jasmine testcase for covering link parameter of the directive

I have been working with the jasmine test cases for the directives but with the template parameter where I would directly check the output of the directive however I do not know how to cover the directive with no template section defined. Like the one given below:
appDirective.directive('linkscriptContainer', [ 'config', function(config) {
return {
restrict : 'A',
scope : {
'value' : '#'
},
link : function(scope, elem, attrs) {
//creating custom script tag
var customScript = document.createElement("script");
customScript.type = "text/javascript";
//checking if property value is available in Config object
//then reading the attribute value and constructing the src tag
if (config[attrs.value] != undefined) {
customScript.src = config[attrs.value];
}
//appending the script tag in linkScriptContainer
elem.append(customScript);
}
};
}]);
You don't need to do anything special for testing the link function. Once, you $compile your element and $scope.$digest() (just like you do for any other directive), link function will be executed by itself.
If your code var customScript = document.createElement("script"); is not getting covered, you might need to mock that function like this,
spyOn(document, "createElement").and.returnValue({});

d3 selector for immediate children

I can obviously do this:
d3.selectAll('div#some-div>ul')
But what if I'm using a DOM node or existing D3 selection:
d3.select(this).selectAll('ul')
will get me all descendent ULs. So, if
var div = d3.select('div')
got me this node:
<div>
<ul>
<li>foo
<ul><li>bar</li></ul>
</li>
<ul>
</div>
Then
var uls = div.selectAll('ul')
will get me two ULs. I guess I could distinguish a top level one like:
uls.filter(function() { return this.parentNode === div.node() }
So, I've answered my own question. Maybe it will be useful to someone. Or maybe someone can recommend a less ugly solution.
Even better, Alain Dumesny, whose answer below is belatedly selected as correct, posted this as an issue to D3 and got the problem fixed, kludge-free, at the source! (I would copy it in here for convenience, but then people might not scroll down and cast greatly deserved upvotes for his heroic feat.)
I wouldn't have expected this to work, but it looks like D3 will sub-select any element that is a child of the selection and matches the selector - so this works:
d3.select(this).selectAll('div > ul');
See http://jsfiddle.net/g3aay/2/
If anyone is still interested, d3.select(this.childNodes) was helping me to solve my problem for picking all immediate children. Alternatively, you can use
selection.select(function(){
return this.childNodes;
})
d3 selection v2.0 should now have this built in with new selection.selectChildren() / selection.selectChild() methods - see https://github.com/d3/d3-selection/issues/243
#nrabinowitz's solution doesn't work all the time.
In my case, I was trying to do d3.select(this).selectAll(".childNode > *").
So I was trying to get all the immediate children of .childNode. The problem is that this was a nested stack, so .childNode could also appear in the children, which was causing problems.
The best way I found is:
var child = d3.select(this).select(".childNode");
var sel = d3.select(this).selectAll(".childNode > *").filter(function() {
return this.parentNode == child.node();
});
The selectAll method relies on the querySelectorAll native method (in v4 at least).
It means you can use the :scope pseudo selector :
var uls = div.selectAll(':scope > ul')
the :scope pseudo selector is currently a draft specification and is not supported in all browsers yet. More information on :scope pseudo selector available on MDN
Based on the solution by Sigfrid, here is something I added to the prototype, in a project I work on.
/**
* Helper that allows to select direct children.
* See https://stackoverflow.com/questions/20569670/d3-selector-for-immediate-children
*
* #param {string} selector
* #returns {Selection}
*/
d3.selectAll('__nonexisting__').__proto__.MYPREFIX_selectChildren = function (selector) {
var expectedParent = this.node();
return this.selectAll(selector).filter(
function() {
return this.parentNode === expectedParent;
}
);
};
The way that I grab the prototype object looks a bit clumsy. Perhaps there is a better way.
The "MYPREFIX_" is meant to prevent name clashes.
The jsdoc #returns {Selection} is ambiguous, unfortunately this type is declared within a closure and has no global name referenceable by jsdoc (afaik).
Once this file is included, you can then do this:
d3.select('#some_id').MYPREFIX_selectChildren('ul')
Looks like d3 used to have some functions built to address this exact problem- but for one reason or another they were removed.
By pasting this code into your program, you can add them back in again:
function childMatcher(selector) {
return function(node) {
return node.matches(selector);
};
}
function children() {
return this.children;
}
function childrenFilter(match) {
return function() {
return Array.prototype.filter.call(this.children, match);
};
}
/**
* Runs the css selector only on the immediate children.
* See: https://stackoverflow.com/questions/20569670/d3-selector-for-immediate-children
* Use: https://github.com/d3/d3-selection/commit/04e9e758c80161ed6b7b951081a5d5785229a8e6
*
* Example Input: selectChildren("form")
*/
d3.selection.prototype.selectChildren = function(match) {
return this.selectAll(match == null ? children
: childrenFilter(typeof match === "function" ? match : childMatcher(match)));
}
function childFind(match) {
return function() {
return Array.prototype.find.call(this.children, match);
};
}
function childFirst() {
return this.firstElementChild;
}
/**
* Runs the css selector only on the immediate children and returns only the first match.
* See: https://stackoverflow.com/questions/20569670/d3-selector-for-immediate-children
* Use: https://github.com/d3/d3-selection/commit/04e9e758c80161ed6b7b951081a5d5785229a8e6
*
* Example Input: selectChild("form")
*/
d3.selection.prototype.selectChild = function(match) {
return this.select(match == null ? childFirst
: childFind(typeof match === "function" ? match : childMatcher(match)));
}
If you are using typescript, then here is the function declaration you can include in the same file:
declare module "d3" {
interface Selection<GElement extends d3.BaseType, Datum, PElement extends d3.BaseType, PDatum> {
selectChild(match: string | null | Function): Selection<GElement, Datum, PElement, PDatum>;
selectChildren(match: string | null | Function): Selection<GElement, Datum, PElement, PDatum>;
}
}
Here's a fiddle that implements this: https://jsfiddle.net/Kade333/drw3k49j/12/
For whatever it's worth after four years, ​d3.selectAll('#id > *') can be used, e.g. in ​d3.selectAll('#id > *').remove() to remove all children of an element with id=id

Resources