Canvas Shadow DOM and Web Components - javascript

I am trying to make use of web components, templates and shadow DOM to create a canvas element. The problem is i cannot get the contex inside the prototype or I get this error when creating the shadow: HierarchyRequestError: Failed to execute 'createShadowRoot' on 'Element': Author-created shadow roots are disabled for this element.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<link rel="import" href="mycanvas.html">
</head>
<body>
<canvas is="my-canvas"></canvas>
</body>
</html>
<template id="mytemplate">
<style>
p {color:green;}
span {text-decoration: underline;}
canvas {background-color: #f00;
width:300px;}
</style>
</template>
<script>
(function() {
var myPrototype= Object.create(HTMLElement.prototype);
var myDocument=document.currentScript.ownerDocument;
myPrototype.createdCallback=function() {
var shadow= this.createShadowRoot();
var template=myDocument.querySelector("#mytemplate");
var clone= document.importNode(template.content, true);
shadow.appendChild(clone);
} //end prototype
var myCanvas= document.registerElement('my-canvas', {
prototype: myPrototype,
extends:'canvas'
});
}());
</script>

regardless of how I try to get the html canvas element ( with
getElementsByTagName or anythig else) it says getContext is not a
function
Try substituting HTMLCanvasElement.prototype for HTMLElement.prototype when defining myPrototype

Related

JS Return HTML Title as H1 Headline

first of all: I‘m not a coder!
I want to inject a dynamic h1 based on page title on a webpage.
Example: <title>Garden</title>
Now I need this as H1 class - I want to include this H1 after a given div class <div class="teaser"></div>
It is may totally simple and I already read some stuff but i don‘t get it…
Fairly trivial
window.addEventListener('DOMContentLoaded', function() {
const h1 = document.createElement('h1')
h1.innerHTML = document.title;
document.querySelector(".teaser").insertAdjacentElement("afterend", h1)
})
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Garden</title>
</head>
<body>
<div class="teaser">Teaser</div>
</body>
</html>

Making an Element draggable without ID

I'm trying to make divs created with .createElement be draggable. It works fine with divs that are already created like below:
<div>
This can be dragged around, but outputs cannot?!
</div>
but when I create new divs with the function addElement(), it doesn't work.
In more detail here is what my code aims to do:
user inputs text -> clicks input button and the user input(s) are outputted on the screen and can be dragged.
Full code:
function addElement () {
var text = document.getElementById("input").value;
// create a new div element
var newDiv = document.createElement("div");
// and give it some content
var newContent = document.createTextNode(text);
// add the text node to the newly created div
newDiv.appendChild(newContent);
// add the newly created element and its content into the DOM
var currentDiv = document.getElementById("div1");
document.body.insertBefore(newDiv, currentDiv);
document.getElementById("input").value = " ";
}
$( function() {
var div = document.getElementsByTagName('div');
$( div ).draggable();
} );
div { width: 150px; height: 150px; padding: 0.5em; }
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>repl.it</title>
<link href="style.css" rel="stylesheet" type="text/css" />
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<link rel="stylesheet" href="/resources/demos/style.css">
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
</head>
<body>
<input id="input"type="text" placeholder=" text">
<button onclick="addElement()" >Input</button>
<p>Outputs:</p>
<script src="script.js"></script>
</body>
</html>
<div>
This can be dragged around, but outputs cannot?!
</div>
</body>
</html>
When you load the page, the draggable gets attached to the div element which is already loaded. But when you dynamically create a new element, the draggable is not re-attached to the new div. So, whenever you add a new div, you need to re-attach the draggable event to it:
function addElement() {
var text = document.getElementById("input").value;
// create a new div element
var newDiv = document.createElement("div");
// and give it some content
var newContent = document.createTextNode(text);
// add the text node to the newly created div
newDiv.appendChild(newContent);
// add the newly created element and its content into the DOM
var currentDiv = document.getElementById("div1");
document.body.insertBefore(newDiv, currentDiv);
$(function() {
var div = document.getElementsByTagName('div');
$(div).draggable();
});
document.getElementById("input").value = " ";
}
$(function() {
var div = document.getElementsByTagName('div');
$(div).draggable();
});
div {
width: 150px;
height: 150px;
padding: 0.5em;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>repl.it</title>
<link href="style.css" rel="stylesheet" type="text/css" />
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<link rel="stylesheet" href="/resources/demos/style.css">
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
</head>
<body>
<input id="input" type="text" placeholder=" text">
<button onclick="addElement()">Input</button>
<p>Outputs:</p>
<script src="script.js"></script>
</body>
</html>
<div>
This can be dragged around, but outputs cannot?!
</div>
</body>
</html>
When you load the page, the draggable gets attached to the div element which is already loaded. But when you dynamically create a new element, the draggable is not attached to the new div. Whenever you add a new div, you need to re-attach draggable event to it.
You only run
$( function() {
var div = document.getElementsByTagName('div');
$( div ).draggable();
} );
when your app loads for the first time, therefore newly created divs are not draggable.
When you want the new divs to be draggable, you have to add $( newDiv ).draggable() to your addElement() function.
You are using $(callback), which only calls the function once when the DOM is loaded.
However, when you add new elements, they will not be made draggable since the function that does it has already run.
To make the new elements draggable too, you will need to call jQuery.draggable() on them as well after creating them.
This means, you should add newDiv.draggable() inside your function that creates the elements.
Sidenote
When using an API like jQuery, you should try to stick to it rather than the native methods to make understanding it easier, since one wouldn't have to go back and forth in their mindsets.
Subnotes
You have incorrect HTML since you have a <div> after closing both <body> and <html>, and are trying to close them again at the end. Since HTML disallows elements outside of <body>, most browsers automatically correct this mistake. However, you should format the HTML correctly yourself.
Creating jQuery-elements using $(document.createElement('div')) instead of using $('<div>') is (minimally) faster, hence I use it below
Do not add the onclick-listener in the HTML, instead, add it using JavaScript. Adding the listener inline would require the function to be exposed in the global scope, and would pollute the global namespace. Listeners do not require to be named, and can easily be added in JS, allowing to not expose the functions to the global scope.
Making your code use mostly jQuery would make it look like this:
$(function() { // Executed once DOM loaded
// Make all pre-existing 'div's draggable
$('div').draggable();
// Add the 'onclick'-listener using jQuery
$('button').click(function() {
// Creating jQuery-element this way; read about the reason in the sub-notes
var newDiv = $(document.createElement("div"));
newDiv.text($('#input').val()); // Set the text to the value of 'input'
newDiv.draggable(); // Make it draggable
$('body').append(newDiv); // Append it to the body
$('#input').val(''); // Set 'input's value to ""
});
});
div {
width: 150px;
height: 150px;
padding: 0.5em;
}
<!DOCTYPE html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
</head>
<body>
<input id="input" type="text" placeholder="text">
<button>Input</button>
<p>Outputs:</p>
<div>
This can be dragged around, but outputs cannot?!
</div>
</body>
</html>

js: element.className does not work (create a dark mode)

I want to change the css properties of many html objects (but in this example I only took body to simplify. My goal is to display dark mode if the current mode is light, or display light mode if current mode is dark.
My javascript function does not work.
debug.html:
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="debug.css">
<script src="darkmode.js"></script>
</head>
<body id="bodyElem" class="my-body light-mode">
<h1>Settings</h1>
<p>Dark mode:</p>
<button type="button" onclick="invertMode()">click</button>
</body>
</html>
debug.css:
.my-body.light-mode{
background-color: yellow;
}
.my-body.dark-mode{
background-color: black;
}
darkmode.js:
function invertMode() {
var body = document.getElementById("bodyElem");
var currentClass = body.className;
body.className = currentClass == "dark-mode" ? "light-mode" : "dark-mode";
}
You will need to add an ID for the <body> tag to be able to find it using your code.
<body id="bodyElem" class="light-mode">
and access it using:
var body = document.getElementById("bodyElem");
If you need to access mutiple elements, you can use their CSS class name like:
document.getElementsByClassName("CLASSNAMEHERE");
then loop them all to apply the changes you need.
you will be using .classList.remove("CLASSNAME") to remove single class and .classList.add("CLASSNAME") to add single class to DOM element
Here is a complete sample fiddle:
https://jsfiddle.net/j3o8Lt5k/1/

how to get the cssText of external style?

I have tried hours to get the results, but failed, below, I will post all I have done, hope I can get some tips, BTW,Thanks.
from the error message, yeah It's cssRules is null, surely error!
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="index.css">
<title>css style</title>
<style type="text/css">
#demo {
font-size: 10px; /*first css rule */
}
p {
border: 1px solid green; /*second one*/
}
</style>
</head>
<body>
<div id="demo" style="color: red;">
<p>how to access of document's css!</p>
</div>
</body>
external css
#demo {
font-weight: 900;
}
p {
padding: 20px;
}
Javascript
<script>
/*1,to get the inline style, this maybe the most easy one*/
var cssInline = document.getElementById('demo').style;
var cssInText = cssInline.cssText, cssColor = cssInline.color;
console.log(cssInText, cssColor);
/*2.a to get the style in head*/
var cssInHeada = document.getElementById('demo');
// using the computed css of inline
var cssHeadText = getComputedStyle(cssInHeada, null);
console.log(cssHeadText);
// 2.b to get the style directly
var cssInHeadb = document.getElementsByTagName('style')[0];
console.log(cssInHeadb.textContent);
// 2.c or like this
var cssInHeadc = document.styleSheets[1];
console.log(cssInHeadc.cssRules[0].cssText); //per rule
/*3, but I cant get the extenal style*/
var cssExtenal = document.styleSheets[0];
console.log(cssExtenal.cssRules[0].cssText);
</script>
Thank your guys!
I suspect your JavaScript is running before the stylesheet is loaded. Try this:
document.addEventListener('DOMContentLoaded', function () {
var cssExtenal = document.styleSheets[0];
console.log(cssExtenal.cssRules[0].cssText);
}, false);
Or if you happen to be using jQuery, this is more universal:
$('document').ready(function(){
var cssExtenal = document.styleSheets[0];
console.log(cssExtenal.cssRules[0].cssText);
});
Update: another possibility is that you're using Chrome and either loading the CSS cross-domain or using the file:// protocol. This appears to be a known issue and is not considered a bug.

Should I write an implementation of a custom element whithin <body>?

Like the below code, the implementation of a custom element is imported.
And is naked, which means, the imported document has no body and head.
index.html
<!DOCTYPE html>
<html>
<head>
<title></title>
<link rel="import" href="html/demo-element.html">
</head>
<body>
<demo-element>hello world</demo-element>
</body>
</html>
demo-element.html
<template>
<style type="text/css">
div {
background-color: #F2CEE5;
padding: 10px;
}
</style>
<div>
<content></content>
</div>
</template>
<script type="text/javascript">
(function() {
var thisDoc = document.currentScript.ownerDocument;
var proto = Object.create(HTMLElement.prototype, {
createdCallback: {
value: function() {
var t = thisDoc.querySelector('template');
var clone = document.importNode(t.content, true);
this.createShadowRoot().appendChild(clone);
}
}
});
var element = document.registerElement('demo-element', {
prototype: proto
});
})();
</script>
I want you see the below which is the result which chrome dev tool shows.
The imported document has head and body and the implementation is in head somehow.
I want to know if this is common or I should write head and body in demo-element.html and put the implementation in the body.

Categories

Resources