This must be a very stupid question, but I just can't get it to work.
I'm creating my own UIKit for iOS. (Website-kit which will allow iPhone-like interfaces).
But, I'm trying to create a JavaScript library, which can be used to change several elements of the document. For instance, set a custom background colour when the document loads.
I'm trying to do that with object-orientated JavaScript. Like this:
var UI = new Interface();
UI.setBackground("#000");
How could I achieve this?
(So the custom "UI" Object, and (an example) on how to change the background color of the document, from INSIDE the object.)
You can save a reference to the DOM inside the JS object and rewrite it as needed.
function Interface() {
this.setBackground = function (color) {
this.pointTo.style.background = color;
};
this.pointTo = document.body;
}
You can initialize this by:
var UI = new Interface();
UI.pointTo = document.getElementById('some_id');
UI.setBackground("#000");
// Set another style, on a different element
UI.pointTo = document.getElementById('some_other_id');
UI.setBackground("#FFF");
This is a simple implementation and need to be allot smarter, but it should do the job.
Edit:
Made a mistake in original posting, and fixed erroneous code. Also made an example: http://jsfiddle.net/HpW3E/
Like silverstrike's code, but you can pass the target object in the interface constructor to don't get trouble in the future.
function Interface(target) {
target = target || document.body;
this.setBackground = function (color) {
target.style.background = color || 'white';
};
}
Ok now you can do this:
var UI = new Interface(document.body);
UI.setBackground("#000");
or even in somecases that you are applying the interface in global scope !ONLY!:
var UI = new Interface(this.body);
UI.setBackground("#000");
Also will work as this:
var UI = new Interface();
UI.setBackground("#000");
Here is a very simple approach
// define the object
var Interface = function () {
var interface = document.getElementById("interface"); // just an example
// your new methods
this.setBackground = function (color) {
interface.style.backgroundColor = color;
}
// rest of your code
}
now you can make use of it
var UI = new Interface();
UI.setBackground("#000");
Related
I'm making my first Jquery Plugin and overcome many problems after I found one that I can not find solution.
The plugin convert a table in a tree-gridview doing a $(element).treeGD(); sentence, that part works ok. But i want to reload all data doing $(element).treeGD.reload();
The first sentence creates an object objTreeGD(obj):
$.fn.treeGD = function () {
var treeGD = new objTreeGD(this);
And adding the second method in the way i'll show you now and trying to use the same treeGD object created above gives me an error (undefined)
$.fn.treeGD.reload = function () {
var urlDatos = treeGD.attr("data-url");
Is there a way to access to that firs object i've created?
Thanks
May be you can use .data() method?
$.fn.treeGD = function () {
var treeGD = new objTreeGD(this);
this.data("myTree", treeGD );
And then, access using:
$.fn.treeGD.reload = function () {
var urlDatos = this.data("myTree").attr("data-url");
I'm working with limeJS trying to figure out the best way to put a GUI over limeJS. Here's a better explanation:
I've created two classes, one called 'SceneWithGui' and another called 'GuiOverlay'. My intention is that 'SceneWithGui' inherits from 'lime.Scene', adding a property and two methods:
guiLayer (which is a GuiOverlay object)
setGuiLayer
getGuiLayer
As follows:
//set main namespace
goog.provide('tictacawesome.SceneWithGui');
//get requirements
goog.require('lime.Scene');
goog.require('tictacawesome.GuiOverlay');
tictacawesome.SceneWithGui = function() {
lime.Node.call(this);
this.guiLayer = {};
};
goog.inherits(tictacawesome.SceneWithGui, lime.Scene);
tictacawesome.SceneWithGui.prototype.setGuiLayer = function (domElement){
this.guiLayer = new tictacawesome.GuiOverlay(domElement);
};
tictacawesome.SceneWithGui.prototype.getGuiLayer = function (){
return this.guiLayer;
};
The intention with 'GuiOverlay' is to make it hold the DOM element in a way that when the Scene or the Director get resized, it will too. For it, I just inherited from 'lime.Node', hoping it is something already set on it. My code:
//set main namespace
goog.provide('tictacawesome.GuiOverlay');
//get requirements
goog.require('lime.Node');
tictacawesome.GuiOverlay = function(domElement){
lime.Node.call(this);
this.setRenderer(lime.Renderer.DOM);
this.domElement = domElement;
};
goog.inherits(tictacawesome.GuiOverlay, lime.Node);
And that's basically the idea of it all. For better visualization, here's a sample use:
//set main namespace
goog.provide('tictacawesome.menuscreen');
//get requirements
goog.require('lime.Director');
goog.require('lime.Scene');
goog.require('lime.Layer');
goog.require('lime.Sprite');
goog.require('lime.Label');
goog.require('tictacawesome.SceneWithGui');
tictacawesome.menuscreen = function(guiLayer) {
goog.base(this);
this.setSize(1024,768).setRenderer(lime.Renderer.DOM);
var backLayer = new lime.Layer().setAnchorPoint(0, 0).setSize(1024,768),
uiLayer = new lime.Layer().setAnchorPoint(0, 0).setSize(1024,768),
backSprite = new lime.Sprite().setAnchorPoint(0, 0).setSize(1024,768).setFill('assets/background.png');
backLayer.appendChild(backSprite);
this.appendChild(backLayer);
lime.Label.installFont('Metal', 'assets/metalang.ttf');
var title = new lime.Label().
setText('TicTacAwesome').
setFontColor('#CCCCCC').
setFontSize(50).
setPosition(1024/2, 100).setFontFamily('Metal');
uiLayer.appendChild(title);
this.appendChild(uiLayer);
this.setGuiLayer(guiLayer);
};
goog.inherits(tictacawesome.menuscreen, tictacawesome.SceneWithGui);
It all looks pretty on code, but it just doesn't work (the scene doesn't even get displayed anymore). Here are the errors I'm getting through Chrome console:
Uncaught TypeError: Cannot read property 'style' of undefined
director.js:301
Uncaught TypeError: Cannot read property
'transform_cache_' of undefined
I'm not really experienced in JS, so the only clue I found is that this happens when 'tictacawesome.menuscreen' reaches 'goog.base(this)'.
UPDATE: After some messing with the code, I'm able to pass the previous problems I had (before this edit), and now I stumble on the ones cited above. When it reaches directior.js:301, the line is scene.domElement.style['display']='none';. scene exists, but scene.domElement doesn't. Did I somehow fucked up the domElement with my guiOverlay?
Any ideas? Any obvious flaws on my design? Am I on the right path?
Thanks.
Your SceneWithGui extends lime.Scene but you call lime.Node.call(this); in SceneWithGui.
The code in SceneWithGui should look like this:
//set main namespace
goog.provide('tictacawesome.SceneWithGui');
//get requirements
goog.require('lime.Scene');
goog.require('tictacawesome.GuiOverlay');
tictacawesome.SceneWithGui = function() {
lime.Scene.call(this);//This was lime.Node.call(this);
this.guiLayer = {};
};
goog.inherits(tictacawesome.SceneWithGui, lime.Scene);
tictacawesome.SceneWithGui.prototype.setGuiLayer = function (domElement){
this.guiLayer = new tictacawesome.GuiOverlay(domElement);
};
tictacawesome.SceneWithGui.prototype.getGuiLayer = function (){
return this.guiLayer;
};
Can find it out quite quickly when creating a normal scene with var scene = new lime.Scene() breakpoint at that line and stepping into it.
It'll take you to scene.js and then set a breakpoint at lime.Node.call(this);
Then you would have noticed when creating scene = new tictacawesome.menuscreen(); that that breakpoint never hits.
I loaded jQuery on a Firefox addon, which causes it to load using XUL's window.
I want to change the default context so it will use the correct window object.
The classic example I always see is:
var $ = function(selector,context){
return new jQuery.fn.init(selector,context|| correctWindow );
};
$.fn = $.prototype = jQuery.fn;
But doing it I kill a lot of functions, like .ajax, .browser, ... I need these methods.
AMO won't let me create an wrapper to jQuery to send the correct window object.
So my only option is to somehow change jQuery's default context without changing its source code.
What options do I have?
On the first content script I added
var loader = Components
.classes["#mozilla.org/moz/jssubscript-loader;1"]
.getService(Components.interfaces.mozIJSSubScriptLoader);
loader.loadSubScript("chrome://extensions/js/jquery-1.7.2.min.js");
var initjQuery = jQuery.fn.init;
$.fn.init = function(s,c,r) {
c = c || window.document;
return new initjQuery(s,c,r);
};
This way it works.
You change the default context with this wrapper:
jQuery.fn.init2 = jQuery.fn.init;
jQuery.prototype.init = function (selection, context, root) {
return new jQuery.fn.init2(selection, context, jQuery.context || root);
}
$(document).ready(function () {
jQuery.context = $(newContextSelector);
$("*").css("color", "red");
});
Look at context that is a jquery object.
On the upside I'm kinda bright, on the downside I'm wracked with ADD. If I have a simple example, that fits with what I already understand, I get it. I hope someone here can help me get it.
I've got a page that, on an interval, polls a server, processes the data, stores it in an object, and displays it in a div. It is using global variables, and outputing to a div defined in my html. I have to get it into an object so I can create multiple instances, pointed at different servers, and managing their data seperately.
My code is basically structured like this...
HTML...
<div id="server_output" class="data_div"></div>
JavaScript...
// globals
var server_url = "http://some.net/address?client=Some+Client";
var data = new Object();
var since_record_id;
var interval_id;
// window onload
window.onload(){
getRecent();
interval_id = setInterval(function(){
pollForNew();
}, 300000);
}
function getRecent(){
var url = server_url + '&recent=20';
// do stuff that relies on globals
// and literal reference to "server_output" div.
}
function pollForNew(){
var url = server_url + '&since_record_id=' + since_record_id;
// again dealing with globals and "server_output".
}
How would I go about formatting that into an object with the globals defined as attributes, and member functions(?) Preferably one that builds its own output div on creation, and returns a reference to it. So I could do something like...
dataOne = new MyDataDiv('http://address/?client');
dataOne.style.left = "30px";
dataTwo = new MyDataDiv('http://different/?client');
dataTwo.style.left = "500px";
My code is actually much more convoluted than this, but I think if I could understand this, I could apply it to what I've already got. If there is anything I've asked for that just isn't possible please tell me. I intend to figure this out, and will. Just typing out the question has helped my ADD addled mind get a better handle on what I'm actually trying to do.
As always... Any help is help.
Thanks
Skip
UPDATE:
I've already got this...
$("body").prepend("<div>text</div>");
this.test = document.body.firstChild;
this.test.style.backgroundColor = "blue";
That's a div created in code, and a reference that can be returned. Stick it in a function, it works.
UPDATE AGAIN:
I've got draggable popups created and manipulated as objects with one prototype function. Here's the fiddle. That's my first fiddle! The popups are key to my project, and from what I've learned the data functionality will come easy.
This is pretty close:
// globals
var pairs = {
{ div : 'div1', url : 'http://some.net/address?client=Some+Client' } ,
{ div : 'div2', url : 'http://some.net/otheraddress?client=Some+Client' } ,
};
var since_record_id; //?? not sure what this is
var intervals = [];
// window onload
window.onload(){ // I don't think this is gonna work
for(var i; i<pairs.length; i++) {
getRecent(pairs[i]);
intervals.push(setInterval(function(){
pollForNew(map[i]);
}, 300000));
}
}
function getRecent(map){
var url = map.url + '&recent=20';
// do stuff here to retrieve the resource
var content = loadResoucrce(url); // must define this
var elt = document.getElementById(map.div);
elt.innerHTML = content;
}
function pollForNew(map){
var url = map.url + '&since_record_id=' + since_record_id;
var content = loadResoucrce(url); // returns an html fragment
var elt = document.getElementById(map.div);
elt.innerHTML = content;
}
and the html obviously needs two divs:
<div id='div1' class='data_div'></div>
<div id='div2' class='data_div'></div>
Your 'window.onload` - I don't think that's gonna work, but maybe you have it set up correctly and didn't want to bother putting in all the code.
About my suggested code - it defines an array in the global scope, an array of objects. Each object is a map, a dictionary if you like. These are the params for each div. It supplies the div id, and the url stub. If you have other params that vary according to div, put them in the map.
Then, call getRecent() once for each map object. Inside the function you can unwrap the map object and get at its parameters.
You also want to set up that interval within the loop, using the same parameterization. I myself would prefer to use setTimeout(), but that's just me.
You need to supply the loadResource() function that accepts a URL (string) and returns the HTML available at that URL.
This solves the problem of modularity, but it is not "an object" or class-based approach to the problem. I'm not sure why you'd want one with such a simple task. Here's a crack an an object that does what you want:
(function() {
var getRecent = function(url, div){
url = url + '&recent=20';
// do stuff here to retrieve the resource
var content = loadResoucrce(url); // must define this
var elt = document.getElementById(div);
elt.innerHTML = content;
}
var pollForNew = function(url, div){
url = url + '&since_record_id=' + since_record_id;
var content = loadResoucrce(url); // returns an html fragment
var elt = document.getElementById(div);
elt.innerHTML = content;
}
UpdatingDataDiv = function(map) {
if (! (this instanceof arguments.callee) ) {
var error = new Error("you must use new to instantiate this class");
error.source = "UpdatingDataDiv";
throw error;
}
this.url = map.url;
this.div = map.div;
this.interval = map.interval || 30000; // default 30s
var self = this;
getRecent(this.url, this.div);
this.intervalId = setInterval(function(){
pollForNew(self.url, self.div);
}, this.interval);
};
UpdatingDataDiv.prototype.cancel = function() {
if (this.intervalId) {
clearInterval(this.intervalId);
this.intervalId = null;
}
}
})();
var d1= new UpdatingDataDiv('div1','http://some.net/address?client=Some+Client');
var d2= new UpdatingDataDiv('div2','http://some.net/otheraddress?client=Some+Client');
...
d1.cancel();
But there's not a lot you can do with d1 and d2. You can invoke cancel() to stop the updating. I guess you could add more functions to extend its capability.
OK, figured out what I needed. It's pretty straight forward.
First off disregard window.onload, the object is defined as a function and when you instantiate a new object it runs the function. Do your setup in the function.
Second, for global variables that you wish to make local to your object, simply define them as this.variable_name; within the object. Those variables are visible throughout the object, and its member functions.
Third, define your member functions as object.prototype.function = function(){};
Fourth, for my case, the object function should return this; This allows regular program flow to examine the variables of the object using dot notation.
This is the answer I was looking for. It takes my non-functional example code, and repackages it as an object...
function ServerObject(url){
// global to the object
this.server_url = url;
this.data = new Object();
this.since_record_id;
this.interval_id;
// do the onload functions
this.getRecent();
this.interval_id = setInterval(function(){
this.pollForNew();
}, 300000);
// do other stuff to setup the object
return this;
}
// define the getRecent function
ServerObject.prototype.getRecent = function(){
// do getRecent(); stuff
// reference object variables as this.variable;
}
// same for pollForNew();
ServerObject.prototype.pollForNew = function(){
// do pollForNew(); stuff here.
// reference object variables as this.variable;
}
Then in your program flow you do something like...
var server = new ServerObject("http://some.net/address");
server.variable = newValue; // access object variables
I mentioned the ADD in the first post. I'm smart enough to know how complex objects can be, and when I look for examples and explanations they expose certain layers of those complexities that cause my mind to just swim. It is difficult to drill down to the simple rules that get you started on the ground floor. What's the scope of 'this'? Sure I'll figure that out someday, but the simple truth is, you gotta reference 'this'.
Thanks
I wish I had more to offer.
Skip
I want to change the method DomElement.appendChild() to work differently when applied on an Object that I have created:
// using MooTools;
var domElement = new Class({...});
var MyObject = new domElement(...);
$(document).appendChild(MyObject); // Error
// I want to add to (extend) appendChild, to do something specific, when:
alert(MyObject instanceof domElement); // true
I could do this by modifying the mootools.js, but I want to avoid this at all costs, because I am certain one day, some other developer will overwrite the js file with an updated version, and I will be imprisoned for murder.
Please, keep me out of jail!
I dont know about MooTools, but there is a simple way in native JS to do this..
var orgAppendChild = document.appendChild;
document.appendChild = localAppendHandler;
var domElement = new Class({...});
var MyObject = new domElement(...);
// document.appendChild(MyObject);
var ss = document.createElement('tr');
document.appendChild (ss);
function localAppendHandler(MyObject)
{
if (MyObject instanceof domElement)
UrCustomRoutine(MyObject )
else
orgAppendChild(MyObject);
}
function UrCustomRoutine(MyObject ){
//your custom routine
}
Hope this helps
Update:
From your further explanation (handling appendChild of any DOM element), i understand that there is no generic way of defining local hanlders to trap the event.
But there is a workaround (this is very ugly i know). Means you have to define a LocalHandler for the DOM element before you are goin to use the appendChild .
Before doing this
document.getElementByID('divTarget').appendChild()
you have to reassign the localhandler to the element you need to access
orgAppendChild = document.getElementById('divTarget').appendChild;
document.getElementById('divTarget').appendChild = localAppendHandler;
var sss = document.createElement('table');
document.getElementById('divTarget').appendChild(sss);
Another Alternative:
If you wanted to keep it simple, i suggest this alternate way. Create AppendChild local method which accepts object and the node name as param.
function AppendChild(MyObject ,Node)
{
if (MyObject instanceof domElement)
//your custom routine
else if (Node=="" && (MyObject instanceof domElement==false))
document.appendChild(MyObject);
else if (Node!="" && (MyObject instanceof domElement==false))
eval( "document.getElementById('" + Node + "').appendChild(MyObject);");
}
And
If you wanted to append DOM element to document
AppendChild(DOMelement,"")
If you wanted to append DOM element inside other
container
AppendChild(DOMelement,"divTarget")
If you wanted to process your custom object
AppendChild(customObject,"")
this is the best way to do this.
you ought to look at using object.toElement() in your class
http://blog.kassens.net/toelement-method
then just use document.body.inject(instanceObject);
var originAppend = Element.prototype.appendChild;
Element.prototype.appendChild = function(el){
// do something to el
originAppend.call(this, el);
}