I'm building a simple one page app using Polymer. I have created a custom element that contains the Polymer-drag-drop demo. The action of dragging and creating a div works fine, the event object's relatedTarget property holds a reference to the correct drop div. The problem is the srcElement and target property both hold references to the shadowRoot parent polymer element, in this case "workspace-drop".
EDIT:
Logging event.currentTarget on fire also contains a reference to the parentDiv holding the colored children. <div flex horizontal style="border: 1px dotted silver;">
Code is as follows (pretty much the demo but in a polymer element):
<link rel="import" href="/components/polymer/polymer.html">
<script src="/components/webcomponentsjs/webcomponents.js">
</script>
<link rel="import" href="/components/core-drag-drop/core-drag-drop.html">
<polymer-element name="workspace-drop">
<template>
<style>
html {
font-family: 'Helvetica Neue', 'Roboto', 'Arial', sans-serif;
}
body {
height: 100vh;
margin: 0;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
}
.box {
display: inline-block;
width: 100px;
height: 100px;
margin: 16px;
}
.dropped {
position: absolute;
border: 1px solid black;
width: 5px;
height: 5px;
}
</style>
<div flex horizontal style="border: 1px dotted silver;">
<core-drag-drop></core-drag-drop>
<div class="box" style="background-color: lightblue;" draggable="false"></div>
<div class="box" style="background-color: orange;" draggable="false"></div>
<div class="box" style="background-color: lightgreen;" draggable="false"></div>
<div id="hello">Hello World</div>
</div>
<div id="drop" hash="test" class="box" style="border: 3px solid silver; position: relative; width: 300px; height: 300px;" draggable="false"></div>
</template>
<script>
(function(){
addEventListener('drag-start', function(e) {
var dragInfo = e.detail;
// flaw #2: e vs dragInfo.event
console.log(e.detail);
var color = dragInfo.event.target.style.backgroundColor;
dragInfo.avatar.style.cssText = 'border: 3px solid ' + color + '; width: 32px; height: 32px; border-radius: 32px; background-color: whitesmoke';
dragInfo.drag = function() {};
dragInfo.drop = drop;
});
//
function drop(dragInfo) {
var color = dragInfo.avatar.style.borderColor;
var dropTarget = dragInfo.event.relatedTarget;
if (color && dropTarget.id === 'drop') {
var f = dragInfo.framed;
var d = document.createElement('div');
d.className = 'dropped';
d.style.left = f.x - 4 + 'px';
d.style.top = f.y - 4 + 'px';
d.style.backgroundColor = color;
dropTarget.appendChild(d);
dropTarget.style.backgroundColor = color;
}
}
Polymer({
ready: function(){
}
});
})();
</script>
</polymer-element>
Any assistance is appreciated!
Figured it out. It is related to this question.
When loggin an event object, currentTarget is null, but when logging event.currentTarget it logs a value. Why is that?
Logging the event after the drag action has completed returns a reference to the object in its completed state. Logging the specific event.target property on drag-start gave reference to the correct object, on start.
Related
I am trying to get a div by id, and adding an event listener to that div, in my case i am trying to implement a simple mouseover event. I am trying to create a new div element and in that element add a new class called vehicles, after adding className vehicles i am trying to modify the style attribute of width to 100px, the code provided is only for practice purposes even if it does not make sense in real life.
const myDiv = document.getElementById("div-1");
myDiv.addEventListener("mouseover", function(event) {
const newDiv = document.createElement("div");
newDiv.classList.add('vehicles');
const vehicles = document.getElementsByClassName("vehicles")[0];
vehicles.setAttribute("style", "width: 100px");
});
#div-1 {
background-color: red;
color: yellow;
width: 20px;
}
.vehicles {
border: solid 2px black;
background-color: blue;
width: 20px;
}
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>test</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div id="div-1">
<p>This is a test</p>
</div>
</body>
</html>
You need to append the new created elements and then it will work:
const myDiv = document.getElementById("div-1");
myDiv.addEventListener("mouseover", function(event) {
const newDiv = document.createElement("div");
newDiv.classList.add('vehicles');
myDiv.append(newDiv); // append the new created div
const vehicles = document.getElementsByClassName("vehicles")[0];
vehicles.setAttribute("style", "width: 100px");
});
#div-1 {
background-color: red;
color: yellow;
width: 20px;
}
.vehicles {
border: solid 2px black;
background-color: blue;
width: 20px;
}
<div id="div-1">
<p>This is a test</p>
</div>
EDIT (comments):
const myDiv = document.querySelector("#div-1"); // use the modern way to select element(s)
myDiv.addEventListener("mouseover", function(event) { // this is your original code
const newDiv = document.createElement("div"); // this is also your original code
newDiv.setAttribute("style", "width: 100px; background: black; height: 1em;"); // instead of adding class and manipulate it you can set the desired property via inline style
myDiv.append(newDiv); // append the new created div
});
#div-1 {
background-color: red;
color: yellow;
width: 20px;
}
<div id="div-1">
<p>This is a test</p>
</div>
You have just created a new element. You must add this element to the DOM tree.
For example,
document.body.appendChild(newDiv);
I am trying to build a grid to run directly with hardware connected to a raspberry pi. On the client side, I am trying to have a button that saves the current "frame" of the grid. I'd like for this button to just gather the CSS color values (in hexadecimal form) and form an array with them, but everything I have tried hasn't worked as of yet.
I am aware of the 'style' and 'computedStyles' methods in javascript, and these may be part of the key to the question, but I'm not sure. My hunch is that the issue lies within state.
<div id="palette">
<div
class="pen"
style="background-color: #ffffff;"
onclick="setPenColor('#ffffff')"
></div>
<--- Yadayada more 'pens' -->
<div id="art">
<div class="row">
<div class="pixel" onclick="setPixelColor(this)"></div>
<div class="pixel" onclick="setPixelColor(this)"></div>
<div class="pixel" onclick="setPixelColor(this)"></div>
<div class="pixel" onclick="setPixelColor(this)"></div>
<--- Javascript -->
var penColor = 'black';
function setPenColor(pen) {
penColor = pen;
}
function setPixelColor(pixel) {
pixel.style.backgroundColor = penColor;
}
var element = document.getElementById('pixel');
var out = '';
var elementStyle = element.style;
var computedStyle = window.getComputedStyle(element, null);
for (prop in elementStyle) {
if (elementStyle.hasOwnProperty(prop)) {
out +=
' ' +
prop +
" = '" +
elementStyle[prop] +
"' > '" +
computedStyle[prop] +
"'\n";
}
}
console.log(out);
<-- CSS -->
#art {
display: table;
border-spacing: 1px;
background-color: black;
border: 5px solid black;
}
.row {
display: table-row;
}
.pixel {
display: table-cell;
background-color: white;
width: 25px;
height: 25px;
}
.pen {
display: inline-block;
width: 35px;
height: 35px;
border: 2px solid black;
border-radius: 50%;
}
My current output just gives me an error message:
Uncaught TypeError: Cannot read property 'style' of null
at grid.js:24
Like I said, I'd like to form an array of the hexadecimal values, but accessing them properly has become my first priority now.
Thanks much for any help! :)
I'm sure this has been asked before, but I haven't had any luck finding an answer. There's probably a term for this which I don't know.
Can a jQuery event handler return an element other than the one from which it was triggered?
Normally, when you trigger a jQuery event for an element, that element will be returned by the event handler. Is there a way to return a different element instead? (other than event.target, event.currentTarget, etc.)
Here's my HTML:
<div id="content">
<div id="wrapper">
<div class="instance">
</div>
</div>
</div>
If I make a custom jQuery event for #wrapper, can I make its event handler return an .instance?
Here's my JavaScript:
$('#content').on('new.instance', '#wrapper', function(event) {
var wrapper = $(event.currentTarget);
var instance = wrapper.find('div.instance').first();
var newInstance = instance.clone(true, true);
newInstance.appendTo(wrapper);
return newInstance;
});
var returnValue = $('#wrapper').trigger('new.instance');
console.log('returnValue.html():', returnValue.html()); // #wrapper, not .instance
Can I make the new.instance event handler return an .instance element? If so, what am I missing in the code?
.trigger()
...
When we define a custom event type using the .on() method, the second argument to .trigger() can become useful.
You could simply add an object to the .trigger method as a second parameter and collect your instances in there.
var instances = {data:[]};
$('#content').on('new.instance', '#wrapper', function(event, instances) {
var wrapper = $(event.currentTarget);
var instance = wrapper.find('div.instance').first();
var newInstance = instance.clone(true, true);
instances.data.push(newInstance);
newInstance.appendTo(wrapper);
});
$('#wrapper').trigger('new.instance', instances);
console.log(instances.data[0].get(0));
// somewhere else at a latter time trigger new.instance again
setTimeout(function() {
$('#wrapper').trigger('new.instance', instances);
$.each(instances.data, function(index, item) {
var counter = index + 1
item.text( 'cloned instance ' + counter );
console.log(item.get(0))
})
}, 2000)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="content">
<div id="wrapper">
<div class="instance"></div>
</div>
</div>
.instance is in the event.chain so you can access it on callback during the bubbling phase. Review the Snippet by clicking each element.
Snippet
var wrp = document.getElementById('wrapper');
wrp.addEventListener('click', function(e) {
if (e.target != e.currentTarget) {
var trueTarget = e.target.className;
alert(trueTarget + ' has been clicked!');
}
e.stopPropagation();
}, false);
#content {
border: 2px dashed grey;
width: 50vw;
height: 50vh;
background: rgba(0, 0, 0, .3);
text-align: right;
color: white;
}
#wrapper {
border: 3px dotted orange;
background: rgba(0, 0, 0, .5);
width: 50%;
height: 50%;
text-align: right;
font-size: small;
color: orange;
}
.instance {
border: 1px solid yellow;
width: 50%;
height: 50%;
background: rgba(0, 0, 0, .7);
text-align: center;
font-size: smaller;
color: yellow;
}
<div id="content">
CONTENT
<div id="wrapper">
WRAPPER
<div class="instance">
INSTANCE
</div>
</div>
</div>
I have a function that alters the size of a div when I click on it. Now I have to write the onclick command in my html page, but I want it to stand in the extern .js file.
Now in html:
<div id="box1" class="kaesten" onclick="changeSize('box1')"> Title 1 </div>
What I want:
<div id="box1" class="kaesten" > Title 1 </div>
Tried something in jquery but it didn't work:
function changeSize(id) {
var elem = document.getElementById(id);
var currentAbsoluteElem = document.getElementById('dummy');
var text = elem.innerHTML;
currentAbsoluteElem.innerHTML = text;
currentAbsoluteElem.setAttribute('style', 'display:block');
/*Extra styling neeed to be done here*/
}
var elems = document.getElementsByClassName('kaesten');
for (var i = 0; i < elems.length; i++) {
elems[i].onclick = function() {
changeSize(this.id);
}
}
var absoluteCl = document.getElementsByClassName('absoluteclass');
absoluteCl[0].onclick = function() {
console.log(document.getElementsByClassName('absoluteclass'))
document.getElementsByClassName('absoluteclass')[0].setAttribute('style', 'display:none');
}
$(document).ready(function() {
$('.kaesten').click(function() {
changeSize($(this).attr('id'));
});
});
.kaesten {
width: 240px;
height: 300px;
background-color: darkgrey;
background-position: center;
background-repeat: no-repeat;
text-shadow: 0px 0px 3px #000;
border: 5px solid #F0F8ff;
vertical-align: top;
text-shadow: 3px 3px 4px #777;
float: left;
margin-left: 30px;
}
.absoluteclass {
position: absolute;
background-color: darkgrey;
width: 600px;
height: 600px;
left: calc(30%);
display: none;
}
<div id="box1" class="kaesten">title1</div>
<div id="box2" class="kaesten">title2</div>
<div id="box3" class="kaesten">title3</div>
<div id="box4" class="kaesten">title4</div>
<div id="dummy" class="absoluteclass"></div>
I know it works in the fiddle, but I don't know why it doesn't work on my homepage without writing the function in the div's.
I guess the problem is that you are trying to assign the onclick event handler before the DOM is actually rendered and ready. My suggestion is to wrap your "initialization code" inside a $(document).ready() method. As follows:
$(document).ready(function() {
// Apply the on click event handlers here, using jQuery or not
// For instance:
$('.kaesten').click(function() {
changeSize($(this).attr('id'));
});
});
if you want to pass the id from jquery to your function you should do it like this:
$(function(){
$(".kaesten").click(function(){
changeSize($(this).attr("id"));
});
});
you can use .css in jquery
$(function(){
$(".kaesten").click(function(){
$(this).css({'width' : '600px' , 'height' : '600px'});;
});
});
I am new to JavaScript/CSS (basically the whole world of web dev) and I am really struggling to create the following widget. I created a picture of what I want to make to make it more clear.
The Play/Pause and Stop button are ready. Loop checkbox is no problem. But the progress bar is painful. The two markers are supposed to mark the point from where the file would start playing and where it would stop. The progress bar is also supposed to be click-able, so if I want to access a certain point in time, then its possible.
What I tried so far
jQuery UI slider: For a sliding progress bar and use that draggable slider to access a certain point in audio file. Works fine. But no markers and looks really ugly. Don't how to change it.
<progress> tag: not very flexible. Marker? Clicking?
<div> tag: there seems to be no way to get the point where I clicked.
So, what do you guys recommend? How should I proceed?
Canvas Alternative
You might want to use a canvas and draw your own progress bar element within it.
Here are some canvas progress bar tutorials:
How to create a progress bar with HTML5
A progress bar using HTML5 canvas
Doing it with <progress>
To access the clicked position within a DOMElement, you can proceed with the click event's properties: clientX and clientY (MDN Source), like so:
HTML
<div class="marker" id="StartMarker">^</div>
<div class="marker" id="StopMarker">^</div>
<progress id="progress" value="0" min="0" max="100">0%</progress>
<form id="choice">
<button id="marker1">Beginning marker</button>
<button id="marker2">Ending marker</button>
<input type="hidden" id="markerValue" value="0" />
</form>
JavaScript (not optimized)
document.getElementById('progress').onclick = function (event, element) {
/* Math.floor((event.offsetX / this.offsetWidth) * 100) */
var newProgress = event.offsetX;
document.getElementById('choice').style.display = "block";
document.getElementById('markerValue').setAttribute('value', newProgress);
document.getElementById('marker1').onclick = function (event) {
event.preventDefault();
var newProgress = document.getElementById('markerValue').value;
var progressBar = document.getElementById('progress');
var startMarker = document.getElementById('StartMarker');
var stopMarker = document.getElementById('StopMarker');
var marker = startMarker;
marker.style.display = "block";
startMarker.style.display = "block";
startMarker.offsetTop = (progressBar.offsetTop + progressBar.offsetHeight + 2) + "px";
startMarker.style.left = newProgress + "px";
};
document.getElementById('marker2').onclick = function (event) {
event.preventDefault();
var newProgress = document.getElementById('markerValue').value;
var progressBar = document.getElementById('progress');
var startMarker = document.getElementById('StartMarker');
var stopMarker = document.getElementById('StopMarker');
stopMarker.style.display = "block";
stopMarker.offsetTop = (progressBar.offsetTop + progressBar.offsetHeight + 2) + "px";
stopMarker.style.left = newProgress + "px";
};
};
CSS
.marker {
position:absolute;
top:24px;
left:9px;
display:none;
z-index:8;
font-weight:bold;
text-align:center;
}
#StartMarker {
color: #CF0;
}
#StopMarker {
color:#F00;
}
#choice {
display:none;
}
progress {
display: inline-block;
-moz-box-sizing: border-box;
box-sizing: border-box;
width: 300px;
height: 20px;
padding: 3px 3px 2px 3px;
background: #333;
background: -webkit-linear-gradient(#2d2d2d, #444);
background: -moz-linear-gradient(#2d2d2d, #444);
background: -o-linear-gradient(#2d2d2d, #444);
background: linear-gradient(#2d2d2d, #444);
border: 1px solid rgba(0, 0, 0, .5);
border-radius: 15px;
box-shadow: 0 1px 0 rgba(255, 255, 255, .2);
}
Live Demo
Using simple blocks for that is possible. Your layout would look like this (simplified):
HTML
<div class="progressbar">
<div class="bar">
<div class="progress" style="width: 30%;">
</div>
</div>
<div class="markers">
<div class="right" style="width: 70%;">
<div class="marker">
</div>
<div class="left" style="width: 20%;">
<div class="marker">
</div>
</div>
</div>
</div>
</div>
SCSS
.progressbar {
width: 20em;
background: grey;
.bar {
height: 2em;
.progress {
background: blue;
height: 100%;
}
}
.markers {
height: 1em;
background: white;
.right {
height: 100%;
background: red;
.marker {
width: 1em;
height: 100%;
background: green;
position: relative;
float: right;
}
.left {
background: white;
height: 100%;
}
}
}
}
The operations can be quite difficult
jQuery
$('.bar').click(function(e){
$(this).find('.progress').css('width', (e.offsetX / this.offsetWidth)*100+'%');
});
will set the Progressbar properly on clicks.
For the markers though you will need mousedown, mousemove, mouseleave events, since you got 2 of them.
Example
http://jsfiddle.net/JXauW/