ckeditor 5 remove an element from the view - ckeditor

I try to delete an element/node from the view.
For now i try to do that:
editor.model.change(writer => {
writer.remove(element)
});
But I need a element or a range to do so.
So my question : How to get an (or an array of) element from a tag ?
(I found that : editor.editable().findOne( 'img' ).remove() here That's for ckeditor4 not 5 but it is exactly what i need)

You can iterate through all elements of the root and then remove the needed one:
let editorModel = editor.model;
let editorDocument = editorModel.document;
editorDocument.on('change:data', (event) => {
let root = editorDocument.getRoot();
let children = root.getChildren();
for(let child of children){
if(child.is('image')) {
editorModel.change(writer => {
writer.remove(child);
});
}
}
});

Related

Cypress automation: multiple cy.get elements in one function

I have a function:
checkWebElemAndAssert(...elements) {
for (const element of elements) {
element.should('be.visible').click().should('be.checked');
}
}
and i use it within another function:
checkRegisterValues = () => {
let maleCheckBox = cy.get('input[value=Male]');
let femaleCheckBox = cy.get('input[value=FeMale]');
let cricketCheckBox = cy.get('#checkbox1');
let registerElemList = [maleCheckBox, femaleCheckBox, cricketCheckBox];
this.browserUtils.checkWebElemAndAssert(...registerElemList);
return this;
}
The problem is that when i use checkRegisterValues() it uses for each action the last element: cricketCheckBox. Any hints on what is wrong? i would expect that the action is made for each element and not the last one.
Have you tried passing in the array like this?
this.browserUtils.checkWebElemAndAssert(registerElemList);
You can also print out
checkWebElemAndAssert(...elements) {
console.log(elements);
for (const element of elements) {
element.should('be.visible').click().should('be.checked');
}
}
and see what you are passing in
ok so i read a bit more and made this:
checkWebElemAndAssert2(elements) {
cy.get(elements).each(($list) => {
cy.get($list).click({ multiple: true }).should('be.checked')
})
}
Basically in elements when i call checkWebElemAndAssert2 i will give the list identifier. Seems to work but not sure meets the standard.
checkRegisterValues = () => {
let myList = 'input[type=radio]';
this.browserUtils.checkWebElemAndAssert2(myList);
return this;
}

Updating react-table values after Dragging and Dropping a row in React Redux

I´ve accomplished the react drag and drop functionality into my project so i can reorder a row in a react table´s list. The problem is i have a column named 'Sequence', witch shows me the order of the elements, that i can´t update its values.
Example:
before (the rows are draggable):
Sequence | Name
1 Jack
2 Angel
after ( i need to update the values of Sequence wherea i change their position after dropping a specific draggable row, in this case i dragged Jack at the first position and dropped it at the second position) :
Sequence | Name
1 Angel
2 Jack
React/Redux it´s allowing me to change the index order of this array of elements, without getting the 'A state mutation was detected between dispatches' error message, but is not allowing me to update the Sequence values with a new order values.
This is what i have tried so far:
// within the parent class component
// item is an array of objects from child
UpdateSequence(startIndex, endIndex, item) {
// the state.Data is already an array of object
const result = this.state.Data;
const [removed] = result.splice(startIndex, 1);
result.splice(endIndex, 0, removed);
// this is working without the mutation state error
this.setState({ Data: result })
let positionDiff = 0;
let direction = null;
let newIndex = 0;
positionDiff = endIndex - startIndex;
if (startIndex > endIndex) {
direction = "up";
}
else if (startIndex < endIndex) {
direction = "down";
}
if (positionDiff !== 0) {
for (var x = 0; x <= Math.abs(positionDiff); x++) {
if (x === 0) {
newIndex = startIndex + positionDiff - x;
this.setState(prevState => ({
Data: {
...prevState.Data,
[prevState.Data[newIndex].Sequence]: Data[newIndex].Sequence + positionDiff
},
}));
}
else {
if (direction === "down") {
newIndex = startIndex + positionDiff - x;
this.setState(prevState => ({
Data: {
...prevState.Data,
[prevState.Data[newIndex].Sequence]: Data[newIndex].Sequence - 1
},
}));
}
else if (direction === "up") {
Data= startIndex + positionDiff + x;
this.setState(prevState => ({
Data: {
...prevState.Data,
[prevState.Data[newIndex].Sequence]: Data[newIndex].Sequence + 1
},
}));
}
}
}
// so when i call save action i am stepping into the 'A state mutation was detected between dispatches' error message.
this.props.actions.saveSequence(this.state.Data)
.then(() => {
this.props.actions.loadData();
})
.catch(error => {
toastr['error'](error, 'error....');
})
}
Calling the action 'saveSequence' whenever i try to update the element of the array, 'Sequence', i am getting the 'A state mutation was detected between dispatches' error message.
Any help will be greatfull! Thank you!
note: The logic applied to reorder the Sequence is ok.
While I don't know redux particularly well, I am noticing that you are directly modifying state, which seems like a likely culprit.
const result = this.state.Data;
const [removed] = result.splice(startIndex, 1);
splice is a destructive method that modifies its input, and its input is a reference to something in this.state.
To demonstrate:
> state = {Data: [1,2,3]}
{ Data: [ 1, 2, 3 ] }
> result = state.Data.splice(0,1)
[ 1 ]
> state
{ Data: [ 2, 3 ] }
Notice that state has been modified. This might be what Redux is detecting, and a general React no-no.
To avoid modifying state, the easy way out is to clone the data you are looking to modify
const result = this.state.Data.slice()
Note that this does a shallow copy, so if Data has non-primitive values, you have to watch out for doing destructive edits on those values too. (Look up deep vs shallow copy if you want to find out more.) However, since you are only reordering things, I believe you're safe.
Well, i figured it out changing this part of code:
//code....
const result = item;
const [removed] = result.splice(startIndex, 1);
// i created a new empty copy of the const 'removed', called 'copy' and update the Sequence property of the array like this below. (this code with the sequence number is just a sample of what i came up to fix it )
let copy;
copy = {
...removed,
Sequence: 1000,
};
result.splice(endIndex, 0, copy);
After i didn´t setState for it, so i commented this line:
// this.setState({ Data: result })
//...code
and the end of it was putting the result to the save action as a parameter , and not the state.
this.props.actions.saveSequence(result)
Works and now i have i fully drag and drop functionality saving the new order sequence into the database with no more 'A state mutation was detected between dispatches' error message!

How can i compare arrays in Cypress?

I want to compare data present in an array with the data retrieved from a class using .each in cypress?
Using below code i have tried to iterate over the FileType array using below code.
const Filetype = ['Access', 'Excel', 'Text/CSV','PDF','JSON','dsdsd'];
const te = cy.wrap($bodyFind).find('.data-sourcename').should('have.length',6).each(($li) => { cy.log($li.text()); });
te.each(($text)=> {
cy.log("Te" + $text);
//prints ['Access','Excel','Text/CSV','PDF','JSON','XML'];
});
// Converted FileType Array to Cypress object using cy.wrap command.
const cywrap = cy.wrap(Filetype);
te.each((e1)=>cywrap.each((e2)=> {
if(e1 == e2) {
expect(e1).equals(e2);
}
}));
But the value of e1 and e2 is same.
expect should fail with 'dsdsd' is equals 'XML'
whereas it passes with 'dsdsd' is equals 'dsdsd'
You could use map here.
const filetypes = ['Access', 'Excel', 'Text/CSV','PDF','JSON','dsdsd'];
cy.get('.data-sourcename').should(($els) => {
// map jquery elements to array of their innerText
const elsText = $els.toArray().map(el => el.innerText)
expect(elsText).to.deep.eq(filetypes)
})
I hope by now you must have found out the solution for this. But still, there was no selected answers yet, thought I would add one.
const Filetype = ['Access', 'Excel', 'Text/CSV','PDF','JSON','dsdsd'];
cy
.get('whatever element')
.each(($span, i) => {
expect($span.text()).to.equal(Filetype[i]);
});
$span would go through each element and .text()will get the text value of that element.

SCRIPT5007: Unable to get value of the property 'indexOf': object is null or undefined.Please help to solve this

I am posting full code now please check and let me know what i have to modify in this code to solve this problem in IE:
var values = [];
$("#tblitem #itm").each(function(a, b)
{
values[a] = b.text;
});
valuex[x] is used to fetch itemname here.and below i used it in indexof().indexof() is working well before i use array.problem occurs after the use of array only in IE.
var compare_value_oldd="$500";
var compare_value_neww=parseFloat(compare_value_oldd.replace(/[^0-9-.]/g,''));
for( var x in values)
{
if (parseFloat(totalnumm.replace(/[^0-9-.]/g,'')) > compare_value_neww && values[x].indexOf("Custom") > -1 )
{
if ($.cookie('test_status1') != '2')
{
$('#element_to_pop_up1').bPopup({
content: 'image', //'ajax', 'iframe' or 'image'
contentContainer: '.content',
loadUrl: 'coupon.jpg'
});
<!--cookie settings here-->
<!--expire time of cookie is 30 days.you can change it as per your requirements-->
$.cookie('test_status1', '2', { expires: 30 });
}
}
}
I got error in this line.
**if (parseFloat(totalnumm.replace(/[^0-9-.]/g,'')) > compare_value_neww && values[x].indexOf("Custom") > -1 )**
You should wrap element inside jquery object:
var values = [];
$("#tblitem #itm").each(function(a, b)
{
values[a] = $(b).text();
});
I don't know which kind of element is '#itm', you could have to use $(b).html(); or $(b).val();

Magento Enterprise Tabs - How to select specific tab in link?

I am trying to link to a specific tab in Magento Enterprise. It seems that all of the answers I've found don't apply well to their method. I just need a link to the page to also pull up a specific tab. This is the code they use:
Enterprise.Tabs = Class.create();
Object.extend(Enterprise.Tabs.prototype, {
initialize: function (container) {
this.container = $(container);
this.container.addClassName('tab-list');
this.tabs = this.container.select('dt.tab');
this.activeTab = this.tabs.first();
this.tabs.first().addClassName('first');
this.tabs.last().addClassName('last');
this.onTabClick = this.handleTabClick.bindAsEventListener(this);
for (var i = 0, l = this.tabs.length; i < l; i ++) {
this.tabs[i].observe('click', this.onTabClick);
}
this.select();
},
handleTabClick: function (evt) {
this.activeTab = Event.findElement(evt, 'dt');
this.select();
},
select: function () {
for (var i = 0, l = this.tabs.length; i < l; i ++) {
if (this.tabs[i] == this.activeTab) {
this.tabs[i].addClassName('active');
this.tabs[i].style.zIndex = this.tabs.length + 2;
/*this.tabs[i].next('dd').show();*/
new Effect.Appear (this.tabs[i].next('dd'), { duration:0.5 });
this.tabs[i].parentNode.style.height=this.tabs[i].next('dd').getHeight() + 15 + 'px';
} else {
this.tabs[i].removeClassName('active');
this.tabs[i].style.zIndex = this.tabs.length + 1 - i;
this.tabs[i].next('dd').hide();
}
}
}
});
Anyone have an idea?
I would consider modifying how the class starts up.
initialize: function (container) {
this.container = $(container);
this.container.addClassName('tab-list');
this.tabs = this.container.select('dt.tab');
// change starts here //
var hashTab = $(window.location.hash.slice(1));
this.activeTab = ( this.tabs.include(hashTab) ? hashTab : this.tabs.first());
// change ends here //
this.tabs.first().addClassName('first');
this.tabs.last().addClassName('last');
this.onTabClick = this.handleTabClick.bindAsEventListener(this);
for (var i = 0, l = this.tabs.length; i < l; i ++) {
this.tabs[i].observe('click', this.onTabClick);
}
this.select();
}
Here, I have only changed how the initial tab is chosen. It checks for an URL fragment which is commonly known as a hash, if that identifies one of the tabs it is preselected. As a bonus the browser will also scroll to that element if possible.
Then you only need to append the tab's ID to the URL. For example you might generate the URL by;
$productUrl = Mage::getUrl('catalog/product/view', array(
'id' => $productId,
'_fragment' => 'tab_id',
));
If you've recently migrated from an earlier Magento release, e.g. from Enterprise 1.11 to Enterprise 1.12, make sure the javascript in /template/catalog/product/view.phtml
right after the foreach that generates the tabs gets updated to the 1.12 version:
<script type="text/javascript">
var collateralTabs = new Enterprise.Tabs('collateral-tabs');
Event.observe(window, 'load', function() {
collateralTabs.select();
});
</script>
surfimp's VERY helpful suggestions did not produce the desired opening of the closed tab otherwise. Once this updated javascript was added, clicking on a link to read Review or Add Your Review on the product page, jumped to the Reviews tab, even if the tab had been hidden.
Similar to Zifius' answer, you can modify the initialize function to just take another argument which will be the active tab.
Event.observe(window, 'load', function() {
new Enterprise.Tabs('collateral-tabs', $('tab_review'));
});
and then in the scripts.js (or wherever this class may exist for you)
initialize: function (container, el) {
...
this.activeTab = el;
...
}
Use whatever logic in the template you like to set 'el' to the desired value.
The reason I did it this way is because when I used Zifius' method, the desired tab would be the active tab, but the default tab's content was still displayed.
Had the same task yesterday and as I don't know about prototype much I solved it by adding another method:
selectTab: function (element) {
this.activeTab = element;
this.select();
},
Usage:
var Tabs = new Enterprise.Tabs('collateral-tabs');
Tabs.selectTab($('tabId'));
Would like to know if it's a correct approach

Resources