How to react on link remove event in JointJS - jointjs

I use the following code to control the remove functionality on links. How can I intercept the remove event and prevent it if the link match a specific condition?
// add a remove button on hovered link
this.paper.on("link:mouseenter", function(linkView) {
let tools = [new joint.linkTools.Remove({ distance: 20 })];
linkView.addTools(
new joint.dia.ToolsView({
name: "onhover",
tools: tools
})
);
});
// remove button on hovered link
this.paper.on("link:mouseleave", function(linkView) {
if (!linkView.hasTools("onhover")) return;
linkView.removeTools();
});

found the answer by using the action argument passed to the linkTools.Remove constructor.
// add a remove button on hovered link
this.paper.on("link:mouseenter", function(linkView) {
let tools = [
new joint.linkTools.Remove({
distance: 20,
action: function(evt) {
// do stuff and remove link using
this.model.remove({ ui: true, tool: this.cid });
}
})
];
linkView.addTools(
new joint.dia.ToolsView({
name: "onhover",
tools: tools
})
);
});

Related

Cypress data-testid not found

I am running a cypress test on a remote web app and the cy.get method fails to capture elements based on their data-testid .
This is a sample of the tests that I want to run :
describe('test: deny', () => {
it('I can deny', () => {
cy.visit('https://www.deepskydata.com/');
cy.wait(1000)
cy.get("[data-testid='uc-accept-all-button']").click();
});
});
Here the button with data-testid='uc-accept-all-button' is not found by cy.get.
Also cy.get('button') doesn't work despite that there are multiple button elements in the DOM.
Has anyone ever encountered a similar issue ?
The button you want to click is for privacy settings.
The problem is this section of the page isn't consistently displayed, once you click the "Accept All" button it may not display on the next run.
To avoid the problem, you should poll for the button inside the shadow root container element before attempting to click.
function clickPrivacySettingsButton(attempt = 0) {
// Poll for 4 seconds
if (attempt === 40) {
cy.log('No Accept All button to click')
return
}
cy.get('#usercentrics-root', {log:false}).then($privacySettings => {
const prvivacyShadow = $privacySettings.shadowRoot // get shadow root
const $acceptAllButton = Cypress.$(prvivacyShadow)
.find('[data-testid="uc-accept-all-button"]') // look for button
if ($acceptAllButton.length === 0) {
cy.wait(100, {log:false})
clickPrivacySettingsButton(++attempt)
} else {
cy.get('#usercentrics-root')
.shadow()
.find('[data-testid="uc-accept-all-button"]')
.click()
cy.log('Dismissed Accept All button')
return
}
})
}
cy.visit('https://www.deepskydata.com/')
clickPrivacySettingsButton()
Notes
You cannot just use Cypress includeShadowDom setting, because the shadow root may or may not exist.
You will have to apply cy.wait() in small increments to effectively poll for the Privacy Settings section.
I could see that there is a Shadow DOM in your app. TO make sure cypress traverses through the shadow DOM, in your cypress config file write:
includeShadowDom: true
Your cypress.config.js should look like this:
const { defineConfig } = require("cypress");
module.exports = defineConfig({
e2e: {
...
},
...
includeShadowDom: true
})
Then in your test, you can directly write:
describe('test: deny', () => {
it('I can deny', () => {
cy.visit('https://www.deepskydata.com/')
cy.get("[data-testid='uc-accept-all-button']").should('be.visible').click()
})
})
Avoid using cy.wait() as these can make the tests flaky. Instead use a visible assertion to first check that the element is visible and then click on it.
You may want to have a test to check the banner exists for a user meeting certain conditions.
Otherwise, you can bypass this modal, with correct permissions of course, by making a making a graphQL mutation saveConsents, so you will not need to making any checks at the UI level.
Note: you should choose your method of recursing and allow failOnStatusCode.
cy.request({
method: 'POST',
url: 'url-endpoint',
auth: 'any-authorization',
body: {
operationName: 'saveConsents',
query: 'graphQL mutation query'
}
variables: 'variables-if-needed',
failOnStatusCode: false, // to allow recurse
})

React Popper - updates position dynamically when adding content to the Popover

I have a Popover containing a list + "Add item" button, so the user can dynamically add items to the list (after 3 items the list gets overflow). The problem starts if the Popover open in the bottom of the window and contain less than 3 items, then the user clicks the "Add item" button, the Popover gets more height thus part of it is outside of the window.
I want to force the Popover to update and gets the right position (Modifiers, ResizeObserver..) but I can't find the right way to make it work.
Any suggestions?
For example:
const observeReferenceModifier = {
name: 'observeReferenceModifier',
enabled: true,
phase: 'write',
effect: ({ state, instance }) => {
const RO_PROP = '__popperjsRO__';
const { reference } = state.elements;
reference[RO_PROP] = new ResizeObserver(entries => {
console.log('size-updated: ', reference.id);
instance.update();
});
reference[RO_PROP].observe(reference);
return () => {
console.log('unobserve: ', reference);
reference[RO_PROP].disconnect();
delete reference[RO_PROP];
};
},
};

dialog sapui5 oError.body display Rendering

Hi I have a dialog witch should display the content of an error in the console from a button.
Inside a UPDATE CRUD I have a dialog witch should return me an error from the console if the operation is in a certain situation.
This is my code from the error function.
function(oError){
var StringoError = JSON.parse(oError.response.body);
/*alert("Error!\n"+oError.message);*/
alert(StringoError.error.message.value);
if I use the 2 alerts it works .. but now I have to style the user experience and put the content of Error.message and StringoError.error.message.value in a dialog/popover/popup.. so I implemented like this:
var dialog = new Dialog({
title: (oError.message),
type: 'Message',
state: 'Error',
content: new Text({
text: JSON.parse(oError.response.body).error.message.value,
}),
beginButton: new sap.m.Button({
text: 'Close',
press: function () {
dialog.close();
}
}),
afterClose: function() {
dialog.destroy();
}
});
dialog.open();
});
The problem is that I get to see the title but I can't see error.message.value and the console gives me back as error:
The renderer for class sap.ui.core.Control is not defined or does not
define a render function! Rendering of __control0 will be skipped!
Should it not be sap.m.Text? Or are you using the AMD Module format? But you are using sap.m.Button in the same code...
content: new sap.m.Text({
text: JSON.parse(oError.response.body).error.message.value,
}),

How to filter urls with # (hash tag) using UrlFilter in a chrome.declarativeContent.PageStateMatcher

I've just started building a chrome extension and as I need to display its icon only for specific urls, I used page_action.
I also used an event listening if the url changes and matches my pattern that way to display the icon:
chrome.declarativeContent.onPageChanged.addRules([
{
conditions: [
new chrome.declarativeContent.PageStateMatcher({
pageUrl: { urlContains: 'https://mysite.com/mypage.html' }
})
],
actions: [ new chrome.declarativeContent.ShowPageAction() ]
}
]);
It works fine but when I want to add a filter of the first character of the query, it fails.
The url pattern I want to filter looks like:
https://mysite.com/mypage.html#e123456789
I tried the following but it didn't help:
pageUrl: { urlContains: 'https://mysite.com/mypage.html#e' }
pageUrl: { urlContains: 'https://mysite.com/mypage.html', queryPrefix: '#e' }
pageUrl: { urlContains: 'https://mysite.com/mypage.html', queryPrefix: 'e' }
I think that the issue comes from the hash tag.
Any idea of a workaround ?
The #... part of a URL is called a "reference fragment" (ocassionally referred to as "hash").
Reference fragments are currently not supported in URLFilters, there is already a bug report for this feature: Issue 84024: targetUrlPatterns and URL search/hash component.
If you really want to show the page action depending on the state of the reference fragment, then you could use the chrome.webNavigation.onReferenceFragmentUpdated event instead of the declarativeContent API. For example (adapted from my answer to How to show Chrome Extension on certain domains?; see that answer for the manifest.json to use for testing):
function onWebNav(details) {
var refIndex = details.url.indexOf('#');
var ref = refIndex >= 0 ? details.url.slice(refIndex+1) : '';
if (ref.indexOf('e') == 0) { // Starts with e? show page action
chrome.pageAction.show(details.tabId);
} else {
chrome.pageAction.hide(details.tabId);
}
}
// Base filter
var filter = {
url: [{
hostEquals: 'example.com'
}]
};
chrome.webNavigation.onCommitted.addListener(onWebNav, filter);
chrome.webNavigation.onHistoryStateUpdated.addListener(onWebNav, filter);
chrome.webNavigation.onReferenceFragmentUpdated.addListener(onWebNav, filter);

YUI3 autocomplete has images on top - How to get autocomplete to the top

My auto YUI autocomplete zindex is off. How can I force the autocomplete DIV to the top.
Below I am using a standard template for YUI:
YAHOO.util.Event.onDOMReady(function(){
YUI().use("autocomplete", "autocomplete-filters", "autocomplete-highlighters", function (Y) {
var inputNode = Y.one('#name'),
tags = [
'css',
'css3',
'douglas crockford',
'ecmascript',
'html',
'html5',
'java',
'javascript',
'json',
'node.js',
'pie',
'yui'
],
lastValue = '';
inputNode.plug(Y.Plugin.AutoComplete, {
activateFirstItem: true,
minQueryLength: 0,
queryDelay: 0,
source: tags,
resultHighlighter: 'startsWith',
resultFilters: ['startsWith']
});
// When the input node receives focus, send an empty query to display the full
// list of tag suggestions.
inputNode.on('focus', function () {
inputNode.ac.sendRequest('');
});
// When there are new AutoComplete results, check the length of the result
// list. A length of zero means the value isn't in the list, so reset it to
// the last known good value.
inputNode.ac.on('results', function (e) {
if (e.results.length) {
lastValue = inputNode.ac.get('value');
} else {
inputNode.set('value', lastValue);
}
});
// Update the last known good value after a selection is made.
inputNode.ac.after('select', function (e) {
lastValue = e.result.text;
});
});
});
Simply to put the z-index in the css. Setting via JS used to be allowed, but as of YUI 3.4.0 it's a css-only flag (https://github.com/yui/yui3/blob/master/src/autocomplete/HISTORY.md).
The relevant CSS is (adjust your z-index as necessary):
.yui3-aclist { z-index: 100; }
PS., your YAHOO. line is from YUI2, so that is quite peculiar and definitely not a standard template.
By the time your callback in the YUI().use(...) section is called, the dom should be ready. No ondomready required.

Resources