Seelcting audio elements using classes and playing them - audio

I have sound clip registered in html:
<audio class="aaa" id="sss"><source src="url/sound.wav"/></audio>
<script type="text/javascript">var sss = document.getElementById("sss"); sss.volume='0.1';</script>
This sound can be played with mouseenter event on the certain div:
$('#divid').mouseenter(function () {
$(sss.play());
});
How can this be achieved with audio class instead of id?
edit: solved

.play() is a method of the HTMLAudioElement object not the jQuery object, jQuery wrapper doesn't do anything here, as you are passing retuned value of the .play() method to it, you can select the element(s) using jQuery, gets DOM element object(s) from the collection and call the .play() method on it:
$('audio.aaa').get(0).play(); // works for the first matched element in the collection
If there are several elements, you can iterate through the collection using .each() method:
$('audio.aaa').each(function() {
// `this` keyword here refers the HTMLAudioElements
this.foo();
});

Related

How to access getbbox on a svg element in a cypress test

I have a SVG which includes text elements. I can get the text of the elements in my cypress test, but when I try to call getbbox() I get the error 'TypeError: text.getBBox is not a function'. If I understand correctly cypress is returning text as a htmlELement, and I need an SVGElement to call getbbox() on, but whats best practice to do that in the context of a cypress test?
cy.get('svg#osmdSvgPage1').get("text").each(textElement => {
var text = textElement.text(); //successful
//do some stuff
var bbox = textElement.getbbox(); //throws 'TypeError: text.getBBox is not a function'
//do more stuff
});
WRT to getBBox(), it must be called on the native SVGGraphicsElement, but you have called it on the jQuery object passed into .each().
Just add an index like this to unwrap the jQuery object:
var bbox = textElement[0].getBBox()
WRT cy.get('svg#osmdSvgPage1').get("text") I think you want this instead
cy.get('svg#osmdSvgPage1').find("text")
assuming the text elements are within the svg.
If there's only one svg, you can just use
cy.get("text")
but if there are several svg on the page cy.get('svg#osmdSvgPage1').get("text") will return all the text from all svg, because .get("text") scans the whole page by default.

Why is JSON.stringify needed to retain an object's value when importing it from node.js into an EJS template?

Environment: Node.js, Express, EJS
When JSON.stringify() is used to process objects passed from node.js to an EJS template the objects retain their original values. Although it works I find this result unexpected. JSON.stringify turns objects into strings. Why does this appear to work in reverse in this instance?
In the Node.js file:
app.get('/', function(req, res) {
let myArray = [1, 5];
let myObject = {
cats: 2,
dogs: 0
}
res.render('index', { myArray, myObject });
})
EJS:
<script>
let importedArray = <%- JSON.stringify(myArray) %>;
let importedObject = <%- JSON.stringify(myObject) %>;
</script>
Rendered version in browser:
Although I find this result unexpected it works perfectly fine.
<script>
let importedArray = [1,5];
let importedObject = {"cats":2,"dogs":0};
</script>
Rendered after both JSON.stringify() are removed in EJS file:
The values are lost and the browser throws an error. I would have thought the unescaped output tag <%- would be enough but it's not.
<script>
let importedArray = 1,5;
let importedObject = [object Object];
</script>
Because when you're trying to specify the source code for a script that will live inside a <script> tag inside a web page, you need to generate RAW Javascript source code that will make your object in the web page.
So, you need some method of turning your live server-side Javascript object back into Javascript source code that describes the same object. JSON.stringify() is one such way to generate that Javascript source.
If you don't use something like JSON.stringify() and just pass your actual Javascript object, the EJS will see that it's not a string and it will call obj.toString() on it to try to get a string representation of it. Unfortunately, the implemention of .toString() for a Javascript object just generates "[object Object]" which is completely useless in an EJS template. So, you can't do it that way - you have to manually generate the correct Javascript source code string. And, JSON.stringify() is one such way to do that.
because ejs only render string text, and when use toString on a json, it will get '[object Object]' instead of your real content

Set and get data like a raphaelJS

I'm working with RaphaelJS.
I've noticed that you can add dynamic data to the elements, for example:
to assign a value:
el.data("key",value);
to get a value:
el.data("key")
How can I copy this behaviour using JQuery or Javascript?
Hi I'm trying a wild guess here: as I understand correctly you'd like to communicate from Rapahel to jQuery.
The best I've come up so far is to keep references of both and use them accordingly as Raphael seems not to insert data into dom directly (apart from ID attribute):
$(document).ready(function () {
var paper = Raphael("div", 400, 150);
var circle = paper.circle(80, 80, 30).data('title', 'Red dot').attr({
fill: '#f00'
});
circle.node.id = 'my_circle';
$el_circle = $(circle[0]); // get DOM element out of Rapahel's object
$el_circle.on('click', function () {
// use Raphael reference:
alert("My is title: " + circle.data('title'));
});
});
http://jsfiddle.net/saxxi/Z35NV/
References.
the possibilities: raphael.js - custom attributes
the explanation: Where does Raphael.js store an element's data that is set with the element.data() method?
Combining Raphael and jQuery to achieve browser compatibility

Reinitialize SVGweb for ajax

I have no problem using SVGweb when page is simply loaded (opened).
How is it possible to reinitialize SVGweb in order to redraw all SVG on the page?
Anotherwords I need SVGweb to rescan and rerender everything on the page.
source (from this):
<script type="image/svg+xml">
<svg>
...
</svg>
</script>
to this (like SVGweb si doing that when simply open the page):
<svg>
...
</svg>
I need this because I change the SVG graphics using ajax and need to rerender it on the page.
I needed the same capability and figured out how to do this properly without modifying the svgweb source or calling the _onDOMContentLoaded() handler manually. In fact, it is supported natively.
The trick is to (re)attach your SVG elements to the DOM using window.svgweb.appendChild() which causes the node to be processed by svgweb, as is documented within the svgweb manual.
Example, using jQuery:
// Iterate over all script elements whose type attribute has a value of "image/svg+xml".
jQuery('body').find('script[type="image/svg+xml"]').each(function () {
// Wrap "this" (script DOM node) in a jQuery object.
var $this = jQuery(this);
// Now we use svgweb's appendChild method. The first argument is our new SVG element
// we create with jQuery from the inner text of the script element. The second
// argument is the parent node we are attaching to -- in this case we want to attach
// to the script element's parent, making it a sibling.
window.svgweb.appendChild(jQuery($this.text())[0], $this.parent()[0]);
// Now we can remove the script element from the DOM and destroy it.
$this.remove();
});
For this to work properly I suggest wrapping all SVG script tags with a dedicated div, so that when attaching the SVG element it is attached to a parent element containing no other nodes. This removes the possibility of inadvertently reordering nodes during the process.
After the DOM is changed with a new SVGweb code (through Ajax)
<script type="image/svg+xml">
<svg>
...
</svg>
</script>
need to execute this:
svgweb._onDOMContentLoaded();
But before need to comment a line in the core source of SVGweb svg-uncompressed.js or svg.js
svg-uncompressed.js
from
if (arguments.callee.done) {
return;
}
to
if (arguments.callee.done) {
//return;
}
svg.js: find and delete this:
arguments.callee.done=true;
or replace with
arguments.callee.done=false;
EDIT:
One more fix to work for IE9:
for svg.js
from
var a=document.getElementById("__ie__svg__onload");if(a){a.parentNode.removeChild(a);a.onreadystatechange=null}
to
var IEv=parseFloat(navigator.appVersion.split("MSIE")[1]);if(IEv<9){var a=document.getElementById("__ie__svg__onload");if(a){a.parentNode.removeChild(a);a.onreadystatechange=null;a=null;}}
for svg-uncompressed.js
from
// cleanup onDOMContentLoaded handler to prevent memory leaks on IE
var listener = document.getElementById('__ie__svg__onload');
if (listener) {
listener.parentNode.removeChild(listener);
listener.onreadystatechange = null;
listener = null;
}
to
// cleanup onDOMContentLoaded handler to prevent memory leaks on IE
var IEv=parseFloat(navigator.appVersion.split("MSIE")[1]);
if (IEv<9) {
var listener = document.getElementById('__ie__svg__onload');
if (listener) {
listener.parentNode.removeChild(listener);
listener.onreadystatechange = null;
listener = null;
}
}

How to bind an event to an element in a chrome extension popup window

I've searched quite a bit, and none of the answers I've found have worked 100%.
Basically, I want the popup to show a handful of buttons, then call the same function with different parameters. Concept:
<button onclick="foo(1,2);">Button 1</button>
<button onclick="foo(2,3);">Button 2</button>
I've tried a few simple and direct methods, none of which work. If I take the code out of the function, and have popup.js contain the code, it works (my function is fine).
I've tried:
$('#btn1').click(function(e) {
alert('btn1');
});
as well as
document.getElementById('btn1').addEventListener('click',doSomething(1,2));
Also, i've tried adding the button addEventListener inside of a document.addEventListener('DOMContentLoaded', function() {....});
The curious part is that if my popup.js contains button.addEventListener, the first one is fired upon clicking the browser action, and then nothing works. This happens regardless of whether the click event listner is inside of a DOMContentLoaded listener or not.
I have a feeling this is a CSP issue, but I can't seem to get it to work.
For those scanning for a question mark:
From within a popup.html/popup.js, how can I call a single function with different parameters based on an onclick event?
Issues
I'm not sure if it was just through your abbreviation when copying to SO but none of the code you have given would work "as pasted":
You have no id's on the buttons so binding to the id (I assume this is just because they weren't relevant in the first paste!)
The second paste uses the jQuery library and so you would need to make sure jQuery is included and allowed: https://stackoverflow.com/a/10928761/969807
In the third paste, the second parameter of addEventListener should be a function accepting the event as the first and only parameter (if wanted). (Read On)
Solution
The most common way to bind an event in the scenario you describe would be like so:
document.getElementById('btn1').addEventListener('click', function (){
foo(1, 2);
}, false);
However if there were a lot (or a variable amount) of buttons, I would probably do it like so:
popup.html:
<div id="buttons">
<button data-param1="1" data-param2="2">Button 1</button>
<button data-param1="2" data-param2="3">Button 2</button>
</div>
popup.js:
var els = document.querySelectorAll('#buttons button'),
i, total, param1, param2;
for (i = 0, total = els.length; i < total; i++) {
el = els[i];
param1 = parseInt(el.getAttribute('data-param1'));
param2 = parseInt(el.getAttribute('data-param2'));
el.addEventListener('click', function (){ foo(param1, param2) }, false);
}

Resources