Execute script within shadowRoot - web-component

I am trying to use the following code to execute a script from within shadowRoot.
const template = document.createElement('template');
template.innerHTML = `<script>console.log("hey");</script>`;
this.shadowRoot.appendChild(template.content);
I'm told creating a template should work, but this code doesn't appear to work in Chrome v71.

The first thing to remember is that shadowDOM encapsulates DOM and CSS and NOT JavaScript.
The second thing to know is that you can not introduce script into the DOM by using .innerHTML. See this link. Instead the class that defines your component is how to encapsulate your JS code.
While you can't use .innerHTML you can create a script element and set its .textContent and then call .appendChild() for that.
const script = document.createElement('script');
script.textContent = `alert("hey");`;
const el = document.querySelector('.testing');
el.attachShadow({mode:'open'});
el.shadowRoot.appendChild(script);
<div class="testing"></div>
But, given #2 this probably is not what you really want to do.

Related

It is possible to attach files by clicking on capybara

I'm using capybara, cucumber and webDriver to perform file tests
I am doing a study and need to attach a file, however the file input does not exist in the dom, and it is only created when the button is clicked, currently my code is like this:
HTML
<a id="input-id" href="#" onClick="callInput">Attach</a>
Script
function callInput(){
const input = document.createElement("input");
input.style.display = "none";
input.type = "file";
input.click();
}
If it's possible the only way would be using the attach_file block mode
attach_file('/file/to/be/attached') do
click_link('Attach')
end
Since you're setting display to 'none' rather than hiding via setting it offscreen or other methods it's possible the make_visible option could make it work if the above doesn't
attach_file('/file/to/be/attached', make_visible: true) do
click_link('Attach')
end
If neither of those work then it's not possible for Capybara to work with the way you've implemented file upload on your page.
Note: odds of either working is pretty low because you're never actually attaching the input to the page so events won't get routed anywhere Capybara can detect.

Is there a way to include data-* as a script attribute in custom Google Tag Manager

I'm including a Custom script in GTM that makes a call to an external resource. The script looks like this
<script type="text/javascript" id="some-key" data-key="xxxxxxxxxxxxxxxxxx" src="link-to-external-resource"></script>
I've set its triggering to All pages which currently triggers fine But the problem is, the script renders without the data-key attribute in the DOM. It's rendering in the DOM looks like this
<script type="text/javascript" id="some-key" src="link-to-external-resource"></script>
Am I missing something? Is there a way to include data-* attributes in Google Tag Manager?
I can confirm that for unknown reasons GTM strips the data attributes from appended script elements. Other elements like img seems to keep data attributes.
I've tested some workaround that preserves the data attributes but it's necessary to test if the appended script behaves properly when added in this way:
<script>
var script = document.createElement('script');
script.id = 'Gdf234ds'
script.dataset.key = 'xxxxxxxxxxxxxxxxxx'
script.src = "https://link-to-external-resource.js"
// use another target than head if necessary
document.getElementsByTagName('head')[0].appendChild(script)
</script>

How can I inject JavaScript file into a WebEngineView page?

I'm adding a script tag to a web page once it's fully loaded in a WebEngineView, but it's silently failing somehow.
I inject the script by invoking webview.runJavaScript with this code:
var s = document.createElement('script');
s.src = "qrc:/jquery-2.1.4.min.js";
document.body.appendChild(s);
That's perfectly standard and to a certain extent it works as expected, i.e., if I view the html source of the page, the script tag has indeed been appended to the body.
The problem is that the script isn't being downloaded, or isn't being evaluated, or something. All I know is in the above example the jQuery functions aren't available. If I load a small JavaScript test file with one global variable, that variable's not available either. Changing the url to http instead of qrc and pointing it to a web server makes no difference.
Injecting an img tag works fine; the image is loaded and displayed.
But JavaScript is broken somehow. Does anyone know how to fix this?
The problem had to do with the asynchronous nature of QML and JavaScript.
I was inserting a script tag to inject jQuery, and then I was calling a function to de-conflict my inserted version of jQuery from whatever version of jQuery might already be in the original page.
But I believe the webview had not finished parsing the inserted jQuery library before my de-conflicting function was called, so it failed. (I'm not very experienced with browser programming or I might have suspected this from the beginning.)
The solution was to insert a script tag with a small bit of JavaScript that inserts jQuery and then sets a timeout to wait 200ms before calling the de-conflict function. Like so:
function insertAuhJQuery(){
var s = document.createElement("script");
s.src = "qrc:/jquery-2.1.4.min.js";
document.body.appendChild(s);
window.setTimeout(deConflictJQuery, 200);
}
function deConflictJQuery(){
auh = {};
auh.$ = jQuery.noConflict(true);
}
insertAuhJQuery()
That works reliably and is acceptable for my purpose.

Template.myTemplate.rendered in Meteor?

What is the use of Template.myTemplate.rendered in Meteor?. I had studied the document but i didn't understand the exact functionality.The document says Provide a callback when an instance of a template is rendered. What is the meaning of instance of a template is rendered.Can you please suggest me with an example?
When the callback is fired, an instance of the template has been rendered (added to the document). It can be useful if you for example want to manipulate the elements in the template through the use of a JavaScript library, for example CodeMirror, as I used in one of my projects. For example:
<template name="test">
<textarea></textarea>
</template>
Template.test.rendered = function(){
// Make the textarea highlight the code (kind of).
var myCodeMirror = CodeMirror.fromTextArea(this.find('textarea'))
}

Using CSS to affect div style inside iframe

Is it possible to change styles of a div that resides inside an iframe on the page using CSS only?
You need JavaScript. It is the same as doing it in the parent page, except you must prefix your JavaScript command with the name of the iframe.
Remember, the same origin policy applies, so you can only do this to an iframe element which is coming from your own server.
I use the Prototype framework to make it easier:
frame1.$('mydiv').style.border = '1px solid #000000'
or
frame1.$('mydiv').addClassName('withborder')
In short no.
You can not apply CSS to HTML that is loaded in an iframe, unless you have control over the page loaded in the iframe due to cross-domain resource restrictions.
Yes. Take a look at this other thread for details:
How to apply CSS to iframe?
const cssLink = document.createElement("link");
cssLink.href = "style.css";
cssLink.rel = "stylesheet";
cssLink.type = "text/css";
frames['frame1'].contentWindow.document.body.appendChild(cssLink);
// ^frame1 is the #id of the iframe: <iframe id="frame1">
You can retrieve the contents of an iframe first and then use jQuery selectors against them as usual.
$("#iframe-id").contents().find("img").attr("style","width:100%;height:100%")
$("#iframe-id").contents().find("img").addClass("fancy-zoom")
$("#iframe-id").contents().find("img").onclick(function(){ zoomit($(this)); });
Good Luck!
The quick answer is: No, sorry.
It's not possible using just CSS. You basically need to have control over the iframe content in order to style it. There are methods using javascript or your web language of choice (which I've read a little about, but am not to familiar with myself) to insert some needed styles dynamically, but you would need direct control over the iframe content, which it sounds like you do not have.
Use Jquery and wait till the source is loaded,
This is how I have achieved(Used angular interval, you can use javascript setInterval method):
var addCssToIframe = function() {
if ($('#myIframe').contents().find("head") != undefined) {
$('#myIframe')
.contents()
.find("head")
.append(
'<link rel="stylesheet" href="app/css/iframe.css" type="text/css" />');
$interval.cancel(addCssInterval);
}
};
var addCssInterval = $interval(addCssToIframe, 500, 0, false);
Combining the different solutions, this is what worked for me.
$(document).ready(function () {
$('iframe').on('load', function() {
$("iframe").contents().find("#back-link").css("display", "none");
});
});
Apparently it can be done via jQuery:
$('iframe').load( function() {
$('iframe').contents().find("head")
.append($("<style type='text/css'> .my-class{display:none;} </style>"));
});
https://stackoverflow.com/a/13959836/1625795
probably not the way you are thinking. the iframe would have to <link> in the css file too. AND you can't do it even with javascript if it's on a different domain.
Not possible from client side . A javascript error will be raised "Error: Permission denied to access property "document"" since the Iframe is not part of your domaine.
The only solution is to fetch the page from the server side code and change the needed CSS.
A sort of hack-ish way of doing things is like Eugene said. I ended up following his code and linking to my custom Css for the page. The problem for me was that, With a twitter timeline you have to do some sidestepping of twitter to override their code a smidgen. Now we have a rolling timeline with our css to it, I.E. Larger font, proper line height and making the scrollbar hidden for heights larger than their limits.
var c = document.createElement('link');
setTimeout(frames[0].document.body.appendChild(c),500); // Mileage varies by connection. Bump 500 a bit higher if necessary
Just add this and all works well:
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
If the iframe comes from another server, you will have CORS ERRORS like:
Uncaught DOMException: Blocked a frame with origin "https://your-site.com" from accessing a cross-origin frame.
Only in the case you have control of both pages, you can use https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage to safely send messages like this:
On you main site(one that loads the iframe):
const iframe = document.querySelector('#frame-id');
iframe.contentWindow.postMessage(/*any variable or object here*/, 'https://iframe-site.example.com');
on the iframe site:
// Called sometime after postMessage is called
window.addEventListener("message", (event) => {
// Do we trust the sender of this message?
if (event.origin !== "http://your-main-site.com")
return;
...
...
});
Yes, it's possible although cumbersome. You would need to print/echo the HTML of the page into the body of your page then apply a CSS rule change function. Using the same examples given above, you would essentially be using a parsing method of finding the divs in the page, and then applying the CSS to it and then reprinting/echoing it out to the end user. I don't need this so I don't want to code that function into every item in the CSS of another webpage just to aphtply.
References:
Printing content of IFRAME
Accessing and printing HTML source code using PHP or JavaScript
http://www.w3schools.com/js/js_htmldom_html.asp
http://www.w3schools.com/js/js_htmldom_css.asp

Resources