I would like to preload the SWF before showing them to the user.
SWF are dynamic and I dont have the FLA files.
I would love to do it using Javascript or jquery if possible.
Have a look at swfjsPreLoader:
This preloader accepts an array of assets (jpg,gif,png,swf) you would
like to preload. Internally it will create an flash-application which
does the preloading. You could define several callback handlers. So
JavaScript gets to know when all assets are loaded or each single
asset is loaded including SWF-files.
I don't know if you're still looking for answers, but here it is.
Create two divs inside your page. Give one an ID called loading, and another the id feature, and hide feature. Put your flash content inside feature, and make sure to hide feature with css display:none.
Then, at the top of your page, or wherever you do your onload stuff, do this:
$(document).load('/path/to/your.swf', function() {
$('#feature').slideDown(600);
$('#loader').slideUp(300);
});
And there you have it.
Inside loading, you can put one of those happy little spinning wheel graphics. I'm sure there are more sophisticated things you can do with callbacks, but this will do the job of preloading.
Enjoy.
You can first load swf file via ajax and then add object to dom.
In this way, browser will use cache, swf is reloaded from cache and is immediately ready.
Follow a sample of what I'm saying (I cannot give you a fiddle sample because you need a local swf to be ajax loaded).
swfobject can be used in "loadObject" function for a better configuration of swf object.
"mySwfFunction" is called after swf is loaded. It can be removed if not needed.
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>Swf demo</title>
<script type='text/javascript' src='http://code.jquery.com/jquery-1.8.2.js'></script>
<style type='text/css'>
</style>
<script type='text/javascript'>
$(window).load(function () {
var loader = new
function () {
var loadObject = function ($el, src, callback, width, height) {
var d = document;
var s = 'object';
var obj = d.createElement(s);
obj.type = 'application/x-shockwave-flash';
if(width){
obj.width = width.toString() + 'px';
}
obj.name = 'plugin';
if(height){
obj.height = height.toString() + 'px';
}
obj.data = src;
$el[0].appendChild(obj);
};
this.loadSwf = function ($el, src, callback, width, height) {
$.ajax({
url: src,
success: function (data) {
loadObject($el, src, callback, width, height);
if(callback) callback();
},
error: function (xhr) {
//your error code
}
});
};
} ();
var mySwfCallback = function() {
$('#mySwf').show();
}
var $el = $('#mySwf');
var src = 'your_file_url.swf';
loader.loadSwf($el, src, mySwfCallback, 300, 300);
});
</script>
</head>
<by>
<div id='mySwf' style='display:none;' >
</div>
</body>
</html>
Can you preload the whole page? If so here is an idea with jQuery:
http://www.gayadesign.com/scripts/queryLoader/
Personally I think it's best to use a Flash-based polite loader as this can be as little as 5kb. The code for it doesn't have to be that hard, something along the lines of:
package
{
import com.firestartermedia.lib.as3.utils.DisplayObjectUtil;
import flash.display.Sprite;
import flash.events.Event;
[SWF( backgroundColor=0xFFFFFF, frameRate=30, height=400, width=600 )]
public class AppLoader extends Sprite
{
public function AppLoader()
{
loaderInfo.addEventListener( Event.INIT, handleInit );
}
private function handleInit(e:Event):void
{
loaderInfo.removeEventListener( Event.INIT, handleInit );
DisplayObjectUtil.loadMovie( 'App.swf', null, handleComplete );
}
private function handleComplete(e:Event):void
{
removeChild( loader );
addChild( e.target.content );
}
}
}
This uses the DisplayObjectUtil available on github: https://github.com/ahmednuaman/as3
Use another swf with preloader. Look here:
http://help.adobe.com/en_US/ActionScript/3.0_ProgrammingAS3/WS5b3ccc516d4fbf351e63e3d118a9b90204-7de1.html
Related
Using the HTML below, how can I get a list of the functions in the <script> tag that is IN the #yesplease div. I don't want any other functions from other script tags. I don't want any global functions or native functions. What I'd like is an array with "wantthis1" and "wantthis2" only in it. I'm hoping not to have to use regex.
I am going to be emptying and filling the #yesplease div with different strings of html (including new script tags with new functions), and I need to make sure that I delete or "wantthis1 = undefined" each function in the script tag before filling it, programmatically, since I won't know every function name. (I don't want them to remain in memory)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script>
function dontCare() {
// don't care
}
</script>
</head>
<body>
<div id="notthisone">
<p>
Hello
</p>
<script>
function dontwantthis () {
// nope
}
</script>
</div>
<div id="yesplease">
<p>
Hello again
</p>
<script>
function wantthis1 () {
// yes
}
function wantthis2 () {
// yes
}
</script>
</div>
<script>
// this function can be called by whatever, but this will look to
// see if functions exist, then call them, otherwise do something
// else
function onSaveOrWhatever () {
if (wantThis1 !== "undefined") {
wantThis1();
}
else {
// do something else (won't get called with above example)
}
if (wantThis3 !== "undefined") {
wantThis3();
}
else {
// do something else (will get called with above example)
}
}
</script>
</body>
</html>
Take innerHTML of all script tags you need
Create an iframe
Get a list of built-in functions of iframe.contentWindow object
Write the content of the script to the iframe created
Get a new list of the functions of iframe.contentWindow object
Find new functions added to the new list
Somehow it doesn't work in stack snippets but it works in Codepen link
var code = document.querySelector("#target script").innerHTML;
var iframe = document.createElement("iframe");
document.body.appendChild(iframe);
var builtInFunctions = getFunctionsOfWindowObject();
var html = `<html><head><script>${code}</script></head><body /></html>`;
iframe.srcdoc = html;
var allFunctions = getFunctionsOfWindowObject();
var result = allFunctions.filter(function(n) {
return builtInFunctions.indexOf(n) < 0;
});
console.log(result);
function getFunctionsOfWindowObject() {
var functions = [];
var targetWindow = iframe.contentWindow;
for (var key in targetWindow) {
if (
targetWindow.hasOwnProperty(key) &&
typeof targetWindow[key] === "function"
) {
functions.push(key);
}
}
return functions;
}
iframe {
display: none;
}
<div id="target">
<script>
function wantthis1() {}
function wantthis2() {}
</script>
</div>
The are a few ways to solve this problem
Architect your application. Use react or vue (or even jquery) to add more control to your code/dom
AST parsing, which would be overkill
Hack it
If you hack it, the problem that you will face is that you are adding functions to global scope. This is shared by everyone, so you can't really monitor it in a nice way.
You can however take advantage of javascript singlethreadedness, and know that things won't happen in the background while you are doing monitoring tasks.
<script>
// take a cache of what is present before your script
window.itemsPresentBeforeScript = {};
foreach (var item in window) {
window.itemsPresentBeforeScript[item] = window[item];
}
</script>
<script> .... your other script </script>
<script>
// use your first cache to see what changed during the script execution
window.whatWasAddedInTheLastScript = {};
foreach (var item in window) {
if (!window.itemsPresentBeforeScript[item]) {
window.whatWasAddedInTheLastScript[item] = window[item];
}
}
delete window.itemsPresentBeforeScript;
// not you have a global list of what was added and you can clear it down when you need to
</script>
Consider the following test-element web component definition (vanilla JavaScript running on Google Chrome, not Polymer),
that creates a simple component with width=500px. Its attachedCallback function outputs its width to the console, and then sets up an asynchronous delay to do it again:
test-element.html
<style> test-element { display: inline-block; width: 500px; } </style>
<script>
(function (window, document) {
var proto = Object.create(HTMLElement.prototype);
proto.attachedCallback = function () {
// Direct output.
console.log("(1) test-element.width = ", this.offsetWidth);
// Delayed output.
window.setTimeout(function () { console.log("(2) test-element.width = ", this.offsetWidth); }.bind(this), 0);
};
document.registerElement('test-element', {prototype: proto});
})(window, document);
</script>
I then create a page that imports test-element, and outputs its width yet again from an inline script tag:
index.html
<!DOCTYPE html>
<html>
<head>
<link rel="import" href="test-element.html">
</head>
<body>
<test-element></test-element>
<script>
var testElement = document.querySelector('test-element');
console.log("(3) test-element.width = ", testElement.offsetWidth);
</script>
</body>
</html>
The output to the console is:
(1) test-element.width = 0
(3) test-element.width = 500
(2) test-element.width = 500
This goes to prove that attachedCallback (1) is called before layouts and paints, which sometimes is really what I want.
For example, if I want to change its width to 100 pixels, I can make testElement.style.width = "100px", and I don't need not worry about
the component flashing its previous 500px width before the callback has a chance to make the change.
However, attachedCallback being called before layouts sometimes is NOT what I want.
For example, if test-element contains a grid, and it needs to draw cells, then I need to know its width so that I can calculate how many cells
fit the available space. But I don't have this information during the attachedCallback, and I can't seem to grasp how to get this information.
As you can see, a 0ms delay (2) seems to trigger the layout calculation in this very simple example.
But as soon as I start doing more complicated things (for example when I have nested web components and asynchronous HTML imports), the 0ms delay is not enough, and I have to change it to a 100ms delay, and then more.
My question is: How can I reliably get the width of the component (or any other computed styles), as soon as possible?
I seem to have found the solution, using requestAnimationFrame:
proto.attachedCallback = function () {
// This never works:
console.log("(1) test-element.width = ", this.offsetWidth);
// This works sometimes:
window.setTimeout(function () { console.log("(2) test-element.width = ", this.offsetWidth); }.bind(this), 0);
// SOLUTION - This seems to always work.
window.requestAnimationFrame(function () { console.log("(4) test-element.width = ", this.offsetWidth); }.bind(this));
};
Note: This is so far working OK for me, no matter how many web components I nest, and no matter how complicated I chain my HTML imports. However... does this always work? HTML parsing of HTML imports is parallelized (according to user https://stackoverflow.com/users/274673/ebidel here: http://www.html5rocks.com/en/tutorials/webcomponents/imports) and I don't perfectly understand the situation to be absolutely sure of this solution.
In your example above, the fastest way to get the (custom) element width in a <script> tag just after the element, exactly what you did in your test (3):
<test-element></test-element>
<script>
var testElement = document.querySelector('test-element');
console.log("(3) test-element.width = ", testElement.offsetWidth);
</script>
It's because HTML elements are rendered sequencially by the browser. So the script content will be executed just after the calculation of the <test-element> width and other layout properties.
(1) test-element.width = 0
(3) test-element.width = 500
HTMLImportsLoaded //with polyfill
DomContentLoaded
window.onload
(2) test-element.width = 500
WebComponentsReady //with polyfill
NB: Other browser than Chrome will behave differently.
Update
Be careful not getting the computed style values too soon in the rendering, especially if another element is using the requestAnimationFrame method, too.
Below an example that shows a web component cannot always rely on this hack to know itself: the grid element doesn't know its rendered width at step (4) yet.
(function(window, document) {
var proto = Object.create(HTMLElement.prototype);
proto.attachedCallback = function() {
// Direct output.
console.log("(1) %s.width = ", this.id, this.offsetWidth);
this.innerHTML = "Element: " + this.id
// Delayed output.
window.setTimeout(function() {
console.log("(2) %s.width = %s ", this.id, this.offsetWidth);
}.bind(this), 0);
window.requestAnimationFrame(function() {
if (this.id == "side")
this.classList.add("large")
console.log("(4) %s.width = %s", this.id, this.offsetWidth);
}.bind(this));
};
document.registerElement('test-element', {
prototype: proto
});
})(window, document);
test-element {
display: inline-block;
border: 1px solid red;
width: 500px;
}
.large {
width: 300px;
}
<!DOCTYPE html>
<html>
<head>
</head>
<body style="display:flex">
<test-element id="grid"></test-element>
<test-element id="side"></test-element>
<script>
var testElement = document.querySelector('test-element');
console.log("(3) %s.width = %s", testElement.id, testElement.offsetWidth);
window.onload = function() {
console.log("window.onload")
}
</script>
</body>
</html>
Well I am unable to lazy load images for some reason. Here is the waterfall view of the tested site
Apparently I am using two lazy load scripts with lazy load script 1 which works but kills the lightbox plugin and also requires lots of tweaking using data-src and src and class="lazy-load" attributes. which I am using for non post related images.
But the main problem lies in the second script which requires Jquery but doesn't require any tweaking with the images. The script is called stalactite (via Github) which I am using like this
<script charset='utf-8' src='http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js' type='text/javascript' />
<script href='http://googledrive.com/host/0B2xMFcMT-eLiV1owdlBMeklGc2M' type='text/javascript' />
<script type='text/javascript'>
$( 'body').stalactite({
loader: '<img/>' // The contents of the loader. Defaults to a dataURL animated gif.
});
</script>
You can find the link of the stalactite script in the above code and here is the documentation.
I don't know why it doesn't work ! Or am I executing it wrongly.
A solution to the problem will be very helpful. Many thanks in advance.
If you are tired of trying to use lazy load libraries and haven't managed to make all of it work, I can suggest you to create lazy load script on your own, or you can take a look at this code below.
By only using jQuery and without needing any other library, you can use this script to achieve the lazy load (I modified the codes from the original one that I used at work):
var doLazyLoad = true;
var lazyLoadCounter = 0;
var lazyLoadMax = 2; // Maximum number of lazy load done
// Button to indicate lazy load is loading,
// or when lazy load has reached its maximum number,
// this button load data manually.
// You can replace this with something like gif loading animation.
var $btnLoadMore = $("#btn-lazy-load-more");
// I use AJAX function to get the data on lazy load
var ajaxFn = function (enableScrollAnim = true) {
var loadingStr = 'Loading...',
idleStr = 'Load more',
ajaxUrl = 'http://www.example.com/posts',
ajaxHeaders = {'HTTP_X_REQUESTED_WITH': 'XMLHttpRequest'},
ajaxData = {
start: $('.posts-wrapper .post').length
};
$btnLoadMore.text(loadingStr); // You can disable the button to prevent manual loading
return $.ajax({
url: ajaxUrl,
type: 'GET',
dataType: 'json',
data: ajaxData,
headers: ajaxHeaders,
// On success AJAX, append newly loaded data to lazy load container.
// Here in my example, the GET request returns data.view i.e. the content, and data.total i.e. total number of posts
success: function (data) {
var $newLoadedPosts = $(data.view),
nlsMarginBottom;
$('.posts-wrapper').append($newLoadedPosts);
$newLoadedPosts.css('display', 'none').fadeIn();
// Animate auto scroll to newly loaded content
if (enableScrollAnim) {
$('html, body').animate({
scrollTop: $newLoadedPosts.first().offset().top
});
}
if ($('.posts-wrapper .post').length < data.total) {
$btnLoadMore.text(idleStr); // If you disable the button, enable the button again here
} else {
// Remove the button when there's no more content to load.
// Determined by data.total
$btnLoadMore.remove();
}
},
error: function () {
$btnLoadMore.text(idleStr); // If you disable the button, enable the button again here
}
});
};
// Do the lazy load here
if ($btnLoadMore.length) {
$(window).scroll(function () {
var scrollOffset = (($btnLoadMore.offset().top - $(window).height()) + $btnLoadMore.height()) + 100;
var hasReachedOffset = $(window).scrollTop() >= scrollOffset;
var isLmsBtnExist = $btnLoadMore.length;
if (hasReachedOffset && lazyLoadCounter < lazyLoadMax && doLazyLoad && isLmsBtnExist) {
doLazyLoad = false;
ajaxFn(false).always(function () {
doLazyLoad = true;
lazyLoadCounter++;
});
}
});
}
$btnLoadMore.click(ajaxFn);
And here is the GIF demo image of my working code.
If you need any further explanation, just comment this answer and I will try to help you.
I'm using Safari 6.0.5.
I open a new empty window, try to change the title to 'debug window', nothing happens. With a check function checking every 10 milliseconds, it says the window.document.title is 'Debug Window', still the new Window title bar says it is 'untitled'.
var debug_window = window.open('', 'debug_window', 'height=200');
debug_window.document.title = 'Debug Window';
function check()
{
debugLog(1, 'title:' + debug_window.document.title);
if(debug_window.document) { // if loaded
debug_window.document.title = "debug_window"; // set title
} else { // if not loaded yet
setTimeout(check, 10); // check in another 10ms
}
}
check();
The output in the debugLog is:
17:35:04.558: title:
17:35:04.584: title:debug_window
What is going wrong here that the new window is still called 'untitled'?
Thanks!
Now the second argument to window.open() is a frame/window-name and serves also as the default title. This is eventually overridden by the document loaded into this window. Opening the document-stream and inserting a basic html-document should serve the purpose:
var debug_window = window.open('', 'debug_window', 'height=200');
debug_window.document.open();
debug_window.document.write('<!DOCTYPE html>\n<html lang="en">\n<head>\n<title>Debug Window</title>\n</head>\n<body></body>\n</html>');
debug_window.document.close();
var debug_body = debug_window.document.getElementsByTagName('body')[0];
// write to debug_window
debug_body.innerHTML = '<p>Message</p>';
So you would be setting up a basic document inside the window, just as it would be loaded by the server (by writing to the "document stream"). Then you would start to manipulate this document like any other.
Edit: Does not work in Safari either.
Other suggestion: set up a basic document (including the title) on the server and inject the content into its body on load. As a bonus, you may setup CSS via stylesheets.
var debug_window = window.open('debug_template.html', 'debug_window', 'height=200');
debug_window.onload = function() {
var debug_body = debug_window.document.getElementsByTagName('body')[0];
debug_body.innerHTML = '...';
// or
// var el = document.createElement('p');
// p.innerHTML = '...';
// debug_body.appendChild(p);
debug_window.onload=null; // clean up cross-reference
};
And on the server side something like
<!DOCTYPE html>
<html lang="en">
<head>
<title>Debug Window</title>
<link rel="stylesheet" href="debug_styles.css" type="text/css" />
</head>
<body></body>
</html>
If this still should not work (e.g.: writing to the debug-window's document is without effect), you could call your app from inside the debug-window by something like:
<body onload="if (window.opener && !window.opener.closed) window.opener.debugCallback(window, window.document);">
</body>
(So you would check if the opener – your App – exists and hasn't been closed in the meantime and then call a callback-function "debugCallback()" in your app with the debug-window and its document as arguments.)
Try:
var debug_window = window.open('about:blank', 'debug_window', 'height=200');
Hi sorry if the name of my question is not correct.
i am trying to create an image rotator, but i would like to be able to re-use it more than once in a page, so i am trying to create it as an object/class.
I have about 5 or 6 images on a page.
i would like to have each image as a rotator, displaying a new image every 2 seconds or so.
<img src="uploads/Range_Images/p6-7.jpg" class="myclass1"/>
<img src="uploads/Range_Images/p6-7.jpg" class="myclass2"/>
<img src="uploads/Range_Images/p6-7.jpg" class="myclass3"/>
<script type=text/javascript>
$Rotator1 = new imageRotator1('p12-13.jpg:p18-19.jpg:p4-5.jpg:p8-9.jpg:p6-7.jpg:p10-11.jpg:p14-15.jpg:p16-17.jpg', '.myclass1');
setInterval($Rotator1.rotateImage(), 1000);
$Rotator2 = new imageRotator1('p12-13.jpg:p18-19.jpg:p4-5.jpg:p8-9.jpg:p6-7.jpg:p10-11.jpg:p14-15.jpg:p16-17.jpg', '.myclass2');
setInterval($Rotator2.rotateImage(), 1000);
$Rotator3 = new imageRotator1('p12-13.jpg:p18-19.jpg:p4-5.jpg:p8-9.jpg:p6-7.jpg:p10-11.jpg:p14-15.jpg:p16-17.jpg', '.myclass3');
setInterval($Rotator3.rotateImage(), 1000);
</script>
Thats the code i am using to display the images and to create an instance of my rotator class
I can think of a few issues i am not sure of the answers too despite googling for hours!
Firstly here is my code (i am mixing javascript with jquery which is probably where i am going wrong to start with...
<script type="text/javascript">
$(document).ready(function(){ // maybe this should not be used when creating a object/class???
// i want to use this function as a class if possible
function imageRotator($images_str, $class){
// set up the vars
this.myImg = $images_str; //string containing image names
this.myClass = $class; //string containing class of image to change
this.imagelist = this.myImg.split(':'); //split the image string into an array
this.index = 1; // set the current index count
// maybe this is where i am going wrong, as in jquery $(this) refers to the current selector and maybe this.myclass (from from the imageRotator object does not work??
// is it possible to reference a value from an object in jquery?
function prototype.rotateImage(){
$(this.myclass).fadeOut('fast', function(){
$(this).attr('src', this.imagelist[this.index]);
$(this).fadeIn('fast', function(){
if (this.index == this.imagelist.length-1){
this.index = 0;
}else{
this.index++;
};
});
});
};
};
});
</script>
I am by no means an expert in programming, but i am sure this should be possible somehow.
any help would be much appreciated :P
update:
ok have modified the code slightly as per castrohenges reply:
<script type="text/javascript">
$(document).ready(function(){
var imageRotator = function($images_str, $class){
// set up the vars
this.myImg = $images_str; //string containing image names
this.myClass = $class; //string containing class of image to change
this.imagelist = this.myImg.split(':'); //split the image string into an array
this.index = 1; // set the current index count
};
function imageRotator.prototype.rotateImage(){
$(this.myclass).fadeOut('fast', function(){
$(this).attr('src', this.imagelist[this.index]);
$(this).fadeIn('fast', function(){
if (this.index == this.imagelist.length-1){
this.index = 0;
}else{
this.index++;
};
});
});
};
});
</script>
</head>
<body>
<img src="uploads/Range_Images/p6-7.jpg" class="myclass1"/>
<img src="uploads/Range_Images/p6-7.jpg" class="myclass2"/>
<img src="uploads/Range_Images/p6-7.jpg" class="myclass3"/>
<script type=text/javascript>
$(document).ready(function(){
$Rotator1 = new imageRotator('p12-13.jpg:p18-19.jpg:p4-5.jpg:p8-9.jpg:p6-7.jpg:p10-11.jpg:p14-15.jpg:p16-17.jpg', '.myclass1');
setInterval($Rotator1.rotateImage(), 1000);
$Rotator2 = new imageRotator('p12-13.jpg:p18-19.jpg:p4-5.jpg:p8-9.jpg:p6-7.jpg:p10-11.jpg:p14-15.jpg:p16-17.jpg', '.myclass2');
setInterval($Rotator2.rotateImage(), 1000);
$Rotator3 = new imageRotator('p12-13.jpg:p18-19.jpg:p4-5.jpg:p8-9.jpg:p6-7.jpg:p10-11.jpg:p14-15.jpg:p16-17.jpg', '.myclass3');
setInterval($Rotator3.rotateImage(), 1000);
});
</script>
</body>
i was getting an error: image rotator not defined on line 45
hence changing it to
var imageRotator = function($images_str, $class){....};
but the error is still there?
will try recreating this script following the plug-in guidelines and see where i get....
If you want to use prototyping you need to change
function prototype.rotateImage(){
and place it outside of the imageRotator function. Like so:
function imageRotator($images_str, $class){ ... }
imageRotator.prototype.rotateImage = function() { ... }
Alternatively you could also take a look at this jQuery plugin http://malsup.com/jquery/cycle/ - this is the first one I found, but I'm sure there will be more out there.
If you do want to use your own custom code I recommend wrapping it up as a jQuery plugin - http://docs.jquery.com/Plugins/Authoring. That way you don't have to worry to much about class architecture and everything will be nicely encapsulated in the jQuery object.