JavaScript styling of DOM shadow host - javascript

I'd written the below code, based on my understanding of this:
The host is not styled!!
var fonixDiv = Object.create(HTMLElement.prototype);
// Set up the element.
fonixDiv.createdCallback = function() {
// Create a Shadow Root
var shadow = this.createShadowRoot();
shadow.innerHTML = '<style>'+
':host { width:200px; height:200px; background: #b0c4de; }'+ // Not working
'p{color: red;}'+ // Working
'</style>'+
'<p>hi</p><button id="d">click</button>';
shadow.children.d.addEventListener('click', function(e) {
this.textContent = "you clicked me :(";
shadow.children[1].textContent="Shadow DOM content changed";
host.style.background = "green"; // working
alert("All: button, text and host should be change");
});
};
// Register the new element.
var Xfonix =document.registerElement('fonix-div', {
prototype: fonixDiv
});
UPDATE
in the html file, I call it as:
<fonix-div></fonix-div>
and as:
<div id='host'></div>
<script>
var host = document.querySelector('#host');
var el = new Xfonix();
host.appendChild(el);
<script>
any help how to style the host element!
fiddle is here
nothing is working for host styling, neither width, nor height nor background :(

I was able to solve the issue using css file:
the .html file is:
<fonix-div></fonix-div>
<div id="host1"></div>
the .js file is:
// Create a new object based of the HTMLElement prototype
var fonixDiv = Object.create(HTMLElement.prototype);
// Set up the element.
fonixDiv.createdCallback = function() {
// Create a Shadow Root
var shadow = this.createShadowRoot();
shadow.innerHTML = '<button id="d">click</button>';
shadow.addEventListener('click', function(e) {
console.log('1: '+this.host.dataset.disabled);
this.host.dataset.disabled='true'; // set Attribute to the custom element
});
shadow.children.d.addEventListener('click', function(e) {
this.textContent = "you clicked me :(";
shadow.children[1].textContent="Shadow DOM content changed";
this.disabled=true;
alert("All: button, text and host should be change");
});
};
// Register the new element.
var Xfonix =document.registerElement('fonix-div', {prototype: fonixDiv});
var thehost = document.querySelector('#host1');
thehost.appendChild(new Xfonix());
the .css file is:
body {background: #F7F7F7;}
fonix-div {
display: inline-block;
width: 200px;
height: 200px;
float: left;
margin: 0.5em;
border-radius: 3px;
background: #FFF;
box-shadow: 0 1px 3px rgba(0,0,0,0.25);
font-family: Helvetica, arial, sans-serif;
-webkit-font-smoothing: antialiased;
}
fonix-div:hover, fonix-div[data-disabled='true']:hover {background: red;}
fonix-div:Active {background: green;}
fonix-div[data-disabled='true'] {background: green;}
fonix-div::shadow p{color: blue;}
the output can be seen here:

Related

Detect if element clicked is a pseudo element

I have the same situation here, but it's not answered well. I have this code for a workaround:
window.addEventListener('load', () => {
// sticky profile notes
const notes = document.querySelector('#textarea-notes'); // Get textarea element
const headerDiv = document.createElement("div"); // Create a <div> element
headerDiv.id = 'div-header';
headerDiv.innerHTML = 'Add Notes'; // Insert instructions
// add header on top
notes.parentNode.insertBefore(headerDiv, notes);
// minimize sticky
headerDiv.addEventListener('click', e => {
// detect if cursor type is pointer
console.log(e.target.style.cursor);
});
});
#div-header {
padding: 10px;
cursor: move;
background-color: #ffffcc;
}
#div-header:after {
margin-left: 10px;
cursor: pointer;
content: 'button';
}
#textarea-notes {
background-color: #ffffcc;
width: 100%;
}
<textarea id="textarea-notes">
</textarea>
wherein I aim to check what type of mouse pointer the user has when clicking the div with the div element.
The problem is when I log the cursor type, it shows an empty space. How do I know the cursor type? And is there a better way to identify if the clicked element is a pseudo-element?
Since you can't detect events on pseudo elements you can insert separate elements into the headerDiv and check the target of the click event to accomplish the same objective. (Or only apply events to the new child elements)
Here I created two spans for "add notes" and "button" texts which get appended to the new div. A new css rule for the button span applies the margin and pointer cursor
window.addEventListener('load', () => {
// sticky profile notes
const notes = document.querySelector('#textarea-notes'); // Get textarea element
const headerDiv = document.createElement("div"); // Create a <div> element
headerDiv.id = 'div-header';
// Create two spans to insert in headerDiv
const notesTitle = document.createElement('span')
notesTitle.innerHTML = 'Add Notes'; // Insert instructions
// this span could also be a real <button>
const notesBtn = document.createElement('span');
notesBtn.textContent = 'button';
notesBtn.className = 'notes-btn'
headerDiv.append(notesTitle)
headerDiv.append(notesBtn)
// add header on top
notes.parentNode.insertBefore(headerDiv, notes);
// minimize sticky
headerDiv.addEventListener('click', e => {
let msg = 'Parent clicked';
if(e.target.matches('.notes-btn')){
msg = 'Button clicked';
}
console.log(msg)
});
});
#div-header {
padding: 10px;
cursor: move;
background-color: #ffffcc;
}
/*#div-header:after {
margin-left: 10px;
cursor: pointer;
content: 'button';
}*/
#div-header .notes-btn{
margin-left: 10px;
cursor: pointer;
}
#textarea-notes {
background-color: #ffffcc;
width: 100%;
}
<textarea id="textarea-notes">
</textarea>

window.print() , google maps blank space between screenshot

I'm currently working on an aspx Page , the main page functionality is to display a google maps path composed by several markers (huge amount) , i'd need to add a print option (A3/A4 Format) ,and i've been using the window.print() function to achieve this , as i've been stuck having issues trying with other methods (like google maps api) , here's my current issue : using window.print() i'm able to get the printing of the map with the right formats , however there's a blank space being showed on the printout , here's an example A4(1050,625):
screenshot
The code:
function print(width,height){
var cDiv = document.createElement('div');
cDiv.setAttribute('id','mainContainer');
cDiv.innerHTML='<div id="mapContainer"></div>';
var jqMapContainer = $("#map");
mapContainer = jqMapContainer[0];
var origDisplay = [],
origMapParent = mapContainer.parentNode;
body = window.document.body;
childNodes = body.childNodes;
// hide all body content
$.each(childNodes, function (i, node) {
if (node.nodeType === 1) {
origDisplay[i] = node.style.display;
node.style.display = 'none';
}
});
body.appendChild(cDiv);
var rc = document.getElementById('mapContainer');
rc.appendChild(mapContainer);
$("#mainContainer").width(width);
$("#mainContainer").height(height);
$(mapContainer).width(width);
$(mapContainer).height(height);
setTimeout(function () {
window.print();
}, 4000);
var _self = this;
// allow the browser to prepare before reverting
setTimeout(function () {
// put the chart back in
origMapParent.appendChild(mapContainer);
$("#mainContainer").remove();
// restore all body content
$.each(childNodes, function (i, node) {
if (node.nodeType === 1) {
node.style.display = origDisplay[i];
}
});
google.maps.event.trigger(map, 'resize');
}, 4000);
}
the div element that contains the map:
<div class="CenterRightColMap">
<div class="contentCC">
<div id="map" class="mapFullPage"></div>
</div>
</div>
Style:
div.mapFullPage
{
width:100%;
height:98%;
}
div.contentCC {
position:relative;
padding: 5px;
margin: 5px 5px 0px 5px;
border: 1px solid #000000;
/*background: #FFFFFF;
color: #666666;
font-family: Tahoma,Verdana,Helvetica,Helvetica-Narrow,sans-serif;*/
text-align:center;
height:100%
}
div.CenterRightColMap
{
position:absolute;
float: auto;
left:430px;
right:20px;
height:85%;
min-height:85%;
FONT-SIZE: 8pt;
background-color: #CECECE;
FONT-FAMILY: Verdana;
padding: 5px
}
Found the solution here : https://bugs.chromium.org/p/chromium/issues/detail?id=426294
Managed to fix it using adding the following style to the page
<style>.gm-style div > img {position: absolute;}</style>
Appears to be a bug from gm

get file object from called window javascript

I am trying to open a window and process the file in the calling JavaScript. I can pass the file name using localStorage but if I return the file I can't get it right.
I can't use this solution due to restrictions of the system I am calling the JavaScript from:
var fileSelector = document.createElement('input');
fileSelector.setAttribute('type', 'file');
fileSelector.click();
Can a file object be passed using localStorage or should I use another method?
My code is:
<!DOCTYPE html>
<html>
<script language="JavaScript">
function testInjectScript2(){
try {
var myhtmltext =
'<input type="file" id="uploadInput3" name=\"files[]" onchange=\'localStorage.setItem("myfile",document.getElementById("uploadInput3").files[0]);\' multiple />';
console.log("myhtmltext="+myhtmltext);
var newWin2 = window.open('',"_blank", "location=200,status=1,scrollbars=1, width=500,height=200");
newWin2.document.body.innerHTML = myhtmltext;
newWin2.addEventListener("unload", function (e) {
if(localStorage.getItem("myfile")) {
var f = localStorage.getItem("myfile");
alert ('in function.f='+f);
alert ('in function.f.name='+(f).name);
localStorage.removeItem("myfile");
}
});
} catch (err) {
alert(err);
}
}
</script>
<body>
<input type="button" text="testInjectScript2" onclick="testInjectScript2()" value="testInjectScript2" />
</body>
</html>
First of all, welcome to SO. If I get you right, you want to upload a file using a new window and get that file using localStorage onto your main page. This is a possible solution. However, please do also note that the maximum size of the localStorage can vary depending on the user-agent (more information here). Therefore it is not recommend to use this method. If you really want to do this, please have a look at the first snippet.
var read = document.getElementById("read-value"), open_win = document.getElementById("open-win"), win, p = document.getElementById("file-set");
open_win.addEventListener("click", function(){
win = window.open("", "", "width=200,height=100");
win.document.write(
'<input id="file-input" type="file"/>' +
'<script>' +
'var input = document.getElementById("file-input");' +
'input.addEventListener("change", function(){window.localStorage.setItem("file", input.files[0]);})'+
'<\/script>'
);
})
read.addEventListener("click", function(){
var file = window.localStorage.getItem("file");
if(file){
p.innerText = "file is set";
}else{
p.innerText = "file is not set";
}
})
<button id="open-win">Open window</button>
<br><br>
<!-- Check if file is set in localStorage -->
<button id="read-value">Check</button>
<p id="file-set" style="margin: 10px 0; font-family: monospace"></p>
<i style="display: block; margin-top: 20px">Note: This only works locally as SO snippets lack the 'allow same origin' flag. i.e. just copy the html and js into a local file to use it.</i>
However, why not use a more elegant solution:
Simply using a modal. When the input value changes you can simply close the modal and get the file value without all the hassle of a localStorage.
// Get the modal, open button and close button
var modal = document.getElementById('modal'),
btn = document.getElementById("open-modal"),
span = document.getElementById("close"),
input = document.getElementById("file-input"),
label = document.getElementById("input-label"), file;
// When the user clicks the button, open the modal
btn.addEventListener("click", function() {
modal.style.display = "block";
})
// When the user clicks on <span> (x), close the modal
span.addEventListener("click", function() {
modal.style.display = "none";
})
input.addEventListener("change", function(){
file = input.files[0];
modal.style.display = "none";
//Change value of the label for nice styling ;)
label.innerHTML = input.files[0].name;
//do something with your value
})
// When the user clicks anywhere outside of the modal, close it
window.addEventListener("click", function(event) {
if (event.target == modal) {
modal.style.display = "none";
}
})
.modal {
display: none; /* Hidden by default */
position: fixed; /* Stay in place */
z-index: 1; /* Sit on top */
padding-top: 10px; /* Location of the box */
left: 0;
top: 0;
width: 100%; /* Full width */
height: 100%; /* Full height */
overflow: auto; /* Enable scroll if needed */
background-color: rgb(0,0,0); /* Fallback color */
background-color: rgba(0,0,0,0.4); /* Black w/ opacity */
}
.modal h2 {
font-family: sans-serif;
font-weight: normal;
}
/* Modal Content */
.modal-content {
background-color: #fefefe;
margin: auto;
padding: 20px;
border: 1px solid #888;
width: 80%;
}
/* The Close Button */
.close {
color: #aaaaaa;
float: right;
font-size: 28px;
font-weight: bold;
}
.close:hover,
.close:focus {
color: #000;
text-decoration: none;
cursor: pointer;
}
/* Input styles, added bonus */
.file-input {
width: 0.1px;
height: 0.1px;
opacity: 0;
overflow: hidden;
position: absolute;
z-index: -1;
}
.file-input + label {
font-size: 1.25em;
font-weight: 700;
padding: 10px 20px;
border: 1px solid #888;
display: inline-block;
cursor: pointer;
font-family: sans-serif;
}
.file-input:focus + label,
.file-input + label:hover {
background-color: #f7f7f7;
}
<!-- Trigger/Open The Modal -->
<button id="open-modal">Open Modal</button>
<!-- The Modal -->
<div id="modal" class="modal">
<!-- Modal content -->
<div class="modal-content">
<span id="close" class="close">×</span>
<h2><i>Upload a file?</i></h3>
<input id="file-input" name="file-input" class="file-input" type="file"/>
<label id="input-label" for="file-input">Upload a file</label>
</div>
</div>
Hope it helps! Let me know!
Cheers!

Javascript: removeChild at certain screen size

I'm trying for hours now to add a wrapper around two divs (aside and .related) at a certain screensize (>60em and <90em). I'm doing this with matchMedia and an eventListener. The wrapper seems to be added at the right spot, but the problem is that it's still there even when the condition of the size is not met.
Here is a jsfiddle: http://jsfiddle.net/Vanilla__/4q26ngmg/1/
Simplified HTML:
<body>
<header>Header</header>
<main>Main</main>
<aside>Aside</aside>
<div class="related">Related</div>
<footer>Footer</footer>
</body>
Javascript:
if(window.matchMedia("screen and (min-width: 60em) and (max-width: 90em)").matches) {
window.addEventListener("resize", function addWrapper(q) {
//Create div with id wrapper
var div = document.createElement('div');
div.id = "wrapper";
// Select aside
var selectDiv = document.querySelector("aside");
//clone
div.appendChild(selectDiv.cloneNode(true));
//Place the new wrapper at the right place in the HTML
selectDiv.parentNode.replaceChild(div, selectDiv);
//Add related to the wrapper so they're both in the wrapper
document.querySelector('#wrapper').appendChild(
document.querySelector('.related') );
});
}
I wanted to add an 'else' to remove the child (with removeChild) or delete the eventListener (with removeEventListener) when there's another screen size, but all I get is errors about that the function is not definied or other errors whatever I try.
else {
window.removeEventListener("resize", addWrapper(q));
}
Does anyone know how the wrapper can be removed when the screensize is not >60em and <90em? I'm a Javascript rookie (as might be clear ;) ). Any help is appreciated.
You could do something like this:
var addWrapper = function () {
//Don't add wrapper if already added
var wrapper = document.getElementById("wrapper");
if (wrapper !== null) return;
//Create div with id wrapper
var div = document.createElement('div');
div.id = "wrapper";
// Select aside
var selectDiv = document.querySelector("aside");
//clone
div.appendChild(selectDiv.cloneNode(true));
//Place the new wrapper at the right place in the HTML
selectDiv.parentNode.replaceChild(div, selectDiv);
//Add related to the wrapper so they're both in the wrapper
document.querySelector('#wrapper').appendChild(
document.querySelector('.related'));
};
var removeWrapper = function () {
//Don't remove if there is no wrapper
var wrapper = document.getElementById("wrapper");
if (wrapper === null) return;
//Replace wrapper with its content
wrapper.outerHTML = wrapper.innerHTML;
}
var wrapperFixer = function () {
if (window.matchMedia("screen and (min-width: 60em) and (max-width: 90em)").matches) {
addWrapper();
} else {
removeWrapper();
}
}
window.onload = function () {
window.addEventListener("resize", wrapperFixer);
//Check and add if wrapper should be added on load
wrapperFixer();
}
body {
display: flex;
height: 40em;
flex-wrap: wrap;
font-family: Helvetica, Arial, sans-serif;
color: white;
text-align: center;
}
header {
background-color: purple;
width: 30%
}
main {
background-color: pink;
width: 40%
}
aside {
background-color: deepPink;
width: 15%
}
.related {
background-color: red;
width: 15%
}
footer {
background-color: slateBlue;
width: 100%;
height: 5em;
}
#wrapper {
border: 4px solid white;
}
<body>
<header>Header</header>
<main>Main</main>
<aside>Aside</aside>
<div class="related">Related</div>
<footer>Footer</footer>
</body>

styling host in custom element using javascript

I wrote the below code to get a shadow DOM with text and button, both text and button had been styled correctly, while the host background had been styled in a strange way,
the code is:
// Create a new object based of the HTMLElement prototype
var fonixDiv = Object.create(HTMLElement.prototype);
// Set up the element.
fonixDiv.createdCallback = function() {
// Create a Shadow Root
var shadow = this.createShadowRoot();
shadow.innerHTML = '\
<style>\
:host { \
border: 2px dashed red;\
text-align: left;\
font-size: 28px;\
background: blue;\
}\
h3 { color: red; }\
button { color: green; }\
</style>\
<h3>Shadow DOM</h3>\
<button id="d">click</button>\
';
shadow.children.d.addEventListener('click', function(e) {
this.textContent = "you clicked me :(";
shadow.children[1].textContent="Shadow DOM content changed";
host.style.background = "green";
alert("All: button, text and host should be change");
});
};
the output is in the attached.
any help pls.
I was able to solve the issue using css file:
the .html file is:
<fonix-div></fonix-div>
<div id="host1"></div>
the .js file is:
// Create a new object based of the HTMLElement prototype
var fonixDiv = Object.create(HTMLElement.prototype);
// Set up the element.
fonixDiv.createdCallback = function() {
// Create a Shadow Root
var shadow = this.createShadowRoot();
shadow.innerHTML = '<button id="d">click</button>';
shadow.addEventListener('click', function(e) {
console.log('1: '+this.host.dataset.disabled);
this.host.dataset.disabled='true'; // set Attribute to the custom element
});
shadow.children.d.addEventListener('click', function(e) {
this.textContent = "you clicked me :(";
shadow.children[1].textContent="Shadow DOM content changed";
this.disabled=true;
alert("All: button, text and host should be change");
});
};
// Register the new element.
var Xfonix =document.registerElement('fonix-div', {prototype: fonixDiv});
var thehost = document.querySelector('#host1');
thehost.appendChild(new Xfonix());
the .css file is:
body {background: #F7F7F7;}
fonix-div {
display: inline-block;
width: 200px;
height: 200px;
float: left;
margin: 0.5em;
border-radius: 3px;
background: #FFF;
box-shadow: 0 1px 3px rgba(0,0,0,0.25);
font-family: Helvetica, arial, sans-serif;
-webkit-font-smoothing: antialiased;
}
fonix-div:hover, fonix-div[data-disabled='true']:hover {background: red;}
fonix-div:Active {background: green;}
fonix-div[data-disabled='true'] {background: green;}
fonix-div::shadow p{color: blue;}
the output can be seen here:

Categories

Resources