Capturing images from HTML page in array using javascript - javascript

I'm trying to capture all images in an HTML page using Javascript. I found this similar question, the best answer to which gives in excellent detail a solution to the problem:
Detect all images with Javascript in an html page
My question is that I can't get the code shown in the best answer to run without error - even when I copy/paste directly into the Firefox console. I suspect the answer is straightforward, though it's had me scratching my head for hours - is anyone able to help please?
This code gives me the error "SyntaxError: missing ) after argument list"...
var elements = document.body.getElementsByTagName("*");
Array.prototype.forEach.call( elements, function ( el ) {
var style = window.getComputedStyle( el, false );
if ( style.backgroundImage != "none" ) {
images.push( style.backgroundImage.slice( 4, -1 ).replace(/['"]/g, "")
}
}
The full solution, which seems to include the above, also appears to give the same error...
var images = [],
bg_images = [],
image_parents = [];
document.addEventListener('DOMContentLoaded', function () {
var body = document.body;
var elements = document.body.getElementsByTagName("*");
/* When the DOM is ready find all the images and background images
initially loaded */
Array.prototype.forEach.call( elements, function ( el ) {
var style = window.getComputedStyle( el, false );
if ( el.tagName === "IMG" ) {
images.push( el.src ); // save image src
image_parents.push( el.parentNode ); // save image parent
} else if ( style.backgroundImage != "none" ) {
bg_images.push( style.backgroundImage.slice( 4, -1 ).replace(/['"]/g, "") // save background image url
}
}
/* MutationObserver callback to add images when the body changes */
var callback = function( mutationsList, observer ){
for( var mutation of mutationsList ) {
if ( mutation.type == 'childList' ) {
Array.prototype.forEach.call( mutation.target.children, function ( child ) {
var style = child.currentStyle || window.getComputedStyle(child, false);
if ( child.tagName === "IMG" ) {
images.push( child.src ); // save image src
image_parents.push( child.parentNode ); // save image parent
} else if ( style.backgroundImage != "none" ) {
bg_images.push( style.backgroundImage.slice( 4, -1 ).replace(/['"]/g, "") // save background image url
}
} );
}
}
}
var observer = new MutationObserver( callback );
var config = { characterData: true,
attributes: false,
childList: true,
subtree: true };
observer.observe( body, config );
});
Thank you.

You're missing some closing parentheses on the images.push() line and the last line.
Not sure if this will make your code do what you ultimately want it to do, but it will at least not cause a syntax error.
var elements = document.body.getElementsByTagName("*");
Array.prototype.forEach.call( elements, function ( el ) {
var style = window.getComputedStyle( el, false );
if ( style.backgroundImage != "none" ) {
images.push(style.backgroundImage.slice(4, -1).replace(/['"]/g, ""));
}
});

Related

WordPress Gutenburg block with Slick Slider not working/initializing in editor

I'm building a WordPress Gutenburg block with Slick Slider that works on the front end, but not working or initializing in the editor.
I learned why from the great answer from #Sally CJ at https://wordpress.stackexchange.com/questions/391371/how-to-load-an-additional-script-for-a-block-in-the-block-editor.
I'm using a modified version of her accordion code to initialize the slider:
jQuery(document).ready(function(){
function initSlider( selector ) {
jQuery( selector ).slick({
dots: true,
infinite: true,
slidesToShow: 3,
slidesToScroll: 3
});
console.log( 'slider initialized' );
}
var targetNode = document.querySelector('#editor');
function initObserver( selector, targetNode ) {
const observer = new MutationObserver( ( mutations, observer ) => {
for ( let mutation of mutations ) {
if ( 'childList' === mutation.type && mutation.addedNodes[0] &&
// Good, the added node has a slider div.
jQuery( selector, mutation.addedNodes[0] ).length >= 1
) {
// Convert the div to a slick slider.
initSlider( mutation.addedNodes[0] );
}
}
} );
observer.observe( targetNode || document.getElementById( 'editor' ), {
childList: true,
subtree: true,
} );
return observer;
}
jQuery( function ( $ ) {
// Setup slider for existing .wp-block-slider in the current DOM.
initSlider( '.wp-block-slider' );
// Observe slider insertions in the block editor.
$( '#editor' ).length && initObserver( '.wp-block-slider' );
} );
} );
This works on the front end but not working or initializing in the editor, even though the script is being loaded with no errors.
Any ideas?
Thanks!

Making a HTML source object

I want to create a little HTML extension which provides a tag (uai) which will be formatted like <uai src="some_what_file.mp3" controller="nav" autoplay="true">
And so on this tag will get a javascript object assigned.
function uai(){
this.src = { ... }
this.controller = { ... }
this.autoplay = { ... }
}
But I wonder how I will apply this function as an object to the html tag and make the HTML tag to apply the source to this.src
This object will be similar to the input tag *
I know the audio tag exists, and I fully know how to use it. But I want to replace the audio tag and functions with this one. It will make it easier for me to make canvas supported audio marks, so that's why I need it.
You can just access it like you would any other element and do what you need to do with it.
console.log(document.querySelector('cookies').getAttribute('flavor'))
<cookies flavor="chocolate chip"></cookies>
There are two important catches you should be aware of though:
First, it can't be self-closing. Browsers handle self-closing elements (<cookies />) in a special way, and you can't create custom self-closing tags (this is also a limitation that frameworks like Angular have to deal with). It has to have a closing tag, even if it has no children: <cookies></cookies>
Second, you can't do things like document.querySelector('cookies').flavor and access the property directly. You need to use document.querySelector('cookies').getAttribute('flavor') or .setAttribute(). You can however apply it yourself to use it latter:
Array.prototype.slice.call(document.querySelectorAll('cookies'), 0).forEach(cookie => Object.defineProperty(cookie, 'flavor', {
get: () => cookie.getAttribute('flavor'),
set: (value) => cookie.setAttribute('flavor', value)
}));
let cookie = document.querySelector('cookies');
console.log(cookie.flavor);
cookie.flavor = 'sugar';
console.log(cookie.flavor);
console.log(cookie);
<cookies flavor="chocolate chip"></cookies>
<cookies flavor="peanut butter"></cookies>
Using a transpiler that support classes and extends is very easy.
class UAIElement extends HTMLElement {
}
document.registerElement('uai', UAIElement);
the plain js version:
document.registerElement('uai', {
prototype: Object.create(HTMLElement.prototype, {
extends: 'audio'
})
});
If you want to use Custom Elements you need to insert an hyphen - in the name of your tag to be sure it won't be used in the future standard, for example: <ultimate-audio>.
Also you should use now the version 1 of the Custom Elements specification, which uses customElements.define() instead of document.registerElement() to register a new element.
Last, you cannot use the extends:'audio' option if you want to create a new tag.
You can use the class definition in all modern browsers:
Content of ulimate-audio.html:
<template>
<h3>UAI</h3>
<nav>
<button id=PlayBtn>Play</button>
<button id=StopBtn>Stop</button>
<input id=AutoplayCB type=checkbox disabled>Auto-Play
<div>Source : <output id=SourceOut></output></div>
</nav>
</template>
<script>
( function ( owner )
{
class UAI extends HTMLElement
{
constructor ()
{
super()
this.model = {}
this.view = {}
}
connectedCallback ()
{
//View
this.innerHTML = owner.querySelector( 'template' ).innerHTML
this.view.autoplay = this.querySelector( '#AutoplayCB' )
this.view.source = this.querySelector( '#SourceOut' )
//Model
//autoplay
var attr = this.getAttribute( 'autoplay' )
this.model.autoplay = typeof attr == 'string' && ( attr == '' || attr == 'true' )
//source
this.model.source = this.getAttribute( 'src' )
//Model -> View
this.view.source.textContent = this.model.source
this.view.autoplay.checked = this.model.autoplay
//[play] event
var self = this
this.querySelector( '#PlayBtn' ).addEventListener( 'click', function ()
{
self.play()
} )
this.querySelector( '#StopBtn' ).addEventListener( 'click', function ()
{
self.stop()
} )
//init
if ( this.model.autoplay )
this.play()
}
play ()
{
this.model.audio = new Audio( this.model.source )
this.model.audio.play()
}
stop ()
{
this.model.audio.pause()
}
set src ( file )
{
console.log( '%s.src=%s', this, file )
this.model.source = file
this.model.audio.src = file
this.view.source.textContent = file
if ( this.model.autoplay )
this.model.audio.play()
}
set autoplay ( value )
{
console.warn( 'autoplay=', value )
this.model.autoplay = ( value === "true" || value === true )
this.view.autoplay.checked = this.model.autoplay
}
}
customElements.define( 'ultimate-audio', UAI )
} )( document.currentScript.ownerDocument )
</script>
The UI of you control is defined in the <template>, where you can add a <style> element.
Then you can use your tag like this:
In the header, include the custom element:
<link rel="import" href="ultimate-audio.html">
In the body, use the new tag:
<ultimate-audio id=UA src="path/file.mp3" autoplay></ultimate-audio>
The methods play(), stop(), and the properties src and autoplay can be invoked form javascript:
UA.src = "path/file2.mp3"
UA.play()

jQuery $(window).scroll event handler off but still firing?

I'm experiencing some strange behavior with a jQuery plugin that I wrote. Basically, the plugin makes a sidebar element stick to the top of the browser window when scrolling through the blog post that the sidebar belongs to. This should only happen when the window reaches a certain size (768px) or above (the plugin detects this by checking the float style of the sidebar).
Everything works as expected...until you resize the browser from large -- sidebar is sticky -- to small -- sidebar should not be sticky. My onResize function supposedly removes the scroll event handler and only adds it back if the startQuery is true (so, if the sidebar float value is something other than none). I've double and triple checked through the console: everything is working correctly as far as I can tell. I even added console.log('scroll') to the onScroll function and it doesn't show up when the event handler is supposed to be removed, but my sidebar is still turning sticky when I scroll through the blog posts.
You can see the problem in action here. To recreate the steps:
Resize your browser window to less than 768px wide and visit the page. See that the .share-bar element inside each blog post does not move as you scroll. 'scroll' is not logged in the console.
Resize your browser window to 768px or larger. See that the .share-bar element becomes sticky as you scroll through each blog post, then sticks to the bottom of the post as you scroll past it. 'scroll' is logged in the console.
Resize your browser window to less than 768px. See that the .share-bar element becomes sticky as you scroll through each blog post. 'scroll' is not logged in the console.
It's almost as if the event handler is removed, but the elements aren't updating or something. I'm sure I'm missing something fundamental, but I've researched and tried all sorts of fixes for $(window).scroll event problems and none of them are working here.
My call to plugin:
$('.share-bar').stickySides({
'wrapper': '.post-wrapper',
'content': '.entry-content' });
Plugin code:
;( function ( $, window, document, undefined ) {
var settings;
var throttled;
$.fn.stickySides = function( options ) {
settings = $.extend( {}, $.fn.stickySides.defaults, options );
// Store sidebars
settings.selector = this.selector;
settings.startQuery = '$("' + settings.selector + '").css(\'float\') != \'none\'';
// Create debounced resize function
var debounced = _.debounce( $.fn.stickySides.onResize, settings.wait );
$(window).resize( debounced );
// Create throttled scroll function
throttled = _.throttle( $.fn.stickySides.onScroll, settings.wait );
// Only continue if the start query is true
if ( eval(settings.startQuery) == true ) {
$(window).on( 'scroll.stickySides', throttled );
}
return this;
};
// Define default settings
$.fn.stickySides.defaults = {
wrapper: 'body',
content: '.content',
wait: 100,
startQuery: ''
};
$.fn.stickySides.onResize = function ( ) {
$(window).off( 'scroll.stickySides' );
// Only continue if the start query is true
if ( eval(settings.startQuery) == true ) {
$(window).on( 'scroll.stickySides', throttled );
} else {
var sides = $(settings.selector);
sides.each ( function () {
var elem = $(this);
var content = elem.siblings( settings.content );
if ( elem.css('position') == 'fixed' || elem.css('position') == 'absolute' ) {
elem.css( 'position', 'static' );
}
if ( content.css('margin-left') != '0px' ) {
content.css( 'margin-left', 0 );
}
});
}
};
$.fn.stickySides.onScroll = function ( ) {
console.log('scroll');
var sides = $(settings.selector);
// Check each sidebar
sides.each ( function () {
var elem = $(this);
var content = elem.siblings( settings.content );
var wrapper = elem.closest( settings.wrapper );
var elemHeight = elem.height();
var wrapperHeight = wrapper.height();
// Only continue if the wrapper is taller than the sidebar
if ( elemHeight >= wrapperHeight ) {
return;
} else {
var wrapperFracs = wrapper.fracs(function (fracs) {
// Only continue if the wrapper is in view
if ( fracs.visible == 0 ) {
return;
} else {
// Check if the wrapper extends beyond the top of
// the viewport
var wrapperSpaceTop = fracs.rects.element.top;
// If it does, change sidebar position as appropriate
if ( wrapperSpaceTop > 0 ) {
var visibleWrapper = fracs.rects.document.height;
// If the visible portion of the wrapper is smaller
// than the height of the sidebar...
if ( visibleWrapper <= elemHeight ) {
// ...position the sidebar at the bottom
// of the wrapper
if ( wrapperSpaceTop != 0 ) {
elem.css('position', 'absolute').css( 'top', (wrapperHeight - elemHeight) + content.position().top + 'px' );
}
// Otherwise, move sidebar to appropriate position
} else {
elem.css('position', 'fixed').css('top', 0);
}
content.css('margin-left', elem.outerWidth());
} else {
elem.css('position', 'static');
content.css('margin-left', 0);
}
}
});
}
});
};
} )( jQuery, window, document );
PS: I would use an existing plugin, but I didn't see one that got really close to the functionality I need here; feel free to point one out if you know of one. I haven't tested outside of Mac yet. And yes, I know some of the page elements don't flow very well on mobile -- ex: site header & nav -- and there are some other missing items unrelated to this problem. I'm waiting for some feedback from my client before I can address that.
Happens every time. Shortly after I ask for help, I figure it out on my own. ;)
The problem was in the fracs function inside the onScroll function. I didn't realize it called its own resize/scroll handlers, so those weren't getting unbound when I removed my scroll handler. I just reworked the plugin to take advantage of the fracs library's handlers instead of calling my own scroll handler:
;( function ( $, window, document, undefined ) {
var settings;
var throttled;
$.fn.stickySides = function( options ) {
settings = $.extend( {}, $.fn.stickySides.defaults, options );
// Store sidebars
settings.selector = this.selector;
settings.startQuery = '$("' + settings.selector + '").css(\'float\') != \'none\'';
if ( eval( settings.startQuery ) == true ) {
$.fn.stickySides.doFracs();
}
// Create debounced resize function
var debounced = _.debounce( $.fn.stickySides.onResize, settings.wait );
$(window).resize( debounced );
return this;
};
// Define default settings
$.fn.stickySides.defaults = {
wrapper: 'body',
content: '.content',
wait: 100,
startQuery: ''
};
$.fn.stickySides.doFracs = function ( ) {
var sides = $(settings.selector);
// Check each sidebar
sides.each ( function () {
var elem = $(this);
var content = elem.siblings( settings.content );
var wrapper = elem.closest( settings.wrapper );
var elemHeight = elem.height();
var wrapperHeight = wrapper.height();
// Only continue if the wrapper is taller than the sidebar
if ( elemHeight >= wrapperHeight ) {
return;
} else {
var wrapperFracs = wrapper.fracs( $.fn.stickySides.fracsCallback );
}
});
}
$.fn.stickySides.unbindFracs = function ( ) {
var sides = $(settings.selector);
// Check each sidebar
sides.each ( function () {
var elem = $(this);
var content = elem.siblings( settings.content );
var wrapper = elem.closest( settings.wrapper );
if ( elem.css('position') == 'fixed' || elem.css('position') == 'absolute' ) {
elem.css( 'position', 'static' );
}
if ( content.css('margin-left') != '0px' ) {
content.css( 'margin-left', 0 );
}
wrapper.fracs('unbind');
});
}
$.fn.stickySides.fracsCallback = function ( fracs ) {
// Only continue if the wrapper is in view
if ( fracs.visible == 0 ) {
return;
} else {
var wrapper = $(this);
var elem = wrapper.find(settings.selector);
var content = elem.siblings( settings.content );
var elemHeight = elem.height();
var wrapperHeight = wrapper.height();
// Check if the wrapper extends beyond the top of
// the viewport
var wrapperSpaceTop = fracs.rects.element.top;
// If it does, change sidebar position as appropriate
if ( wrapperSpaceTop > 0 ) {
var visibleWrapper = fracs.rects.document.height;
// If the visible portion of the wrapper is smaller
// than the height of the sidebar...
if ( visibleWrapper <= elemHeight ) {
// ...position the sidebar at the bottom
// of the wrapper
if ( wrapperSpaceTop != 0 ) {
elem.css('position', 'absolute').css( 'top', (wrapperHeight - elemHeight) + content.position().top + 'px' );
}
// Otherwise, move sidebar to appropriate position
} else {
elem.css('position', 'fixed').css('top', 0);
}
content.css('margin-left', elem.outerWidth());
} else {
elem.css('position', 'static');
content.css('margin-left', 0);
}
}
}
$.fn.stickySides.onResize = function ( ) {
// Only continue if the start query is true
if ( eval(settings.startQuery) == true ) {
$.fn.stickySides.doFracs();
} else {
$.fn.stickySides.unbindFracs();
}
};
} )( jQuery, window, document );
Voila! Problem solved.

Backbone model.change() not firing

I'm currently writing an application using Backbone and for some reason, it doesn't update a view, but only in certain circumstances.
If I refresh the page at index.html#/blog/2 it loads the page just fine, everything works great. However, if I refresh the page at index.html#/blog/1 and then change the URL to index.html#/blog/2 and press enter(NOT refresh), the change never gets fired.
This is my router:
makeChange: function() {
// Set activePage to the current page_id => /blog/2
var attributes = {activePage: this.page_id};
var $this = this;
// Loop through all sections in the app
app.sections.some( function( section ) {
// Check if section has the page
if( !section.validate( attributes ) )
{
// If it has, set the activePage to /blog/2
section.set( attributes, {silent: true} );
// Set active section to whatever section-id was matched
app.set( {activeSect: section.id}, {silent: true} );
console.log('Calling change!');
// Calling change on both the app and the section
app.change();
section.change();
console.log('Change complete!');
return true;
}
});
}
This is the app view(which is referenced as "app" up above^):
var AppView = Backbone.View.extend({
initialize: function( option ) {
app.bind( 'change', _.bind( this.changeSect, this ) );
},
changeSect: function() {
var newSect = app.sections.get( app.get('activeSect' ) );
var newSectView = newSect.view;
if( !app.hasChanged( 'activeSect' ) )
newSectView.activate( null, newSect );
else
{
var oldSect = app.sections.get( app.previous( 'activeSect' ) );
var oldSectView = oldSect.view;
newSectView.activate( oldSect, newSect );
oldSectView.deactivate( oldSect, newSect );
}
}
});
Tell me if you need to see some other classes/models/views.
I solved it! This only happens when navigating between different pages(by changing activePage in the section) in the same section, so activeSect in app was never changed, thus never called changeSect(). Now even when activeSect is the same in the app, and activePage has changed in the section, it will call the changeSect() in the app anyway.
In Section-model, I added this:
initialize: function() {
this.pages = new Pages();
this.bind( 'change', _.bind( this.bindChange, this ) );
},
prepareForceChange: function() {
this.forceChange = true;
},
bindChange: function() {
console.log('BINDCHANGE!');
if( this.forceChange )
{
AppView.prototype.forceChange();
this.forceChange = false;
}
},
In router.makeChange() above this:
section.set( attributes, {silent: true} );
app.set( {activeSect: section.id}, {silent: true} );
I added:
var oldSectId = app.get('activeSect');
if( oldSectId == section.id ) section.prepareForceChange();

cannot debug onmouseover event

/* this is our script for monopoly_first_page.html */
var result;
var button;
var image;
var x = 0;
function animation( animatedObject ){
var hereObject = animatedObject;
alert( hereObject );
/*setInterval( animate( animatedObject, x ), 100 );*/
}
function animate( hereObject, x ){
alert( x );
if( x == 0){
hereObject.style.width++;
}
else{
hereObject.style.width--;
}
if( hereObject.style.width <= 225 ){
x = 0;
}
if( hereObject.style.width >= 300 ){
x = 1;
}
}
function disanimation( animatedObject ){
var hereObject = animatedObject;
clearInterval();
}
window.onload = init;
function init(){
result = document.getElementById( "result" );
button = document.getElementById( "button-container" );
document.getElementById( "button-container" ).onmouseclick = animation( button );
document.getElementById( "button-container" ).onmouseout = disanimation( button );
alert( button );
alert( button );
}
hi every one...this is one of my source code and im a beginner...i faced a problem and it is where i wrote this statement:
document.getElementById( "button-container" ).onmouseclick = animation( button );
when function init begins to run function animation also execetues... but im sure im not rolling my mouse over the specified DIV...
what is the problem?
You need to pass a function to any handlers. What is happening with your code is that it calls animation(button) then sets that value to the onmouseclick property. Since the animation(...) function doesn't return a function, nothing beneficial will happen.
This would be a lot closer.
whatever.onmouseclick = animation;
If you need to, you could also do this: (assuming you want a specific button passed)
whatever.onmouseclick = function(e) { animation(button); }
just wanted to add to john, you can also do
document.getElementById( "button-container" ).addEventListener("click",function(){animation(button);},true);
insetead of "onmouseclick"
:-)
As #JohnFisher already mentioned, you assign the RESULT of your function to the event
However I only ever use onclick. Where did you get onmouseclick from?
Also you repeat your getElementById unnecessarily and have an init that is an onload so consolidate it:
window.onload = function() {
var button = document.getElementById( "button-container" );
// button is not necessarily known or the same at the time of the click so use (this)
button.onclick = function() { animation(this); }
button.onmouseout = function() { disanimation(this); }
}

Categories

Resources