views:

764

answers:

3

I'm trying to create a small Javascript "framework" that I can use in my greasemonkey scripts. I only need very basic functions, so this is why I choose not to use mooTools or DOMAssistant. Besides, I'm not going to be silly and put DOMAssitant in a 20KB Greasemonkey script! I just want a small, neat snippet of code.

I have a small problem with the below code. I think its because I am returning an array in $() so I get .setStyle is not a function error message.


var fmini = {  
  $ : function(a) {
    var i=0,obj,d;
    var e = [];

    while (obj = arguments[i++]) {
      d = document.getElementById(obj);
      d.setStyle = fmini.setStyle;
      d.each = fmini.each;
      e.push(d);
    }

    return e;
  },
  setStyle : function(style, value) {
    if (typeof this.style.cssText !== 'undefined') {
      var styleToSet = this.style.cssText;
      if (typeof style === 'object') {
        for (var i in style) 
          if (typeof i === 'string') styleToSet += ';' + i + ':' + style[i];
      }
      else styleToSet += ';' + style + ':' + value;
      this.style.cssText = styleToSet;
    }
    return this;
  },
  each : function (functionCall) {
       for (var i=0, il=this.length; i < il; i++) 
        functionCall.call(this[i]);
       return this;
    },
}
window.$ = fmini.$;

I would like this to work when I do


  $('bob','amy').setStyle({
    'border' : '5px solid #ff0000',
    'background-color' : '#ccc'
    });
+5  A: 

Write your methods to operate on the set of nodes returned from $. That way both $('bob').setStyle() and $('bob', 'amy').setStyle() will work. I see you have a generic forEach or each method which is a good start.

var fmini = {
    $: function() {
        var i=0, obj;
        var e = [];
        e.setStyle = fmini.setStyle;
        e.each = fmini.each;

        while (obj = arguments[i++]) {
            e.push(document.getElementById(obj));
        }

        return e;
    },

    setStyle : function(style, value) {
        return this.each(function() {
            if (typeof this.style.cssText !== 'undefined') {
                var styleToSet = this.style.cssText;
                if (typeof style === 'object') {
                    for (var i in style) 
                        if (typeof i === 'string') styleToSet += ';' + i + ':' + style[i];
                }
                else styleToSet += ';' + style + ':' + value;
                this.style.cssText = styleToSet;
            }
        })
    }
}

Incidentally this is something jQuery was the first to do/popularze.

Crescent Fresh
-1, $ is still returning an array of functions (in this case), and you cant access them like `$().setStyle`
Luca Matteis
Of objects im sorry.
Luca Matteis
@sktrdie: you missed the part where I attached `setStyle` to said array of objects. Please re-read.
Crescent Fresh
Interesting, I've never seen this type of augmentation on arrays ([]), sorry about this, and thanks I guess I learned something. Can you augment on pretty much anything?
Luca Matteis
@sktrdie: yes you can augment anything. Although the approach in the code sample will work, it is wasteful wrt memory. Memory will be allocated for the extra methods everytime `$` is called. jQuery does it right.
Crescent Fresh
Thank you crescentfresh! It works perfectly. So if I had lots of '$' calls I would waste lots of extra memory? Is there anyway around this?
Gary Green
@Gary: Yes. Use a prototype and instantiate it in `$`. The functions don't get copied over to new objects, rather new objects reuse the same functions that are bound to the instantiated objects. Ask another question if you don't know wth I'm talking about (should get lots of help on this topic).
Crescent Fresh
+1  A: 

Like you had suspected the return of $ in this case is an array of the elements, you have to extend array with setStyle or add the extension when the array is populated before you pass the array back. Then you shouldn't get an error saying .setStyle is not a function. However you will have to also make sure you handle your object context binding when you are chaining like this otherwise this is referring to the current scope and not an element in your array.

Quintin Robinson
+1  A: 

The $ function is returning an array; it should either be returning the element object itself (d) on which you augment the setStyle method, or just another object.

Luca Matteis