Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

node_modules curation: step 1 #130

Merged
merged 7 commits into from
May 10, 2012
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
47 changes: 44 additions & 3 deletions featherdoc/docs/hello feather.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ Hello, feather

-`1.` From the `hello_world` folder, create a widget via the command line: `feather create-widget sayHello`

This will ask you if `hello_world` is OK to use as the namespace of the widget (since we omitted a namespace as the last argument when we ran the command). So far we've typically just stuck with the app name as being the namespace for all widgets; it's a pattern that seems to work for most apps (assuming your app name isn't something long winded), though you may want to introduce additional namespaces if your app design is particulary large. After you say "yes", it will then create a folder at `hello_world/public/widgets/sayHello` that contains four files as follows...
This will ask you if `hello_world` is OK to use as the namespace of the widget (since we omitted a namespace as the last argument when we ran the command). So far we've typically just stuck with the app name as being the namespace for all widgets; it's a pattern that seems to work for most apps (assuming your app name isn't something long winded). You may want to introduce additional namespaces if your app design is particulary large. After you say "yes", it will then create a folder at `hello_world/public/widgets/sayHello` that contains four files as follows...

* sayHello.client.js
* sayHello.css
Expand Down Expand Up @@ -83,7 +83,7 @@ Hello, feather
```

__A note about `id` attributes__
At this point we'd like to make you aware of an important feature of the feather framework. Let's say you want to add ten instances of this widget to your page. You would simply edit the `index.feather.html` file and add nine more `widget` tags. You must, however, take care that all ten instances have different `id`s (in fact the framework will hollar at you during startup if you fail to meet this requirement and will error out). The reason this is true is so that all the elements on the page can be gauranteed to be uniquely ID'ed and so that behavioral code in the widgets' `client.js` file can safely reference _only_ the DOM elements associated with _that_ _instance_. To accomplish this, feather auto prefixes an id chain to elements based on the hierarchy of where each instance is embedded. So in our example above (with just a single instance embedded in the page), the button will actually have an id of `sayHello1_sayHiBtn` in the DOM (because we gave the `widget` tag an id of `sayHello1` when we embedded it). Don't worry though, when you write client code within the widget's `client.js` file you will not have to worry about knowing what that id hierarchy looks like; you'll be able to reference the scoped elements by their relative IDs via code like `this.get('#sayHiBtn')`, which we'll demonstrate shortly.
At this point we'd like to make you aware of an important feature of the feather framework. Let's say you want to add ten instances of this widget to your page. You would simply edit the `index.feather.html` file and add nine more `widget` tags. You must, however, take care that all ten instances have different `id`s (in fact the framework will hollar at you during startup if you fail to meet this requirement and will error out). The reason this is true is so that all the elements on the page can be gauranteed to be uniquely ID'ed and so that behavioral code in the widgets' `client.js` file can safely reference _only_ the DOM elements associated with _that_ _instance_. In this way, you can have as many instances of a single widget on the screen as you want without having to write any code to deal with that scenario (it's managed for you). To accomplish this, feather auto prefixes an id chain to elements based on the hierarchy of where each instance is embedded. So in our example above (with just a single instance embedded in the page), the button will actually have an id of `sayHello1_sayHiBtn` in the DOM (because we gave the `widget` tag an id of `sayHello1` when we embedded it). As already mentioned, when you write client code within the widget's `client.js` file you will not have to worry about knowing what that id hierarchy looks like; you'll be able to reference the scoped elements by their relative IDs via code like `this.get('#sayHiBtn')`, which we'll demonstrate shortly.

-`2.` Add the following style rule to the `sayHello.css` file (let's make this button really ugly)...

Expand All @@ -107,7 +107,48 @@ Hello, feather
color: red;
}
```
The problem, of course, is that because widgets are meant to be reusable, and you will be embedding them in arbitrary locations in your app, the id prefixes will be (and should remain) unknown within the context of your CSS files.
The problem, of course, is that because widgets are meant to be reusable and you will be embedding them in (potentially) arbitrary locations in your app, the id prefixes will be (and should remain) unknown within the context of your CSS files. As demonstrated above, the actual id of the button in the DOM in our example will be `sayHello1_sayHiBtn`, and not just `sayHiBtn`, therefore the CSS selector above will actually find 0 elements. You may, then, be tempted to simply target your CSS rule as `.hello_world_sayHello #sayHello1_sayHiBtn`. That would be a mistake because it is tightly coupling the CSS rule to a specific embed hierarchy, and this rule will break the second that hierarchy changes for whatever reason.

-`3.` Bind a click handler in the `sayHello.client.js` file as follows...

```js
feather.ns("hello_world");
(function() {
hello_world.sayHello = feather.Widget.create({
name: "hello_world.sayHello",
path: "widgets/sayHello/",
prototype: {
onInit: function() {

},
onReady: function() {

this.domEvents.bind(this.get('#sayHiBtn'), 'click', function() {
alert("Hi there!");
});

}
}
});
})();
```

Since this is our first look at the `client.js` file, let's take a moment to examine the boilerplate to understand what's going on.

- The first line is a call to `feather.ns` (where 'ns' stands for 'namespace'). `feather.ns` is a helper function that encapsulates the safe (non-overwriting) creation of a variable at an arbitrary path within a given context (where the default context is the global context, or `window` on the client). The call `feather.ns("hello_world")` first checks to see if the `hello_world` variable has already been created in the global context (`window` in this case), and does nothing if it has, or creates an empty object to represent that namespace if it hasn't (this assures that the order in which you embed same-namespaced widgets won't inadvertantly affect the creation of this object.). `feather.ns` is very handy and offers a few more options, which will be explained in greater detail in the API docs.
- Next you'll notice the very standard module pattern (an immediately-called anonymous function), whose body is a single statement that creates a widget constructor at `hello_world.sayHello`. The constructor arguments template (the object being passed into the `feather.Widget.create` factory function) includes the widget boilerplate properties of `name`, `path`, and `prototype`. `name` seems redundant at first glance, but is important because it will be used in various places behind the scenes. The same is true of `path`; this is mainly used to pass into feather's dynamic widget loading mechanism so the server can easily resolve which widget is being requested. Finally, the `prototype` property is exactly that... the javascript prototype of the resulting widget constructor.

There are two important methods of interest on all client-side widget prototypes: `onInit` and `onReady`.

- The `onInit` function is called immediately after a widget instance is created on the client, but before the DOM has been updated with that widget's HTML from its template. This would be where you would add any initialization code (i.e. the stuff you'd normally put into a constructor function).
- The `onReady` method is called immediately after the widget's HTML has been rendered into the DOM, and this is the point at which it's safe to interact with the widget's DOM elements (e.g add event handlers).

So, with the understanding that `onReady` is the point at which our widget's DOM elements are ready, you can then see this is where we write the event binding code on our button.

_jQuery integration and the domEvents registry_
There is no mistaking that jQuery is the world's most popular client side toolkit. For this reason (and also because it's amazing), feather relies on jQuery heavily. jQuery is auto-included in all feather pages, and is not optional in the feather framework (yes, feather is opinionated on this topic). In our example code above, jQuery's `.bind()` method is what's actually being used behind the scenes. Feather widgets, however, all contain their own local registry of event handlers: the `.domEvents` property. The reason this exists is because widgets are able to be disposed of (imagine a single page interface where many widgets are dynamically created and destroyed as the user performs various actions). As each widget is destroyed, this local domEvents "registry" is used to automatically clean up all of that instance's listeners. This frees you from having to worry about memory leaks.



a. adding a button
aa. discussion on id attribute
Expand Down
4 changes: 2 additions & 2 deletions lib/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -126,11 +126,11 @@
"enabled": true,
"provider": {
"jsFiles": [
"/feather-client/lib/jqueryUI-1.8.14/js/jquery-ui-1.8.14.custom.min.js",
"/feather-client/lib/jqueryUI-1.8.20/js/jquery-ui-1.8.20.custom.min.js",
"/feather-client/ui.js"
],
"cssFiles": [
"/feather-client/lib/jqueryUI-1.8.14/css/black-tie/jquery-ui-1.8.14.custom.css"
"/feather-client/lib/jqueryUI-1.8.20/css/black-tie/jquery-ui-1.8.20.custom.css"
]
}
}
Expand Down
2 changes: 0 additions & 2 deletions lib/data.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,9 @@ var dataInterface = module.exports = function(options) {
if (! require.resolve("./data/data-"+providerName)) {
throw new Error("No data provider found for " + providerName);
}
// logger.info({message:"Initializing data provider " + providerName, category:"feather.data"});
var providerClass = require("./data/data-"+providerName).DataProvider;
var provider = new providerClass(options);
this.db = provider.getDb();
// logger.info({message:"Provider " + provider.name + " is ready.", category:"feather.data"});
};

dataInterface.prototype = {
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading