Archive for March, 2009

Error: Unable to create directory /var/www/vhosts/justswell.org/subdomains/blog/httpdocs/wp-content/uploads/2013/05. Is its parent directory writable by the server?
by admin

Cross browser key event handling with Javascript and Swell

Posted in Event, Javascript, Swell

Handling keyboard events with Javascript is an extremely difficult task considering each browser discrepancies.

One guy compiled all the differences into a single page that he adequately called “Javascript madness :  Keyboard events“, and from there you can clearly see the real madness :D

Of course we have directly experienced the aforementioned problems and found out pretty smart solutions for almost any browser.

The two major headaches were IE not firing keypress event on specific keys and Opera not able to prevent default behavior of keydown event.

HTMLEvents magic or how to fix messy browser implementation

The special keys encompass all the keys that don’t cause a character to appear, but execute a certain function.  Among these keys we can find shift, escape, pageDown, enter and so on.

Some general caveats (courtesy of quirksmode) :

  • IE doesn’t fire the keypress event for delete, end, enter, escape, function keys, home, insert, pageUp/Down and tab.
  • Onkeypress, Safari gives weird keyCode values in the 63200 range for delete, end, function keys, home and pageUp.Down. The onkeydown and -up values are normal.
  • Alt, Cmd, Ctrl and Shift cannot be detected on Mac, except in Opera. However, you can always use the altKey, ctrlKey, and shiftKey properties.

For getting rid of this weird behavior we are capturing special keys on keydown and use a static property to hold the keyname (keymapper) and keycode that we use when keypress event is fired.

As we didn’t want to hack our code too much we just simulate the keypress event on IE when the unsupported special keys are pressed.

// Check if keypressed is a special key
_specialKeyName = this.getSpecialKeyName(e.getKeyCode());
if(_specialKeyName) {
    this._specialKey = _specialKeyName;
    this._keyCode    =  e.getKeyCode();
    // This is a special key, we know that IE will not fire
    // keypress event, we'll do it for him :D
    if(Swell.Core.Browser.isIE) {
        this.simulate(o, 'keypress');
    }
}
 
/**
 * Fires programmatically a native DOM event
 * @function simulate
 *
 * @param {String|HTMLElement|Array} o the object to assign the handler to
 * @param {String} type event type : click, change, keypress, etc, never prepend "on" keyword as Swell does this job for you
 *
 * @see https://developer.mozilla.org/en/DOM/element.dispatchEvent
 * @see http://msdn.microsoft.com/en-us/library/ms536390(VS.85).aspx
*/
simulate : function(o, e) {
    var _event;
    // Testing if o is an object or a string
    // add is just dealing with DOM events, and is not meant to
    // handle custom events of Swell Objects
    // as Swell.Core.Dom is not part of the core distribution <~20K :D
    // We will use the good old document.getElementById for element retrieval
 
    if(Swell.Core.isString(o)) {
        o = _getById(o);
    } else if(Swell.Core.isArray(o)) {
        // Loop on function
        for(var n = 0; n < o.length; n++) {
            this.simulate(o[n], e);
        }
        o = null;
    }
 
    if(!o) {
        return;
    }
    if(document.createEventObject) { // IE
        _event = document.createEventObject();
        return o.fireEvent('on' + e, _event);
    }
    else {
        // All other browsers
        _event = document.createEvent('HTMLEvents');
        _event.initEvent(e, true, true); //event type,bubbling,cancellable
        return !o.dispatchEvent(_event);
    }
},
by

Empowering SwellJS adopters with CDN technology

Posted in Swell

One of our objectives is to make usage of SwellJS easy in order to maximize its adoption. Usually one of the major drawbacks is the installation.
Most software you want to use on your website will require you to download it, extract it, upload it, and keep it up to date.

One of the best ways we found on SwellJS to reduce installation hassle is to remove the installation process. We will instead provide the library via a CDN.

So, what will a “CDN” do, and how does it helps to avoid installation of the SwellJS library?

Read the rest of this entry »

Error: Unable to create directory /var/www/vhosts/justswell.org/subdomains/blog/httpdocs/wp-content/uploads/2013/05. Is its parent directory writable by the server?
by admin

Restrict field input with Javascript and Swell

Posted in Javascript, Swell

Today, we are delivering the first page to play around with Swell and we are quite happy of the result. We wanted to show how easy it is to restrict the characters typed in form fields.

By using the universal selector (*) built-in Swell’s Event library, you can catch any keystroke and of course retrieve its text representation  in your event handler !

Be careful the code behind the Event library is still in early Alpha stage and far from being production ready, have fun !

Restrict input chars playground page

by

Cross-browser getStyle with ease

Posted in Swell

As Element is one of the most important components, we wanted to be able to manipulate DOM, CSS and everything related to content manipulation. Our main goal is to make the user write a minimum of code while keeping the smallest codebase possible (yes, we are DRY hard fervents).

To achieve this challenging goal, we made a batch system that allows us to run a specific function without modifying it several times over given arguments.

So, to put it in a more comprehensive manner, by simply writing this snippet of code:

foo: function() {
    var _fn = function(arg) {
        return this.domEl.id + arg+ 'bar';
    }
 
    return _delegate.call(this, _fn, arguments);
}

If you execute $(‘foo’, ‘bar’, ‘baz’).foo(‘baz’); you’ll get ['foobazbar', 'barbazbar', 'bazbazbar'].
The _delegate method loops through the internal elements stack and executes on each element the given _fn.


getStyle at work

Another thing worth mentioning is the normalization process done backwards by getStyle, as properties may differ between browsers, which one should we choose? currentStyle or getComputedStyle? usually you would use chained if statements to address each possibility.

This is where our approach clearly gives better results by keeping trace of native properties  (e.g. under currentStyle “float” would be “styleFloat”, and getComputedStyle, “cssFloat”) as well as providing an abstraction layer for getting/setting values.

var _styleExceptions = {
    'CURRENT_STYLE' : {
        'float' : 'styleFloat',
        'opacity' : 'filter',
        'border' : null
    },
    'DEFAULT_VIEW'  : {
        'float' : 'cssFloat',
        'border' : null
    }
};
 
getStyle : function() {
    var _fn = function(style) {
        var _method = this._domEl.currentStyle ? { o : this._domEl.currentStyle, type : 'CURRENT_STYLE' } : { o : document.defaultView.getComputedStyle(this._domEl, null), type : 'DEFAULT_VIEW' };
 
        var _exceptions = new Swell.Core.Hashtable().inject(_styleExceptions[_method.type]);
        _exceptions.defineGetter(function(key, val, arg) {
            var _oStyle = arg.o,
                _isCurrentStyle = (arg.type === 'CURRENT_STYLE') ? true : false;
            switch(key) {
                case 'opacity':
                    if (_isCurrentStyle) {
                        return /opacity\s?=\s?([0-9]+)/.exec(_oStyle[val])[1]/100;
                    }
                case 'border':
                    return [_oStyle['borderTopWidth'], _oStyle['borderRightWidth'], _oStyle['borderBottomWidth'], _oStyle['borderLeftWidth']];
                default:
                    return _oStyle[val];
            }
        }, _method);
 
        if (_exceptions.exists(style)) {
            return _exceptions.get(style);
        }
 
        return _method.o[style];
    }
    return _delegate.call(this, _fn, arguments);
}

For example retrieving the opacity value without worrying about the browser.

    <div id="foo" style="filter:alpha(opacity=50);"></div>
    <script type="text/javascript">
        $('foo').getStyle('opacity'); // returns 0.5
    </script>
Error: Unable to create directory /var/www/vhosts/justswell.org/subdomains/blog/httpdocs/wp-content/uploads/2013/05. Is its parent directory writable by the server?
by admin

Painless publish/subscribe system with swell’s custom events

Posted in Javascript, Swell

Let me start with wikipedia’s own publish/subscribe pattern definition : Publish/subscribe (or pub/sub) is an asynchronous messaging paradigm where senders (publishers) of messages are not programmed to send their messages to specific receivers (subscribers). This decoupling of publishers and subscribers can allow for greater scalability… We absolutely wanted to have this pattern implemented into Swell as we are fervent supporters of the SoC. The goal was to be able to hook the Custom event model to potentially any class as well as using custom events outside of a class context.

Custom event model

By inheriting the CustomEventModel class built-into swell, the children class is augmented with new methods and collections brought from the model. Example :

    Swell.Core.Class({
        name        : 'Hashtable',
        namespace   : 'Swell.Core',
        inherits    : [Swell.Core.Enumerable, Swell.Core.CustomEventModel],
        ...

Swell.Core.Hashtable class now have those methods :

  • createEvent (creates a custom event that is bound to the class ex : onHashUpdated)
  • fireEvent (fires desired event and will notice all the subscribers aka execute callback functions)
  • subscribe (subscribe to a custom event of the class from/outside the class)
  • unsubscribe
  • getEvents

In the hashtable code, we use custom events to update a static property containing the length.

var _initEvents = function() {
    /**
      * Initialization of the event
      * @event onChange fires when an item is added/updated in the hashtable
    */
    this.createEvent('onHashUpdated');
    this.subscribe('onHashUpdated', _updateLength); //_updateLength is a private function of the class
}
...
/**
 * Now triggering the event
*/
set : function(key, value) {
    if(arguments.length === 1) {
        _hash[Swell.uniqueId()] = key;
    } else {
        _hash[key] = value;
    }
    this.fireEvent('onHashUpdated', this);
    return this;
},
...

Standalone custom events

This is the simplest way of using the custom event system.
In the example below we have created a basic object called button that makes use of custom events.

var button = function() {
    var value = 1;
 
    this.setValue = function(val) {
        value = val;
        this.onValueChange.fire();
    };
 
    this.onValueChange = new Swell.Core.CustomEvent('onValueChange');
}
 
var handler = function() {
    alert('button value has changed');
}
 
var btn = new button();
btn.onValueChange.subscribe(handler);
btn.setValue('toto');

And the firebug DOM :

Firebug DOM

Firebug DOM

Error: Unable to create directory /var/www/vhosts/justswell.org/subdomains/blog/httpdocs/wp-content/uploads/2013/05. Is its parent directory writable by the server?
by admin

A simple yet versatile hashtable with swell

Posted in Javascript, Swell

Today we wanted to feature the hashtable object used internally by the core components and/or widgets in Swell.

At first don ‘t get me wrong, objects used as hash-tables  is to date the most convenient way of storing static properties associated to a key, I just complain that it’s sometimes (not always) missing features you would find in other languages such as PHP.

Here’s the code :

Swell.Core.Class({
    name        : 'Hashtable',
    namespace   : 'Swell.Core',
    inherits    : [Swell.Core.Enumerable, Swell.Core.CustomEventModel],
    functions   : function() {
 
        var _hash = {};
        var _updateLength = function() {
            var _l = 0, _n;
 
            if(_hash.__count__) {
                this.length = _hash.__count__;
            } else {
                for(_n in _hash) {
                    _l++;
                }
                this.length = _l;
            }
        }
 
        var _initEvents = function() {
            /**
             * @event onChange fires when an item is added/updated in the hashtable
            */
            this.createEvent('change');
            this.subscribe('change', _updateLength);
        }
 
        return {
 
            length : 0,
 
            /**
             * Constructor, initialize enumerable
             *
             * @function construct
             * @constructor
            */
            construct : function() {
                this.setEnumerable(_hash);
                _initEvents.call(this);
            },
 
            /**
             * Resets the hashtable
             *
             * @function dispose
            */
            empty : function() {
                _hash = {};
            },
 
            /**
             * Add/Update an entry in the hashtable
             *
             * @function set
             * @param {String} key Key name
             * @return {Swell.Core.Hashtable}
            */
            set : function(key, value) {
                if(arguments.length === 1) {
                    _hash[Swell.uniqueId()] = key;
                } else {
                    _hash[key] = value;
                }
                this.fireEvent('change', this);
                return this;
            },
 
            /**
             * Add an entry in the hashtable if the key does not exist
             *
             * @function set
             * @param {String} key Key name
             * @return {Swell.Core.Hashtable}
            */
            add : function(key, value) {
                if(!this.exists(key)) {
                    this.set(key, value);
                    return this;
                }
                return false;
            },
 
            /**
             * Update an entry in the hashtable if the key exists
             *
             * @function set
             * @param {String} key Key name
             * @return {Swell.Core.Hashtable}
            */
            update : function(key, value) {
                if(this.exists(key)) {
                    this.set(key, value);
                    return this;
                }
                return false;
            },
 
            /**
             * Get the value of the corresponding key in the hashtable
             *
             * @function get
             * @param {String} key Key name
             * @return {Mixed/Boolean} value
            */
            get : function(key) {
                if(_hash.hasOwnProperty(key)) {
                    return _hash[key];
                }
                return false;
            },
 
            /**
             * Exchanges all keys with their associated values in the hashtable
             *
             * @function flip
             * @return {Swell.Core.Hashtable}
            */
            flip : function() {
                var _k, _tmp = {};
 
                for( _k in _hash ) {
                    _tmp[_hash[_k]] = _k;
                }
                _hash = _tmp;
                return this;
            },
 
            /**
             * Returns the first item of the hashtable
             *
             * @function first
             * @param {Boolean} [extended] Returns an array with the first item as key and second one as val (optional)
             * @return {Mixed}
            */
            first : function(extended) {
                for(var _p in _hash) {
                    if(!Swell.Core.isUndefined(extended)) {
                        return [_p, _hash[_p]];
                    }
                    return _hash[_p];
                }
                return false;
            },
 
            /**
             * Returns the last item of the hashtable
             *
             * @function last
             * @param {Boolean} [extended] Returns an array with the last item as key and second one as val (optional)
             * @return {Mixed}
            */
            last : function(extended) {
                var _lastitem = false;
                for(var _p in _hash) {
                    _lastitem = _hash[_p];
                }
                if(!Swell.Core.isUndefined(extended)) {
                    return [_p, _lastitem];
                }
                return _lastitem;
            },
 
            /**
             * Unsets an item from the hashtable
             *
             * @function remove
             * @return {Swell.Core.Hashtable}
            */
            remove : function(key) {
                if(_hash.hasOwnProperty(key)) {
                    delete _hash[key];
                    this.fireEvent('change', this);
                }
                return this;
            },
 
            /**
             * Applies the callback to the elements of the hashtable
             *
             * @function map
             * @return {Swell.Core.Hashtable}
            */
            map : function(fn) {
                var _p, _tmp = {};
                if(Swell.Core.isFunction(fn)) {
                    for(_p in _hash) {
                        _tmp[_p] = fn.call(null, _hash[_p]);
                    }
                }
                return _tmp;
            },
 
            /**
             * Test if a property exists in the hash table
             *
             * @function exists
             * @return {Boolean}
            */
            exists : function(key) {
                return _hash.hasOwnProperty(key);
            },
 
            /**
             * Applies an user function on every member of the hashtable
             *
             * @function walk
             * @return {Swell.Core.Hashtable}
            */
            walk : function(fn) {
                var _p;
                if(Swell.Core.isFunction(fn)) {
                    for(_p in _hash) {
                        _hash[_p] = fn.call(null, _hash[_p]);
                    }
                }
                return this;
            },
 
            /**
             * Returns an array of keys
             *
             * @function keys
             * @return {Mixed[]} keys
            */
            keys : function() {
                var _k, _tmp = [];
                for(_k in _hash) {
                    _tmp.push(_k);
                }
                return _tmp;
            },
 
            /**
             * Pop the element off the end of array
             *
             * @function pop
             * @return {Mixed} value of the popped item
            */
            pop : function() {
                var _item = this.last(true);
                delete _item[0];
 
                return _item[1];
            },
 
            /**
             * Returns an array of values
             *
             * @function values
             * @return {Mixed[]} values
            */
            values : function() {
                var _k, _tmp = [];
                for(_k in _hash) {
                    _tmp.push(_hash[_k]);
                }
                return _tmp;
            },
 
            /**
             * Returns the wrapped native object
             *
             * @function toObject
             * @return {Object}
            */
            toObject : function() {
                return _hash;
            },
 
            /**
             * Returns a string representation of the wrapped native object
             *
             * @function toSource
             * @return {String}
            */
            toSource : function() {
                if(_hash.toSource) {
                    return _hash.toSource();
                } else {
                    var _stack = [];
                    for(var _n in _hash) {
                        _stack.push('"' + _n + '" : "' + _hash[_n] + '"');
                    }
                    return '({' + _stack.join(',') + '})';
                }
            }
        }
    }()
});

But how to use it ?

A Swell class can be instantiated just like you would do with a classic object.

    var ht = new Swell.Core.Hashtable();
 
    // Put some stuff into the hashtable
    ht.set('foo', 'bar');
    ht.set('baz','bleh');
 
    //Then walk every member of the hashtable to turn the value into uppercase
    h.walk(function(member) {
        return member.toUpperCase();
    });
 
    // Output the hash, this will give us an object like : {foo : "BAR", baz : "BLEH"}
    h.toObject();
by

Swell from the underneath

Posted in Swell

Here’s our thoughts about Swell’s core architecture.

Swell's Core architecture

Swell's Core architecture

by

SVN post-commit hook, API doc autogeneration

Posted in Swell

Generating manually Swell’s API doc actually’s being a pain, we finally chose to generate it automatically through subversion’s repositories hooks.
These hooks once enabled, allows you to listen specific SVN-based events (pre/start/post commit/lock…) and therefore execute your home-made script.

In our case, we use JSDoc to generate the API doc and well, it took about 6mins with one core (2ghz) fully-loaded to parse/generate the documentation for only 4 files…
Let’s hope that we’ll not commit too often.

svn up /path/to/your/repository/api/src
java -jar /path/to/your/repository/api/jsdoc/jsrun.jar /path/to/your/repository/api/jsdoc/app/run.js -r=1 /path/to/your/repository/api/src -t=/path/to/your/repository/api/jsdoc/templates/jsdoc
Error: Unable to create directory /var/www/vhosts/justswell.org/subdomains/blog/httpdocs/wp-content/uploads/2013/05. Is its parent directory writable by the server?
by admin

Swell makes javascript hot key event listeners a breeze…

Posted in Javascript, Swell

These days the trend is to have a seamless desktop experience in your browser, that means pushing the boundaries of the web applications by trying to mimic the natural behavior of desktop hosted solutions. One of the must-have is undoubtedly a robust and easy-to-use event toolkit. That was one of the heaviest task and probably, to date, one of the features we are most proud of.

We’ll try to make a bunch of articles on how to use the Event toolkit. Today we’ll talk about hot-keys, a hot-key is a key combination that you can use to trigger an action in your web-application, for example you are building a WYSIWYG editor and want to capture combination like Ctrl + B to turn the text in bold.

Here’s how you would create this keyboard event listener with Swell.

Swell.Core.Event.addKeyListener(document, 'ctrl+b', function(event, keys) {
 
    if(event.modifiers.ctrl) {
        if(keys.contains('b')) {
            Swell.Lib.Selection.getCurrent().wrap('<strong>$1</strong>');
        }
    }
 
}, null, null, true);
by

Clientside getElementsByClassName cross-browser implementation

Posted in Swell

We just came up with a “getElementsByClassName” cross-browser implementation quite interesting.

Most of the A-Grade browsers doesn’t support getElementsByClassName natively, and in this case you’ll have to write from scratch this method—excepted in one case: IE8.

Although it’s kinda annoying for a recent browser (which is still in RC1) to not support this W3C recommandation natively, it does at least support querySelectAll… in standards mode.
So we ran several tests to check the difference between IE8 in quirks/standards mode, which is actually noteworthy: 500% gain when using querySelectorAll, but still about twice slower compared to the native getElementsByClassName implementation in Firefox 3.0.6 ; but well, we didn’t expect that much.

function(className, root, tagName) {
    root = root || document.body;
    if (Swell.Core.isString(root)) {
        root = this.get(root);
    }
 
    // for native implementations
    if (document.getElementsByClassName) {
        return root.getElementsByClassName(className);
    }
 
    // at least try with querySelector (IE8 standards mode)
    // about 5x quicker than below
    if (root.querySelectorAll) {
        tagName = tagName || '';
        return root.querySelectorAll(tagName + '.' + className);
    }
 
    // and for others... IE7-, IE8 (quirks mode), Firefox 2-, Safari 3.1-, Opera 9-
    var tagName = tagName || '*', _tags = root.getElementsByTagName(tagName), _nodeList = [];
    for (var i = 0, _tag; _tag = _tags[i++];) {
        if (this.hasClass(_tag, className)) {
            _nodeList.push(_tag);
        }
    }
    return _nodeList;
}