How do I invoke this function with JavaScript? - javascript

I am just working with basic level of javascripts. Today I found the below and for scrolling down DIV layer when new data adds to DIV. I couldn't understand how to Call the function. Is it to be used using window.onload function? or any other. And where should I declare the DIV name?
Code follows.
var chatscroll = new Object();
chatscroll.Pane =
function(scrollContainerId)
{
this.bottomThreshold = 25;
this.scrollContainerId = scrollContainerId;
}
chatscroll.Pane.prototype.activeScroll =
function()
{
var scrollDiv = document.getElementById(this.scrollContainerId);
var currentHeight = 0;
if (scrollDiv.scrollHeight > 0)
currentHeight = scrollDiv.scrollHeight;
else
if (objDiv.offsetHeight > 0)
currentHeight = scrollDiv.offsetHeight;
if (currentHeight - scrollDiv.scrollTop - ((scrollDiv.style.pixelHeight) ? scrollDiv.style.pixelHeight : scrollDiv.offsetHeight) < this.bottomThreshold)
scrollDiv.scrollTop = currentHeight;
scrollDiv = null;
}
Update 1:
<script type="text/javascript">
var chatscroll = new Object();
var chatScrollPane = new chatscroll.Pane('div1');
chatScrollPane.activeScroll()
chatscroll.Pane = function (scrollContainerId) {
this.bottomThreshold = 25;
this.scrollContainerId = scrollContainerId;
}
chatscroll.Pane.prototype.activeScroll = function () {
var scrollDiv = document.getElementById(this.scrollContainerId);
var currentHeight = 0;
if (scrollDiv.scrollHeight > 0)
currentHeight = scrollDiv.scrollHeight;
else
if (objDiv.offsetHeight > 0)
currentHeight = scrollDiv.offsetHeight;
if (currentHeight - scrollDiv.scrollTop - ((scrollDiv.style.pixelHeight) ? scrollDiv.style.pixelHeight : scrollDiv.offsetHeight) < this.bottomThreshold)
scrollDiv.scrollTop = currentHeight;
scrollDiv = null;
}
</script>

chatscroll.Pane is designed to be used as a constructor. You would construct an instance like this:
new chatscroll.Pane('somescrollContainerId');
The returned value becomes reusable if you assign it to a variable.
var chatScrollPane = new chatscroll.Pane('somescrollContainerId');
The scrollContainerId you pass in will be the ID (id attribute) of the DIV element in your HTML document that you want to use this object with.
You shouldn't need to declare it in your window.onload, but that certainly won't hurt. All the constructor is doing is creating a new object, setting the this value to that new object, creating and setting bottomThreshold and scrollContainerId properties therein, then returning this new object when the constructor is finished.
Just make sure you never call the activeScroll function until after the document is fully parsed, since that actually goes into your document to retrieve and manipulate elements.

Related

Photoshop javascript batch replace smart layer from folder and resize

I am trying to work out how to use javascript with photoshop, but eventhough i dont find a logical error in the code, it doesnt work properly.
I have a folder of 1000+ images/.ai files that have varying dimensions. I need these images on the Pillow and saved as .jpeg.
I choose the smartlayer and run the script to choose the images and it saves them correctly. The only problem is, that the resizing of images and positioning dont work properly.
If i put the image in manually, it works without issues, but not with the script.
If the width is greater than the height, it should set the width to 1200 px and calculate the height according to that. (and vice versa) and place in the middle of the layer.
How do i fix the resizing and positioning?
Is it possible to choose a folder where the images are inside instead of selecting the images?
How do i handle it when there are 2 smart layers to change in the mockup instead of 1?
Anyone know where the problem lies this code?
Im grateful for any bit of help!
// Replace SmartObject’s Content and Save as JPG
// 2017, use it at your own risk
// Via #Circle B: https://graphicdesign.stackexchange.com/questions/92796/replacing-a-smart-object-in-bulk-with-photoshops-variable-data-or-scripts/93359
// JPG code from here: https://forums.adobe.com/thread/737789
#target photoshop
if (app.documents.length > 0) {
var myDocument = app.activeDocument;
var theName = myDocument.name.match(/(.*)\.[^\.]+$/)[1];
var thePath = myDocument.path;
var theLayer = myDocument.activeLayer;
// JPG Options;
jpgSaveOptions = new JPEGSaveOptions();
jpgSaveOptions.embedColorProfile = true;
jpgSaveOptions.formatOptions = FormatOptions.STANDARDBASELINE;
jpgSaveOptions.matte = MatteType.NONE;
jpgSaveOptions.quality = 8;
// Check if layer is SmartObject;
if (theLayer.kind != "LayerKind.SMARTOBJECT") {
alert("selected layer is not a smart object")
} else {
// Select Files;
if ($.os.search(/windows/i) != -1) {
var theFiles = File.openDialog("please select files", "*.psd;*.tif;*.jpg;*.ai", true)
} else {
var theFiles = File.openDialog("please select files", getFiles, true)
};
};
(function (){
var startRulerUnits = app.preferences.rulerUnits;
app.preferences.rulerUnits = Units.PIXELS;
var bounds = activeDocument.activeLayer.bounds;
var height = bounds[3].value - bounds[1].value;
var width = bounds[2].value - bounds[0].value;
if (height > width){
var newSize1 = (100 / width) * 800;
activeDocument.activeLayer.resize(newSize1, newSize1, AnchorPosition.MIDDLECENTER);
app.preferences.rulerUnits = startRulerUnits;
}
else{
var newSize2 = (100 / height) * 800;
activeDocument.activeLayer.resize(newSize2, newSize2, AnchorPosition.MIDDLECENTER);
app.preferences.rulerUnits = startRulerUnits;
}
})();
if (theFiles) {
for (var m = 0; m < theFiles.length; m++) {
// Replace SmartObject
theLayer = replaceContents(theFiles[m], theLayer);
var theNewName = theFiles[m].name.match(/(.*)\.[^\.]+$/)[1];
// Save JPG
myDocument.saveAs((new File(thePath + "/" + theName + "_" + theNewName + ".jpg")), jpgSaveOptions, true,Extension.LOWERCASE);
}
}
};
// Get PSDs, TIFs and JPGs from files
function getFiles(theFile) {
if (theFile.name.match(/\.(psd|tif|jpg)$/i) != null || theFile.constructor.name == "Folder") {
return true
}
};
// Replace SmartObject Contents
function replaceContents(newFile, theSO) {
app.activeDocument.activeLayer = theSO;
// =======================================================
var idplacedLayerReplaceContents = stringIDToTypeID("placedLayerReplaceContents");
var desc3 = new ActionDescriptor();
var idnull = charIDToTypeID("null");
desc3.putPath(idnull, new File(newFile));
var idPgNm = charIDToTypeID("PgNm");
desc3.putInteger(idPgNm, 1);
executeAction(idplacedLayerReplaceContents, desc3, DialogModes.NO);
return app.activeDocument.activeLayer
};
I have attached 2 pictures. 1 how it needs to look like and 2 what the script outputs
Correct
Wrong
Your replaced images have to be the same resolution as the smart object.
You can declare the folder path in your code. If you still want to select the path by hand, you can select one image in the path, and extract the parent folder path.
You can recursively go through all of the layers in the documents and extract all the smart objects that you want to replace.
You may want a function to recursively traverse all the layers in the document
function browseLayer(layer, fn) {
if (layer.length) {
for (var i = 0; i < layer.length; ++i) {
browseLayer(layer[i], fn)
}
return;
}
if (layer.layers) {
for (var j = 0; j < layer.layers.length; ++j) {
browseLayer(layer.layers[j], fn);
}
return;
}
//apply this function for every layer
fn(layer)
}
Get all the smart objects in the document
const smartObjects = [];
//The smart objects can be visit twice or more
//use this object to mark the visiting status
const docNameIndex = {};
const doc = app.open(new File("/path/to/psd/file"));
browseLayer(doc.layers, function (layer) {
//You cannot replace smart object with position is locked
if (layer.kind == LayerKind.SMARTOBJECT && layer.positionLocked == false) {
smartLayers.push(layer);
doc.activeLayer = layer;
//open the smart object
executeAction(stringIDToTypeID("placedLayerEditContents"), new ActionDescriptor(), DialogModes.NO);
//activeDocument is now the smart object
const docName = app.activeDocument.name;
if (!docNameIndex[docName]) {
docNameIndex[docName] = true;
smartObjects.push({
id: layer.id,
name: layer.name,
docName: docName,
width : app.activeDocument.width.as('pixels'),
height : app.activeDocument.height.as('pixels'),
resolution : app.activeDocument.resolution //important
});
}
//reactive the main document
app.activeDocument = doc;
}
});
I assume that you have two smart objects needed to replace, the images for replacement are stored in different folders with the same name.
smartObjects[0].replaceFolderPath = "/path/to/folder/1";
smartObjects[1].replaceFolderPath = "/path/to/folder/2";
//we need temp folder to store the resize images
smartObjects[0].tempFolderPath = "/path/to/temp/folder/1";
smartObjects[1].tempFolderPath = "/path/to/temp/folder/2";
Ex: The first iteration will replace smartObjects[0] with "/path/to/folder/1/image1.jpg", and smartObjects[1] with "/path/to/folder/image1.jpg"
Now resize all the images following the properties of the smart objects
smartObjects.forEach(function(smartObject){
//Get all files in the folder
var files = new Folder(smartObject.replaceFolderPath).getFiles();
//Resize all the image files
files.forEach(function (file) {
var doc = app.open(file);
doc.resizeImage(
new UnitValue(smartObject.width + ' pixels'),
new UnitValue(smartObject.height + ' pixels'),
smartObject.resolution
);
//save to temp folder
doc.saveAs(
new File(smartObject.tempFolderPath + "/" + file.name),
new PNGSaveOptions(),
true
);
doc.close(SaveOptions.DONOTSAVECHANGES)
});
});
Finally, replace the smart object
//get list of file again
var files = new Folder(smartObject.replaceFolderPath).getFiles();
files.forEach(function(file){
var fileName = file.name;
smartObjects.forEach(function(smartObject){
//active the window opening the smart object
app.activeDocument = app.documents.getByName(args.documentName);
var desc = new ActionDescriptor();
desc.putPath(charIDToTypeID("null"), new File(smartObject.tempFolderPath + "/" + fileName));
executeAction(stringIDToTypeID( "placedLayerReplaceContents" ), desc, DialogModes.NO);
});
//Now export document
var webOptions = new ExportOptionsSaveForWeb();
webOptions.format = SaveDocumentType.PNG; // SaveDocumentType.JPEG
webOptions.optimized = true;
webOptions.quality = 100;
doc.exportDocument(new File("/path/to/result/folder" + file.name), ExportType.SAVEFORWEB, webOptions);
});
Now you can close all the opening smart objects
smartObjects.forEach(function (s) {
app.documents.getByName(r.docName).close(SaveOptions.DONOTSAVECHANGES);
});

drawImage is not working

var canvas = null;
var context = null;
var img = null;
var frames = [];
var assets = [];
var imgLoadCount = 0;
setup = function (fileArray) {
assets = fileArray;
//Loading an image
for(var i = 0; i < assets.length; i++) {
console.log(i);
frames.push(new Image()); // declare image object
frames[i].onload = onImageLoad(assets.length); //declare onload method
frames[i].src = URL.createObjectURL(assets[i]); //set url
}
};
onImageLoad = function (len) {
console.log("IMAGE!!!");
canvas = document.getElementById("my_canvas"); //creates a canvas element
context = canvas.getContext('2d');
canvas.width = window.innerWidth; //for full screen
canvas.height = window.innerHeight;
var x, y, numTilesRow;
numTilesRow = 10;
imgLoadCount++;
console.log("imgLoadCount = " + frames.length + ", length = " + len);
if(imgLoadCount != len) {
return;
}
for(var index = 0; index < len; index++) {
x = Math.floor((index % numTilesRow));
y = Math.floor(index / numTilesRow);
worldX = x * numTilesRow;
worldY = y * numTilesRow;
context.drawImage(frames[index], worldX, worldY);
}
};
I cant tell why drawImage has suddenly stopped working after inserting the code
if(imgLoadCount != len) {return;} that makes sure that all images are properly loaded. Would some one please help me find a solution to this problem.
You'll have to understand the difference between a function reference and a function call. The .onload property expects to be assigned with a function reference, but you assign it with the return value of the immediate(!) call to the function .onImageLoad. The difference is the parentheses ().
If you want to call a function with parameters as a callback to .onload, then you'd have to include it into an anonymous function (which itself is a function reference)
frames[i].onload = function() {onImageLoad(assets.length);};
With this, of course, you create a closure. This means that at the point of execution the onImageLoad() method will have access to the current value of assets.length (and not to the value at the point of assignment!). But in your case this doesn't make any difference, because assets.length never changes.

webGL story sphere popups

I am trying to adapt the really cool looking WebGL Story Sphere, source code and css here. There's one big problem: once you click on a news article, the text of the article in the popup is always the same. I want to modify the code so that when you click on an article, the right text appears in the popup.
I'm working from a set of article texts that I specify in the code, e.g. var captions = ["good","better","best"]. Though the article titles and images populate correctly in the popup, I can't get the text to do so. Can you help me?? Here's what I've got:
// function code
var passvar = null; // failed attempt to store texts for later
function initialize() {
math = tdl.math;
fast = tdl.fast;
canvas = document.getElementById("canvas");
g_fpsTimer = new tdl.fps.FPSTimer();
hack();
canvas.addEventListener("mousedown", handleMouseDown, false);
canvas.addEventListener("mousemove", handleMouseMove, false);
canvas.addEventListener("mouseup", handleMouseUp, false);
// Create a canvas 2d for making textures with text.
g_canvas2d = document.createElement('canvas');
window.two2w = window.two2h = g_tilesize;
g_canvas2d.width = two2w;
g_canvas2d.height = two2h;
g_ctx2d = g_canvas2d.getContext("2d");
window.gl = wu.create3DContext(canvas);
if (g_debug) {
gl = wd.makeDebugContext(gl, undefined, LogGLCall);
}
//gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, gl.TRUE);
// Here is where I specify article titles, images, captions
// Titles and images populate the popup correctly, captions don't...
var titles = ["a","b","c"];
var captions = ["good","better","best"];
var images = ['imagesphere/assets/1.jpg',
'imagesphere/assets/bp/2.png',
'imagesphere/assets/bp/3.png'
];
var headlines = titles.concat( titles);
var blurbs = captions.concat( captions);
var tmpImages = [];
var tmpHeadlines = [];
var tmpCaptions = [];
// make a bunch of textures.
for (var ii = 0; ii < g_imagesDownGrid; ++ii) {
var textures = [];
for (var jj = 0; jj < g_imagesAcrossGrid; ++jj) {
var imgTexture = new ImgTexture();
textures.push(imgTexture);
if (tmpImages.length == 0) {
tmpImages = images.slice();
}
if (tmpHeadlines.length == 0) {
tmpHeadlines = headlines.slice();
}
if (tmpCaptions.length == 0) {
tmpCaptions = blurbs.slice();
}
var rando = math.randomInt(tmpImages.length);
var img = tmpImages.splice(rando, 1)[0];
var headline = tmpHeadlines.splice(rando, 1)[0];
var caption = tmpCaptions.splice(rando, 1)[0];
passvar = caption;
if (img.indexOf('videoplay.jpg') > -1){
window.vidtexture = imgTexture;
images = images.slice(1); // dont use that thumb again.
headlines = 'WebGL Brings Video To the Party as Well'
}
imgTexture.load(img, /* "[" + jj + "/" + ii + "]" + */ headline);
}
g_textures.push(textures);
}
// And here's where I try to put this in a popup, finally
// But passvar, the stored article text, never refreshes!!!
<div id="story" class="prettybox" style="display:none">
<img class="close" src="imagesphere/assets/close.png">
<div id="storyinner">
<input id = "mytext">
<script>document.getElementById("mytext").value = passvar;</script>
</div>
</div>
And here is my click handler code:
function sphereClick(e){
window.console && console.log('click!', e, e.timeStamp);
var selected = g_textures[sel.y][sel.x];
window.selected = selected;
animateGL('eyeRadius', glProp('eyeRadius'), 4, 500);
var wwidth = $(window).width(),
wheight = $(window).height(),
story = $('#story').width( ~~(wwidth / 7 * 4) ).height( ~~(wheight / 6 * 5) ),
width = story.width(),
height = story.height(),
miniwidth = 30;
story.detach()
.find('#storyinner').find('h3,img,caption').remove().end().end()
.show();
story.css({
left : e.pageX,
top : e.pageY,
marginLeft : - width / 2,
marginTop : - height / 2
}).appendTo($body); // we remove and put back on the DOM to reset it to the correct position.
$('style.anim.story').remove();
$('<style class="anim story">')
.text( '.storyopen #story { left : ' + (wwidth / 3 * 2) + 'px !important; top : ' + wheight / 2 + 'px !important; }' )
.appendTo($body);
$(selected.img).prependTo('#storyinner').parent();
$('<h3>').text(selected.msg.replace(/\(.*/,'')).prependTo('#storyinner');
$body.addClass('storyopen');
} // eo sphereClick()
There's a lot wrong here, but here's a start. It won't solve your problem, but it will help you avoid issues like this.
var passvar = null; is a global variable.
Your loop for (var ii = 0; ... sets that global variable to a new value on every iteration.
Later, you click something and the global variable passvar is never changed.
If you want to use this pattern, you need to set passvar from your click handler so it has the value that was clicked. Since you didn't actually post your click handlers, it's hard to advise more.
But this is also a bad pattern, functions take arguments for a good reason. Since you have to find your clicked item in the click handler anyway, why not pass it directly which does involve a shared global variable at all?
var handleMouseUp = function(event) {
var story = findClickedThing(event);
if (obj) {
showPopup(story.texture, story.caption);
}
}
Which brings me to this:
var titles = ["a","b","c"];
var captions = ["good","better","best"];
var images = ['imagesphere/assets/1.jpg',
'imagesphere/assets/bp/2.png',
'imagesphere/assets/bp/3.png'
];
When you have 3 arrays, all of the same length, each array describing a different property of an object, you are doing it wrong. What you want, is one array of objects instead.
var stories = [
{
title: "a",
caption: "good",
image: "imagesphere/assets/1.jpg"
}, {
title: "b",
caption: "better",
image: "imagesphere/assets/bp/2.jpg"
}, {
title: "c",
caption: "best",
image: "imagesphere/assets/bp/3.jpg"
},
];
console.log(stories[1].caption); // "better"
Now once you find the clicked object, you can just ask it what it's caption is. And you can pass the whole object to the popup maker. And no field is handled differently or passed around in a different manner, because you are not passing around the fields. You are passsing the entire object.

I'm trying to stop snow script and clear the page after x seconds

How can I make the snow clear after a certain time. I've tried using variables and the calling a timeout which switches on to false and stops the makesnow() function but that doesn't seem to clear the page at all.
<script language="javascript">
ns6 = document.getElementById;
ns = document.layers;
ie = document.all;
/*******************[AccessCSS]***********************************/
function accessCSS(layerID) { //
if(ns6){ return document.getElementById(layerID).style;} //
else if(ie){ return document.all[layerID].style; } //
else if(ns){ return document.layers[layerID]; } //
}/***********************************************************/
/**************************[move Layer]*************************************/
function move(layer,x,y) { accessCSS(layer).left=x; accessCSS(layer).top = y; }
function browserBredde() {
if (window.innerWidth) return window.innerWidth;
else if (document.body.clientWidth) return document.body.clientWidth;
else return 1024;
}
function browserHoyde() {
if (window.innerHeight) return window.innerHeight;
else if (document.body.clientHeight) return document.body.clientHeight;
else return 800;
}
function makeDiv(objName,parentDiv,w,h,content,x,y,overfl,positionType)
{
// positionType could be 'absolute' or 'relative'
if (parentDiv==null) parentDiv='body';
var oDiv = document.createElement ("DIV");
oDiv.id = objName;
if (w) oDiv.style.width = w;
if (h) oDiv.style.height= h;
if (content) oDiv.innerHTML=content;
if (positionType==null) positionType="absolute";
oDiv.style.position = positionType;
if (x) oDiv.style.left=x; else oDiv.style.left=-2000;
if (y) oDiv.style.top=y; else oDiv.style.top=-2000;
if (overfl) oDiv.style.overflow=overfl; else oDiv.style.overflow="hidden";
eval(' document.'+parentDiv+'.appendChild (oDiv); ');
delete oDiv;
}
var snowC=0;
var x = new Array();
var y = new Array();
var speed = new Array();
var t=0;
var cC = new Array();
var ra = new Array();
function makeSnow() {
x[snowC] = Math.round(Math.random()*(browserBredde()-60));
y[snowC] = 10;
makeDiv("snow"+snowC,"body",32,32,'<img src="http://i693.photobucket.com/albums/vv296/KIBBLESGRAMMY/CAT/Orange-tabby-cat-icon.gif">');
speed[snowC] = Math.round(Math.random()*8)+1;
cC[snowC]=Math.random()*10;
ra[snowC] = Math.random()*7;
snowC++;
}
function moveSnow() {
var r = Math.round(Math.random()*100);
if (r>70 && snowC<20) makeSnow();
for (t=0;t<snowC;t++) {
y[t]+=speed[t];move("snow"+t,x[t],y[t]);
if (y[t]>browserHoyde()-50) {y[t] = 10;x[t] = Math.round(Math.random()*(browserBredde()-60));}
cC[t]+=0.01;
x[t]+=Math.cos(cC[t]*ra[t]);
}
setTimeout('moveSnow()',20);
}
moveSnow();
</script>
makeSnow just adds the snowflakes. Stopping that, as you say, does not clear anything. moveSnow handles the animation, and calls itself at a timeout. If instead of setting a timeout for the next moveSnow each time, you set it up to run in an interval just once, you would have an easier time stopping it.
window.snowAnimation = window.setInterval(moveSnow, 20);
If you add a css class to your snow flakes, it would be easier to target them for deletion.
oDiv.className = 'snowflake';
Then your clear function could look something like:
function clearSnow() {
window.clearTimeout(window.snowAnimation);
var flakes = document.getElementsByTagName('snowflake');
for(var i = 0, l = flakes.length; i < l; i++) {
document.body.removeChild(flakes[i]);
}
}
Timeout doesnt help, it helps you only to stop creating new snowdivs, however if you see makeDiv is the one which creates new divs on to the body, if you clear / display:none the divs which got created on makeDiv i hope it will clear all the divs on the screen.
You need to remove the divs that were created. It might be easier if you give them all some sort of class, like ".snowflake" as you create them (in makeDiv), then start removing them from the dom.
You will have to clear the elements created after the time you wanna stop snow falling.
Following code snippet will help you to clear the elements
if(count < 500){
setTimeout('moveSnow()',20);
}else{
var i = 0;
var elem = document.getElementById('snow'+i);
do{
elem.parentNode.removeChild(elem);
elem = document.getElementById('snow'+ ++i);
}while(elem != null)
}
count++;
you have to create a global variable count.

Undefined error using javascript objects

I am newbie to javascript objects and I have a problem. I am trying to make an image gallery but I keep getting an error that this.current, this.size & this.initial are undefined, and therefore, the script cannot work. Please help me resolve this error. the following is the full script.
function gallery()
{
this.image = new Array(10);
this.initial = 1;
this.current = 0;
this.size = 10;
this.frame_height = 400;
this.frame_width = 600;
this.initialize=function()
{
if(document.images)
{
var count = 1;
for(count=1;count<=this.size;count++)
{
this.image[count] = new Image();
this.image[count].src = 'images/'+count+'.jpg';
}
}
divImg.id = "divImg";
divImg.setAttribute("Width",this.frame_width);
divImg.setAttribute("align","center");
divImg.setAttribute("margin","0px auto");
divBtn.id = "divBtn";
divBtn.setAttribute("align","center");
divBtn.setAttribute("backgroung-color","Black");
divBtn.setAttribute("color","White");
divBtn.style.margin = "0px auto";
divBtn.className ="btn";
pictureFrame.src = this.image[this.initial].src;
pictureFrame.setAttribute('Width',this.frame_width);
pictureFrame.setAttribute('Height',this.frame_height);
pictureFrame.name = 'img';
btnNext.innerHTML='NEXT';
btnPrevious.innerHTML='PREVIOUS';
btnLast.innerHTML='LAST';
btnFirst.innerHTML='FIRST';
btnFirst.onclick=this.first;
btnLast.onclick=this.last;
btnPrevious.onclick=this.previous;
btnNext.onclick=this.next;
myForm.appendChild(pictureFrame);
divImg.appendChild(myForm);
divBtn.appendChild(btnFirst);
divBtn.appendChild(btnPrevious);
divBtn.appendChild(btnNext);
divBtn.appendChild(btnLast);
pageBody.appendChild(divImg);
pageBody.appendChild(divBtn);
headerTag.appendChild(pageBody);
}
this.next=function()
{
alert(this.size);
alert(this.current);
if (this.current < this.size)
{
this.current +=1;
pictureFrame.src = this.image[this.current].src;
}
else
{
alert("This is the last image");
}
}
this.previous=function()
{
alert(this.current);
alert(this.initial);
if (this.current > this.initial)
{
this.current = this.current-1;
pictureFrame.src = this.image[this.current].src;
}
else
{
alert("This is the first image");
}
}
this.first=function()
{
this.current=this.initial;
pictureFrame.src = this.image[this.current].src;
}
this.last=function()
{
alert(this.size);
this.current=this.size;
pictureFrame.src = this.image[this.current].src;
}
};
var divImg= document.createElement('div');
var divBtn = document.createElement('div');
var btnFirst= document.createElement('button');
var btnNext= document.createElement('button');
var btnPrevious= document.createElement('button');
var btnLast= document.createElement('button');
var divTop = document.createElement('div');
var headerTag = document.getElementsByTagName('html')[0];
var pageBody = document.createElement('body');
var myForm=document.createElement("form");
var pictureFrame = document.createElement('img');
var pics=new gallery();
window.onload=pics.initialize();
You're expierencing an out of scope failure which is very common to people who are new to ECMAscript.
Every function has it's own execution context and each context in ECMA-/Javascript has its own this context variable. To avoid this, the most common way is to store a reference to the "outer" this context-variable in a local variable:
function gallery()
{
this.image = new Array(10);
this.initial = 1;
this.current = 0;
this.size = 10;
this.frame_height = 400;
this.frame_width = 600;
var self = this;
//...
this.initialize=function()
{
if(document.images)
{
var count = 1;
for(count=1;count<=self.size;count++)
{
self.image[count] = new Image();
self.image[count].src = 'images/'+count+'.jpg';
}
}
// ...
This will work in like every Javascript environment. In the meantime, there are "better" (other) ways to avoid this problem in ECMA. For instance, ECMAscript Edition 5 introduces the .bind() method which let you "bind" the reference from the this context variable to an object of your choice. Lots of javascript frameworks offer a pretty similar way of binding this to an object, even Javascript itself lets you do it with a little effort.
What jAndy said is correct, when the window object calls pics.initialise, this refers to window (this refers to the caller of the function, unless the function is anonymous).
However there is a simpler solution that you may prefer:
Instead of
var pics = new gallery();
window.onload = pics.initialize;
You can do:
var pics = new gallery();
window.onload = function() {
pics.initialize();
};
Because it is wrapped in an anonymous function, this will refer to the gallery instance, instead of window.
jAndy's suggestions are definitely more robust, but may be a bit difficult for someone still grappling with Javascript.

Categories

Resources