2012. december 14., péntek

Protain - defining (extending) simple classes II.

Protain also supports a "classical" syntax to create prototype chains - it doesn't look like the syntax in Java, C++ or C# or etc., but at least it is similar. So, let's do a class named Person with some methods - of course we are inside a scope of a namespace, which is refered with this:
/**
 * Person Class
 */
protain
    .class(this, 'Person')
    /**
     * @constructor
     * @param instance {Object} the new instance
     * @param name {String} the name of the instance
     */
    .init(function (instance, name) {
        instance.setName(name);
    })
    //class properties
    .define({
        /**
         * sets the name property of the context
         */
        setName: function (name) {
            //type check
            if (typeof name !== 'string' && name === '') {
                throw new TypeError('Invalid argument!');
            }

            //set the name
            this.name = name;

            //return the context
            return this;
        },
        /**
         * returns the name property of the context
         */
        getName: function () {
            return this.name;
        }
    });
Now, that we have a base class, we can extend from it using the .extend() method and .build() to build the instance with the inherited functionality:
/**
 * AgingPerson
 */
protain
    .class(this, 'AgingPerson')
    /**
     * setting up inheritance
     */
    .extend(this, 'Person')
    /**
     * @constructor
     * @param instance {Object} the new instance
     * @param name {String} the name of the instance
     * @param age {Number} the age of the instance
     */
    .init(function (instance, name, age) {
        /**
         * .build() will initialise the instance based on the inheritance and the arguments passed
         */
        this.build(arguments);

        instance.setAge(age);
    })
    .define({
        /**
         * returns the age property of the context
         */
        getAge: function () {
            return this.age;
        },

        /**
         * sets the age property of the context
         */
        setAge: function (age) {
            if (typeof age !== 'number') {
                throw new TypeError('Invalid argument!');
            }

            //set the age
            this.age = age;

            //return the context
            return this;
        }
    });
The .extend() method takes two parameters:
  • namespace - the namespace to register the extend to
  • className - the name of the class to extend

When you extend from a class, you will have to use the this.build(arguments); method inside the constructor to build the instance based on the inheritance. This method calls the base class's constructor method, just like the super() method in Java.

And then you can use the .create() method for instantiating:
var AgingPerson = protain.class(this, 'AgingPerson');

var agingPerson = AgingPerson.create('benqus', 26);
Well, I should write some more example on GitHub but so far you are good to go with Protain. =)

I hope you enjoyed these tutorials! Any question are welcome! =)

Find Protain on GitHub: https://github.com/benqus/protain

2012. december 10., hétfő

Protain - defining node-classes

So, we have arrived to the subject in which Protain tries to bring something different. Node-based class behaviour.
Sounds so advanced that I threw my brain, went after it and threw it again... =)

Let's quickly create 2 nodes in a namespace, mine will be same as in the previous tutorials - I won't comments in these now:
protain
    .node(this, 'name', {
        getName: function () {
            return this.name;
        },
        setName: function (name) {
            this.name = name;
            return this;
        }
    })
    .node(this, 'guid', function () {
        var id = 0;
    
        return {
            generateId : function () {
                this.ID = id++;
                return this;
            }
        }
    }());
First thing you want to keep in mind is that classes are able to inherit from nodes only in the same namespace!

Then when you create a class, you just "list" the nodes you want to use for that class. Also, you still have the .define or .init methods available for custom class property definitions:
/**
 * defining a "node class"
 */
protain
    .class(this, 'MyFirstNodedClass', 'guid', 'name')
    /**
     * defines a property on the class
     */
    .define({
        CLASS_NAME: 'MyFirstNodedClass'
    })
    /**
     * @constructor
     */
    .init(function (instance, name) {
        /**
         * setting some instance properties
         */
        instance
            .generateId()
            .setName(name + ' ' + (instance.ID + 1));
    });
This was very hard, right? =) Now, let's see it in action by generating 10 instances in a loop and logging it out to the console:
/**
 * instantiating 10 instances and logging them out
 */
for (var i = 0; i < 10; i++) {
    console.log(
        /**
         * logging a new instance
         */
        protain
            .class(this, 'MyFirstNodedClass')
            .create('Some random name')
    );
}
Node-based class behaviour (I'm still wet...) is quiet simple I guess... =) You are also able to extend classes from each other but that belongs to another article...

Find Protain on GitHub: https://github.com/benqus/protain

2012. december 2., vasárnap

Protain - defining simple classes I.

We arrived to the point when you would like to create a class.

Let's start by defining a simple class, nothing fancy, just a class, with a class property and a constructor. It looks like this:
protain.namespace('hu.benqus.namespace_tutorial', function (path) {
    /**
     * defining a class - simple way
     */
    protain
        /**
         * creates a class
         */
        .class(this, 'MyFirstClass')
        /**
         * defines a property on the class
         */
        .define({
            myProperty: 'myPropertyValue'
        })
        /**
         * @constructor
         */
        .init(function (instance) {
            console.log(this); //class
            console.log(instance); //instance
        });
});

Methods:

protain.class
Method creates a class object.

Arguments:
  • namespace - a protain namespace {Object}
  • class name - name of the class in {String}
  • [node1], [node2] - node names to inherit the functionality from (same namespace) {String} (see later, in the node classes article)


protain.define
Method defines a set of properties on the class object which it was invoked on.

Arguments:
  • properties - set of attributes {Object}


protain.init
Method defines a constructor function for the class. The argument method's context (this) will be the class (!!!).
First argument will be the current instance and the remaining arguments will be the passed ones in the .create() method (see later, in the instantiation article).

Arguments:
  • constructor - a constructor function to be invoked on each instantiation {Function}


This wasn't so hard after all, right? Next one will be the "noded classes", stay tuned for more dose of protain! =)

Find Protain on GitHub: https://github.com/benqus/protain

2012. december 1., szombat

Protain - nodes, concept

In this article, I would like to introduce the meaning of node in Protain.

But first, let's talk about a different approach to object-oriented programming. I named it "prototype-oriented" programming but only for myself. The first thing I would like you to forget is the idea of class, in the classical meaning. Instead, think about objects only. Of corse we are still in JavaScript!

What is a node?

In JavaScript, in prototypal-inheritance, the prototype will tell you where the instance is derived from, through the instance's prototype. Which is a reference to another object. And object properties can refer to other object's properties. That is what a node is: an object, with specified properties.

For cubes: "A node is an object's attribute collection, used by one or more classes. It's purpose is to share the same functionality between classes instead of specifying them again and again."

For example:
Suppose you have 5 different classes in the same namespace and a bunch of nodes (functionalities). You can "connect" these nodes by specifying the 5 classes. You can connect these classes differently.
Also, it is very handful when you don't have to re-model, re-design and re-implement the whole prototype-chain when you have to extend the list of functionalities.

Let's define two nodes. One in the current context-namespace and the other in the hu.benus.global namespace. We will use the protain.node method, which takes the following arguments:
  • namespace - the namespace to register the node to
  • name - the name of the node
  • object - the node as an object
protain.namespace('hu.benqus.namespace_tutorial', function (path) {
    /**
     * creating a node (functionality)
     * called 'name' containing 2 methods
     * on the current namespace
     */
    protain
        .node(this, 'name', {
            /**
             * @return {String}
             */
            getName: function () {
                return this.name;
            },
            /**
             * @param name {String}
             */
            setName: function (name) {
                this.name = name;
                return this;
            }
        });

    /**
     * creating another namespace
     * @type {Object}
     */
    var global = protain.namespace('hu.benqus.global');

    /**
     * creating a node called 'guid'
     * on the hu.benqus.global namespace
     */
    protain
        .node(global, 'guid', function () {
            /**
             * static property
             * @type {Number}
             */
            var id = 0;

            return {
                /**
                 * specifies an ID attribute for the context
                 */
                generateId : function () {
                    this.ID = id++;
                    return this;
                }
            }
        }());
});
Now, you can define as many classes as you want using the same name and guid nodes (functionalities).

Dealing with nodes is simple again, just specify the context, the name, and the node object and you are good to go.

Next one will be the class (prototype object) creation. Stay tuned for more! =)

Find Protain on GitHub: https://github.com/benqus/protain

Protain - basics, namespacing

Let's talk about some development things also, like JavaScript and Protain.

This is my favourite language for web usage. And the reason is because JavaScript is flexible and I learned how to live with or how to avoid (mostly) the bad parts of the language. =)

This learning/avoiding process came from my mentor/surpervisor/lead front-end developer Daniel Stocker, in the front-end team at Production Minds by using his JS OOP library called Troop.

That library gave the inspiration to create Protain.

What is Protain?

A JavaScript library that supports namespacing, inheritance and functionality in a much simplier and cleaner, organised way. Namespacing is the first key concept of Protain. Second key concept is sharing functionality between classes through "nodes". Third is to provide an inheritance functionality that is easy to use without breaking the primary key concepts of protain.

Using Protain - namespaces

Let's jump right at the middle!
Use the protain.namespace([path]{String}, [callback]{Function}); method to register a namespace and/or create a scope for your context.
Note: if you don't specify a path for the namespace, it will be invoked with the protain's root namespace!

The following code will show you how to register a namespace:
/**
 * registering a namespace
 */
protain.namespace('hu.benqus.namespace_tutorial', function (path) {
    // stuff ...
});
This will create a namespace inside protain, specified by the path (a string, separated by . [dot] or / [backslash]) and the callback function. If you don't specify any arguments for the protain.namespace() method, it will return the the complete namespace hierarchy. Let's use that to check the whole namespace hierarchy in the WebKit Debugger:
console.log(protain.namespace());
Each namespace contents 4 attributes, except the root, which does not contain the path attribute:
  • classes - (surprisingly) classes will be registered right here
  • context - this will be the context of the callback method you specifiy for the above protain.namespace method
  • nodes - nodes are the attributes shared by classes, we will talk about this later
  • path - the current namespace's path from the root

You may also want to have references to another namespaces in the context:
protain.namespace(function (path) {
    //reference to other namespace
    var other = protain.namespace('hu.benqus.other');
});
Namespacing is that simple in protain.
Next tutorial will be about explaining and creating the above mentioned nodes. Stay tuned! =)

Find Protain on GitHub: https://github.com/benqus/protain

2012. szeptember 1., szombat

HTML contenteditable - Going nifty

So, we have arrived to the third experiment:
Making the selection interact with the user. We will detect if there is any selection and if there is any, we will show a nice little modal box aligned to the selection.

ClientRect object

This is a really simple object, it contains the following attributes on the instance level:
  • top
  • left
  • right
  • bottom
  • width
  • height
Each Range object has its own ClientRect object describing the actual range's dimensions and positions. Cool, huh? So how do we use it? Simple:
//returns a ClientRect object
var clientRect = range.getBoundingClientRect();
Using this object we can simply show up a modal dialog box after some short & basic math using jQuery:
//returns a ClientRect object
var clientRect = range.getBoundingClientRect();
menu.css({
    left: (rect.left +
           (rect.width / 2) -
           (menu.outerWidth(true) / 2)),
                
    top: (rect.top +
          rect.height +
          5)
    })
    .show();

Modifying a selection through Range

Mofiying a selection is not a big deal, you only need to keep in mind some rules:
  • Creating a new Range object is done through document.createRange() method.
  • The range.setStart() method does NOT accept HTMLElement as a first parameter. You need to pass a TextNode (#text) type node in there.
    Also, Webkit cannot select empty elements (without at least one TextNode)
    Solution: use the Element.firstChild property instead of the Element - in case you only have text inside the element. Otherwise you can write a function which digs down in the Element's children and their children and returns a TextNode.
  • range.startContainer and range.endContainer contains the TextNodes where the selection begins and ends. They point to the same TextNode if there is no selection or the selection does not flow out from a TextNode.
  • range.startOffset and range.endOffset represent the numbers (positions) where the selection ends. Watch for the positions, they return the "distance" from the beginning of their TextNode, NOT the distance from the parent Element. We used a method to merge these separate TextNodes and another to get the "absolute" position of the caret.
Modifying a selection is quiet simple:
//creating a new range object
var newRange = document.createRange();

//setting up the new range object created at the beginning of the scope
newRange.setStart(theTextNodeYouPreviouslyFound, start);
        
//removeing all range objects and adding the new one
selection.removeAllRanges();
selection.addRange(newRange);
So putting it all together, I have created this small dummy interaction, check it out at this jsfiddle. It is simple, right? =) Just enough for a weekend demonstration. =)

HTML contenteditable - Basics for awesomeness

So, you have already found out the basics of a contenteditable element. Let's focus now on how to work with the Selection and the Range(s) inside.
I will use jQuery for the demostrations because of two reasons:
  • I am used with jQuery...
  • It is just way easier to delegate your eventHandlers with jQuery since your event will bubble (propagate) up on the DOM (watch out with the context!).

Selection object

The Selection object is a single "static" object of a Window object. You can have more Window objects by adding iframes into your site/app and each frame is going to have its own single Selection object, but no more. You might want to be aware of that.
You can get this object by calling the window.getSelection(); method. That will give you back a reference to the Selection object. Again: the Selection object is single, if you reuse it somewhere else in your code, I recommend storing it in your "parent/owner" scope somewhere. Here's a little experiment with the Selection object:
kldfnlkdnjd
​(function () {
    var selection = window.getSelection();
    
    $(document.body)
        .on('click', '[contenteditable]', function () {
            var sel = window.getSelection();
            
            alert(selection === sel);
        });
}());​
As you can see, the selection and the sel references are pointing to the same Selection object so you don't need the sel variable and call the getSelection() method again.
The Selection object provides some methods to edit your selection but you can be more flexible on the Range objects inside the Selection. However, you will need 2 methods for sure, even if you are working with Range objects:
  • selection.removeAllRanges()
    Not surprisingly, this will remove all of the Range objects inside.
  • selection.addRange(range)
    Adds a Range object to the selection. Weird, huh? =)
A Selection may contain more than one Range, you can achieve that programmatically but as a user I have not found any need for that (yet...).

Range objects

Range objects contain the actual user-selection and it does not really matter if the selection is inside a contenteditable element or somewhere else, it is going to return the selection Range(s) anyway with the proper data about the selection.
I used mostly the range.setStart/setEnd(Node, position) method to set up my selection and place the caret back to the contenteditable when there was a change. These methods take a TextNode as a first argument and a position number.
Also, there are situations when you need a new Range object and throw out the existing one. These cases look something like this:
//the Selection object
var selection = window.getSelection();

//creates a new {Range} object
var newRange = document.createRange();

//this will place the caret at beginning of the 'textNode'
range.setStart(textNode, 0);

//clear up the selection object so Ranges won't collide
selection.removeAllRanges();

//add the new Range object
//this will handle the visul selection also
selection.addRange(newRange);
So these are the really basics of the selections. I think the best way of learning it is doing, so I will come back with examples about "how-to"s and "how-not-to"s soon. =)

Stay tuned, there is a lot more to this. Also, if everything goes as planned we will do some serious interaction going between a simple text editor and the user... ;)

2012. augusztus 31., péntek

HTML contenteditable - Basics

What is it?

Recently, I have got the opportunity to work with HTMLElements with the attribute contenteditable set (to true if you like it more). This is not over-complicated:
<div contenteditable></div>

<!-- or if you prefer to be more expressive -->

<div contenteditable='true'></div>
Quiet simple, right? =)
It is like a textarea but it is a HTMLDivElement - actually, the prototype object of the object is HTMLDivElement but that is JavaScript/DOM stuff, we don't need that for now.

So the question arises: why would we want to use a contenteditable element instead of a textarea?

Pros:

  • Styling is easier
    It is way much easier to align, position, resize, etc. Since you can work with a div (or section or article or span or whatever...) it is way much easier to maintain the element itself.
    Also, you can forget !important rules in your stylesheets.
  • (X|HT)ML inside
    You can overwrite the browser's default behaviour and write your own text (or in my case Script/screenplay) editor. Like tinyMCE

Kontras:

  • You have just found any enemy. Why? The default behaviour might be/is different in each browser. That just sucks, right? Browser War II... (I am using Webkit [Chrome/Maxthon/Safari])
    So you must write a ridiculously (okay, not that much) massive state-machine which overwrites these default behaviours. (if you want to be the employee of the YEAR at the company, you have good chances now! =D )
  • Key events are not firing up on the contenteditable's children elements when working with (X|HT)ML inside
    This is really weird so far, since the mouse events work just fine but the key events... Not a chance in Chrome 21... You might want to give it a try: jsfiddle here.
    So you will have to have a solution for these type of problems. I wrote a small workaround for that eventHandler context issue, it is really basic stuff with jQuery and it is only a first draft but you get the idea. =) And the fiddle is here.

Writing in a contenteditable element

This is the worst part.. You have click on it (place the focus inside), and you're done! =D Just like the textarea, just like that.

Getting the contents of a contenteditable element

You have some ways to do that, I prefer the DOM way for this one since it is very very simple:
//[element] might be a context inside an event handler function refered as 'this'
element.textContent;
You can also use jQuery to achieve the same result:
//[element] might be a context inside an event handler function refered as 'this'
$(element).text();
You just saved 2 function calls with the DOM way but that doesn't really matter.

So, these are the basics of the contenteditable's, quiet simple stuff, just to get you used to it. =)
Let me know if I should write more about how to do some cool stuff with it. Like XML/HTML stuff inside. It can be awesome if you are over the hatred... =D Next »

2012. július 30., hétfő

Installing MongoDB driver for PHP Ubuntu Server 12.04

This article is about connecting PHP with MongoDB.

Before you start, make sure you have apache2 and PHP5+ installed in your server:
$ sudo apt-get install apache2 php5 libapache2-mod-php5


You will also need to install some dependencies for the driver. Do it this way:
$ sudo apt-get install php-pear php5-dev


Okay, let's find this driver!
$ pecl search mongo


And install it:
$ sudo pecl install mongo


If you wouldn't have the make package installed, install and reinstall mongo:
$ sudo apt-get install make
$ sudo pecl install mongo


Now, let's hack that php.ini too, located at /etc/php5/apache2/ path. Do that by adding mongo.so extension somewhere after the extensions part:
$ sudo vim /etc/php5/apache2/php.ini

extension = mongo.so


Since I have run my database server on a separate MongoDB server, I have also changed to path to the database for the extension. I have added the following lines after MySQL block:
[Mongo]
; default host 127.0.0.1
; custom host: the IP address of the database server
mongo.default_host = "xxx.xxx.xxx.xxx"
Further infos at in the PHP - MongoDB documentation.

Installing MongoDB on Linux Ubuntu Server 12.04

For those who like to know how to install MongoDB on a clean Linux Ubuntu 12.04 install.
Note: this article is for any Ubuntu versions above 9.10, using upstart.


At first, you need to tell Ubuntu that the repository where you are going to download MongoDB is a secure one. Do that by typing this line in the terminal:
$ sudo apt-key adv --keyserver keyserver.ubuntu.com --recv 7F0CEB10
I you are interrested about the 'apt-key' part, visit SecureApt.


Now you need to tell where to look for MongoDB. You will need to store this information in a file named 10gen.list, in the /etc/apt/sources.list.d/ directpory, so feel free to type in the terminal (I use vim):
$ sudo vim /etc/apt/sources.list.d/10gen.list
And the contents of the file will be:
deb http://downloads-distro.mongodb.org/repo/ubuntu-upstart dist 10gen


Now, let's update!
$ sudo apt-get update
And finally, here comes our target: MongoDB!
updated 'mongo' to 'mongo-10gen'
$ sudo apt-get install mongodb-10gen

Done.
Based on my experience, if you type in "mongo" now, it will not work. I rebooted the server and it was working like a charm. Try rebooting and then:
$ mongo
show dbs;
//local
//test