JavaScript organization | Module pattern w/ modules - javascript

I'm organizing my code into 20-60 line modules, usually in the module pattern. I want a well formed object oriented JavaScript library.
Is this the best way to do this? The code has been tested and works.
I like it because a programmer can pull modules from the library and use them as needed, they are self contained.
Here is Tool, Message, Effect and Text, all contained in NS.
Question?
Is this a good way ( best practice ) to organize my library?
Note
So far, there is 0 consensus in the comments and answers...very frustrating.
Outer Module Pattern
var NS = ( function ( window, undefined )
{
/* All Modules below here */
} )( window );
Tools
/**
*Tools
* getTimeLapse - benchmark for adding
*/
var Tool = ( function ()
{
var Tool = function ( )
{
};
Tool.prototype.getTimeLapse = function( numberOfAdds )
{
var end_time;
var start_time = new Date().getTime();
var index = 0;
while ( index <= numberOfAdds )
{
index++;
}
end_time = new Date().getTime();
return ( end_time - start_time );
};
return Tool;
} () );
Message
/**
*Message
* element - holds the element to send the message to via .innerHTML
* type - determines the message to send
*/
var Message = ( function ()
{
var messages =
{
name: 'Please enter a valid name',
email: 'Please enter a valid email',
email_s: 'Please enter a valid email.',
pass: 'Please enter passoword, 6-40 characters',
url: 'Please enter a valid url',
title: 'Please enter a valid title',
tweet: 'Please enter a valid tweet',
empty: 'Please complete all fields',
same: 'Please make emails equal',
taken: 'Sorry, that email is taken',
validate: 'Please contact <a class="d" href="mailto:foo#foo.com">support</a> to reset your password',
};
var Message = function (element)
{
this.element = element;
};
Message.prototype.display = function( type )
{
this.element.innerHTML = messages[ type ];
};
return Message;
} () );
Effects
/**
*Effects
* element - holds the element to fade
* direction - determines which way to fade the element
* max_time - length of the fade
*/
var Effects = ( function ()
{
var Effects = function ( element )
{
this.element = element;
};
Effects.prototype.fade = function( direction, max_time )
{
var element = this.element;
element.elapsed = 0;
clearTimeout( element.timeout_id );
function next()
{
element.elapsed += 10;
if ( direction === 'up' )
{
element.style.opacity = element.elapsed / max_time;
}
else if ( direction === 'down' )
{
element.style.opacity = ( max_time - element.elapsed ) / max_time;
}
if ( element.elapsed <= max_time )
{
element.timeout_id = setTimeout( next, 10 );
}
}
next();
};
return Effects;
} () );
Text
/**
*Text
* form_elment - holds text to check
*/
var Text = ( function ()
{
var Text = function ( form_element )
{
this.text_array = form_element.elements;
};
Text.prototype.patterns =
{
prefix_url: /^(http:)|(https:)\/\//,
aml: /<(.+)_([a-z]){1}>$/,
url: /^.{1,2048}$/,
tweet: /^.{1,40}$/,
title: /^.{1,32}$/,
name: /^.{1,64}$/,
email: /^.{1,64}#.{1,255}$/,
pass: /^.{6,20}$/
};
Text.prototype.checkPattern = function( type )
{
return this.patterns[ type ].exec( this.text_array[type].value );
};
Text.prototype.checkUrl = function( type )
{
return this.patterns[ type ].exec( this.text_array.url.value );
};
Text.prototype.checkSameEmail = function()
{
return ( ( this.text_array.email.value ) === ( this.text_array.email1.value ) );
};
Text.prototype.checkEmpty = function()
{
for ( var index = 0; index < this.text_array.length; ++index )
{
if ( this.text_array[ index ].value === '')
{
return 0;
}
}
return 1;
};
return Text;
} () );

The one thing I would suggest to change to make your code cleaner and reduce its footprint is to just set the prototype property at once, so that instead of doing
Object.prototype.method1 = function(){};
Object.prototype.method2 = function(){};
You do
Object.prototype = {
method1: function(){},
method2: function(){}
};
If you need to conserve the constructor reference, which is recommened, you should re-assign the constructor afterward. See this answer for more details.

I personally prefer using a modular code organization library like ncore
This encourages you to write your code as a set of modules (one module per file) and then hook them together using dependency injection and bootstrapping.
The code is slightly portable because modules are just objects on their own right, however if one doesn't use ncore advantages are lost.
The leaderboard app shows a detailed example of OO code organization

A few suggestions... First would be to create a namespace object as scope for your libraries... jQuery uses "jQuery" and "$", underscore uses "_". I tend to use "CompanyName.SiteName"
if (typeof CompanyName == "undefined") var CompanyName = {};
CompanyName.SiteName = CompanyName.SiteName || {};
The first line explicitly checks against undefined, as you'll get errors in many browsers otherwise for root variables using the method on the SiteName property.
From there, I would make a couple adjustments... When you are calling an anonymous function inline, it's best to wrap the whole of the call inside the parens.
CompanyName.SiteName.ModuleName = (function(w){
...
return moduleImplementation;
}(window || this)); //CompanyName.SiteName.ModuleName
This tends to avoid the confusion by having the parens wrap the whole, and by having a comment at the end of the module declaration.
Per the comment above, you may want to make the prototype declaration as a more singular statement. I would advise against this, as longer modules can make readability an issue.
myModule.prototype = {
"method1": function(){
}
...
"methodN": function(){
//by the time you get here, you may not see the top, and where you are nested in
}
};
//with the dot-notation, or hash notation
myModule.prototype.methodN = ...
myModule.prototype["methodN"] = ...
//you can see where you are binding to at that function
You may also want to look into RequireJS and AMD
There's also the concept of dealing with simpler objects, and using functional binders. Treating your library as a set of functions (similar to C exports) that are passed and work with simpler objects/types. It really depends on your needs/usage and the specifics of your needs and use.
You may also want to look at javascript libraries like KnockoutJS, Underscore and Backbone for some examples.

Related

Can I magically make the selectors non-functional if the selection value is empty?

Background:
I have a function that I call like this:
hide_modules('string1','string2');
The function is something like:
function hide_modules(param1,param2) {
MM.getModules()
.withClass(param1)
.exceptWithClass(param2)
.enumerate(function(module) {
module.hide(
// some other code
);
});
}
Most of the time I call the function with values as shown above.
Sometimes I do not want 'string1' to have a value and I'd like the my function to not use that first selector, effectively like this:
MM.getModules()
// .withClass(param1)
.exceptWithClass(param2)
.enumerate(function(module) {
module.hide(
// some other code
);
});
I've tried just calling it with an empty string, 0, false as param1 but the end result class selection is not what I want.
Sometimes I also call it with param2 empty and not wanting to have the param2 related selector used either.
So the question is:
Without writing a big if-then-else statement, is there some fancy way I can make those selectors non-functional (the equivalent of commenting it out like above) when the param1 and/or param2 values are not specified?
The supporting code that my function calls is provided for me in a 3rd party library that I can't change. I include some of the relevant parts here as it may help with the answer:
var withClass = function (className) {
return modulesByClass(className, true);
};
var modulesByClass = function (className, include) {
var searchClasses = className;
if (typeof className === "string") {
searchClasses = className.split(" ");
}
var newModules = modules.filter(function (module) {
var classes = module.data.classes.toLowerCase().split(" ");
for (var c in searchClasses) {
var searchClass = searchClasses[c];
if (classes.indexOf(searchClass.toLowerCase()) !== -1) {
return include;
}
}
return !include;
});
Since js doesn't supports function overloading, the only way is to validate your parameters inside your method. Check for truthy and ternary operator will do the trick
var modules = MM.getModules();
modules = param1 ? modules.withClass(param1) : modules;
modules = param2 ? modules.exceptWithClass(param2) : modules;
modules.enumerate(function(module) {
module.hide(
// some other code
);
});
to skip first parameter
hide_modules(null,'string2');
to skip second parameter
hide_modules('string1');

My object isn't updating by reference, what's wrong with the logic?

I've been working with this bug for a few days now, and I think I've pinpointed the problem area, but I'm not sure why it doesn't work. I think it may have to do with a problem with passing an object by reference, but if that's the case I'm not sure how to apply that solution to my situation.
Basically, I'm working on (as a learning experience) my own implementation of dependency injection (although I've been told my structure is actually called AMD, I'll keep using "DI" until I understand more about the difference). So I'll briefly explain my code, then highlight the problematic part.
The syntax:
This is what my code should do, it's just very very simple DI.
I created scope with a string path, using "/scopeName/subScopeName:componentName" to select a scope, so that code users can select the scope while defining the component in a simple way, using a ":" to select a component from the scope.
There are no interfaces since it's so simple to type check in JS. There are no special component types such as factories, values, etc, every component is treated equally.
var JHTML = new Viziion('JHTML');
JHTML.addScope('/generate');
/* ... snip ... */
JHTML.addComponent('/generate:process', function(nodes) {
/* ... snip - the code inside isn't important here - snip ..*/
}).inject(['/generate:jsonInput']);
The inject function just takes an array of component paths in the order the component's arguments are expected.
Hooks are components stored in the hooks property, and then there's a function returnUserHandle which will return an object consisting of just the hooks, so all of the functions are hidden in closures, and you can feed the code user just the usable methods.
JHTML.addHook('generate', function(jsonInput, process) {
var html = process(jsonInput);
return html;
}).inject(['/generate:jsonInput', '/generate:process']);
var handle = JHTML.returnUserHandle();
/* HTML Generator Syntax - Client */
console.log(handle.generate());
The problem:
To point inject to the correct object intuitively, there's a focus property on the main object, and I thought I could use that.focus ( which is a reference to this.focus) within my different methods such as addComponent and inject to link new functions to the correct location in my scope model and have them still referenced in focus after being created with addComponent or after being called by the focusComponent method, and then inject could find the dependencies, and "wire" them by doing this:
that.focus = function() {
that.focus.apply(null, dependencies);
};
And I thought that would package the dependencies (an array) as a closure and when the code user calls the function, the correct dependencies get applied and that's the ball game. But nope. The functions dont seem to be passing by reference from that.focus into the scope model. that.focus updates, but the scope model does not.
What's wrong with my reference logic?
The code:
Here's a simplified version of the code. I think I've done my best to explain how it works and where exactly the reference problem I'm trying to solve is located.
/* Dependency Injection Framework - viziion.js */
function Viziion() {
var that = this;
//here's the focus property I mentioned
this.focus = null;
this.scope = {
'/': {
'subScopes': {},
'components': {}
}
};
this.hooks = {};
this.addScope = function(scopeName) {
/* the way this works inst relevant to the problem */
};
this.addComponent = function(componentName, func) {
var scopeArray = // snip
// snip - just code to read the component path
for (var i = 0; i <= scopeArray.length; i++) {
if (scopeArray[i] !== "") {
if (scope.subScopes[scopeArray[i]]) {
scope = scope.subScopes[scopeArray[i]];
} else if (i == scopeArray.length) {
// And here's where I add the component to the scope model
// and reference that component in the focus property
scope.components[scopeName] = func;
that.focus = scope.components[scopeName];
} else {
throw 'Scope path is invalid.';
}
}
}
} else {
throw 'Path does not include a component.';
}
return that;
};
this.returnComponent = function(componentName, callback) {
/* ... snip ... */
};
this.addHook = function(hookName, func) {
/* ... snip ... */
};
this.inject = function(dependencyArray) {
if (dependencyArray) {
var dependencies = [];
for (var i = 0; i < dependencyArray.length; i++) {
that.returnComponent(dependencyArray[i], function(dependency) {
dependencies.push(dependency);
});
}
that.focus = function() {
that.focus.apply(null, dependencies);
};
return that;
}
};
/* ... snip - focusComponent - snip ... */
/* ... snip - returnUserHandle - snip ... */
This should, when applied as shown up above under the "Syntax" header, produce a console log with a string of HTML.
Instead, I get TypeError: undefined is not a function, corresponding to the line var html = process(jsonInput);.
If you want to test the full code, all together, here it is:
/* Dependency Injection Framework - viziion.js */
function Viziion(appName) {
if (typeof appName == 'string') {
var that = this;
this.name = appName;
this.focus = null;
this.scope = {
'/': {
'subScopes': {},
'components': {}
}
};
this.hooks = {};
this.addScope = function(scopeName) {
if (typeof scopeName == 'string') {
var scopeArray = scopeName.split('/');
var scope = that.scope['/'];
for (var i = 0; i < scopeArray.length; i++) {
if (scopeArray[i] !== "") {
if (scope.subScopes[scopeArray[i]]) {
scope = scope.subScopes[scopeArray[i]];
} else {
scope.subScopes[scopeArray[i]] = {
'subScopes': {},
'components': {}
};
}
}
}
} else {
throw 'Scope path must be a string.';
}
return that;
};
this.addComponent = function(componentName, func) {
if (typeof componentName == 'string') {
var scopeArray = componentName.split(':');
if (scopeArray.length == 2) {
var scope = that.scope['/'];
var scopeName = scopeArray[1];
scopeArray = scopeArray[0].split('/');
for (var i = 0; i <= scopeArray.length; i++) {
if (scopeArray[i] !== "") {
if (scope.subScopes[scopeArray[i]]) {
scope = scope.subScopes[scopeArray[i]];
} else if (i == scopeArray.length) {
scope.components[scopeName] = func;
that.focus = scope.components[scopeName];
} else {
throw 'Scope path is invalid.';
}
}
}
} else {
throw 'Path does not include a component.';
}
} else {
throw 'Component path must be a string.';
}
return that;
};
this.returnComponent = function(componentName, callback) {
if (typeof componentName == 'string') {
var scopeArray = componentName.split(':');
if (scopeArray.length == 2) {
var scope = that.scope['/'];
var scopeName = scopeArray[1];
scopeArray = scopeArray[0].split('/');
for (var i = 0; i <= scopeArray.length; i++) {
if (scopeArray[i] !== "") {
if (i == scopeArray.length) {
callback(scope.components[scopeName]);
} else if (scope.subScopes[scopeArray[i]]) {
scope = scope.subScopes[scopeArray[i]];
} else {
throw 'Scope path is invalid.';
}
}
}
} else {
throw 'Path does not include a component.';
}
} else {
throw 'Component path must be a string.';
}
};
this.addHook = function(hookName, func) {
if (typeof hookName == 'string') {
that.hooks[hookName] = func;
that.focus = that.hooks[hookName];
} else {
throw 'Hook name must be a string.';
}
return that;
};
this.inject = function(dependencyArray) {
if (dependencyArray) {
var dependencies = [];
for (var i = 0; i < dependencyArray.length; i++) {
that.returnComponent(dependencyArray[i], function(dependency) {
dependencies.push(dependency);
});
}
console.log(that.focus);
that.focus = function() {
that.focus.apply(null, dependencies);
};
console.log(that.focus);
console.log(that.scope);
return that;
}
};
this.focusComponent = function(componentPath) {
that.focus = that.returnUserHandle(componentPath);
};
this.returnUserHandle = function() {
return that.hooks;
};
} else {
throw 'Viziion name must be a string.';
}
}
/* JSON HTML Generator - A Simple Library Using Viziion */
var JHTML = new Viziion('JHTML');
JHTML.addScope('/generate');
JHTML.addComponent('/generate:jsonInput', [{
tag: '!DOCTYPEHTML'
}, {
tag: 'html',
children: [{
tag: 'head',
children: []
}, {
tag: 'body',
children: []
}]
}]);
JHTML.addComponent('/generate:process', function(nodes) {
var html = [];
var loop = function() {
for (var i = 0; i < nodes.length; i++) {
if (nodes[i].tag) {
html.push('<' + tag + '>');
if (nodes[i].children) {
loop();
}
html.push('</' + tag + '>');
return html;
} else {
throw '[JHTML] Bad syntax: Tag type is not defined on node.';
}
}
};
}).inject(['/generate:jsonInput']);
JHTML.addHook('generate', function(jsonInput, process) {
console.log('Process func arg:');
console.log(process);
var html = process(jsonInput);
return html;
}).inject(['/generate:jsonInput', '/generate:process']);
var handle = JHTML.returnUserHandle();
/* HTML Generator Syntax - Client */
console.log(handle.generate());
Big question, bigger answer. Let's get started.
Heavy OOP, Proper Scope
First and foremost, from your code, it looks like you maybe don't fully grasp the concept of this.
Unless you change the execution context of an object's methods beforehand, said object's methods always have their contextual this bound to the object instance.
That is:
function A () {
var that = this;
this.prop = 1;
this.method = function () {
console.log(that.prop);
};
}
new A().method();
is generally equivalent to:
function A () {
this.prop = 1;
this.method = function () {
console.log(this.prop);
};
}
new A().method();
unless method is adjusted before execution with .bind, .call, or .apply.
Why does this matter? Well, if we use our this context properly we can utilize object prototypes. Prototypes serve as a far more elegant solution to defining every method of an object on a per-instance basis.
Here we create two instances, but only ever one method.
function A () {
this.prop = 1;
}
A.prototype.method = function () {
console.log(this.prop);
};
new A().method();
new A().method();
This is important for clarity, and later on is important when you are binding contexts and arguments to functions (!).
Code Hygiene
You can skip this topic if you like (head down to The Problems(s)), since it might be considered out of place, but keep in mind it does relate to part of the problem with the code.
Your code is hard to read.
Here are some thoughts on that.
Prototypes
Use them. You shouldn't need to worry about users changing execution contexts on you, as that's probably a misuse of your program. Security shouldn't be a concern considering they have the source code.
Not much else to say here.
Exit early
If you're doing sanity checks, try to opt out as early in your code as you can. If you need to throw because of a type mismatch, throw right then and there - not 27 lines later.
// Not great
if (typeof input === 'string') {
...
} else throw 'it away';
// Better
if (typeof input !== 'string') throw 'it away';
...
This goes for loops as well - making appropriate use of the continue keyword. Both of these things improve code clarity, and reduce nesting and code bloat.
Loop caching
When you're looping over a data structure, and you plan to use the current element several times within the block, you should save that element in a variable. Accessing elements and properties isn't necessarily a free-OP.
// Not great
for (var i = 0; i < myArray.length; i++) {
if (myArray[i] > 5) callback(myArray[i]);
internalArray.push(myArray[i]);
}
// Better
var len = myArray.length, element;
for (var i = 0; i < len; i++) {
element = myArray[i];
if (element > 5) callback(element);
internalArray.push(element);
}
When used correctly this improves both clarity and performance.
The Problem(s)
First off, what are we really doing here? The whole problem boils down to an overly complicated application of function binds. That is, simply changing the execution contexts of functions.
I'll also state outright that this program has no bug - it's just flawed.
The major crux of the problem would be these three lines
that.focus = function() {
that.focus.apply(null, dependencies);
};
found in the inject method. They don't make any sense. This would cause an infinite recursion, plain and simple. When you define that function, it doesn't care at all what the focus property of that is right then and there. That matters solely at execution time.
Lucky for us, we never actually get that far, since the process component doesn't get bound correctly.
A huge part of the problem is the focus property. In your program, you're using this as a sort of most recent action. A singular history as to what has just occurred. The problem is, you've tried to hot-swap this value in strange ways.
The focus property (and as you'll see later, other properties) is needed however, because of the reverse application of inject. The way you've structured your component/hook registers into inject model requires state to be held between method invocations.
As an end note for this section, the process component function definition would never have returned anything. Even if your model was correct, your input was flawed. handle.generate() would have returned undefined always.
The Answer(s)
So how can we fix this? Well, the first idea would be to scrap it, honestly. The reverse injection model is ugly, in my opinion. The level of indirection involved with the inject method is very confusing from the surface.
But then we wouldn't learn anything, would we?
So really, how do we fix this? Well, much to the dismay of the functional programmers reading, we need to hold more state.
On its own, our focus property can't provide enough information to properly change the execution contexts of our functions.
On top of our focus, which will simply hold a reference to our most recent component value, we need the field (component/hook name), and the fragment (component object, nothing if hook).
Using these two or three values inside inject, we can take our depedancies array, bind it to our focus, and set the resulting function back into our field.
The great thing about the next part is we can actually drop our closure by making the contextual this of our component/hook the unbound function.
The whole operation looks like this:
var focus = this.focus,
fragment = this.fragment,
field = this.field,
hook = function hook () {
return this.apply(null, arguments);
}, func;
dependencies.unshift(focus);
func = Function.prototype.bind.apply(hook, dependencies);
if (fragment) fragment[field] = func;
else this.hooks[field] = func;
Most of this should be pretty straight forward, but there is one piece that may give people some issues. The important thing to remember is we are essentially creating two functions in sequence here, 'discarding' the first in a sense. (It should be noted that this can be done another way with hook.bind.apply, but it creates even more confusing code. This is about as elegant as you can get.)
dependencies.unshift(focus);
func = Function.prototype.bind.apply(hook, dependencies);
First, we add our focus (our original function) to the front of our list of dependencies. This is important in a moment.
Then we invoke Function.prototype.bind using Function.prototype.apply (remembering that function prototype methods also share the function prototype methods. Pretty much turtles all the way down).
Now we pass our bind context, hook, and our prefixed dependencies to apply.
hook is used as the host for bind, whose contextual this is altered by the first element of the array of arguments passed to apply. The remaining elements are unrolled to shape the subsequent arguments of bind, thus creating the bound arguments of the resulting function.
This isn't a very simple concept, so take your time.
The other thing to note is I've dropped focusComponent completely. Its implementation didn't make sense in context. Your model relies on a last input injection, so you'll need to re-implement focusComponent as a method that simply adjusts the focus, field, and fragment states.
A small sub-fix is the process component function. Not going to go into detail here. You can compare and contrast with your original code, the differences are pretty obvious.
JHTML.addComponent('/generate:process', function (nodes) {
return (function build (struct, nodes) {
var length = nodes.length, node, tag;
for (var i = 0; i < length; i++) {
node = nodes[i];
tag = node.tag;
if (!tag) throw '[JHTML] Bad syntax: Tag type is not defined on node.';
struct.push('<' + tag + '>');
if (node.children) {
build(struct, node.children)
struct.push('</' + tag + '>');
}
}
return struct;
}([], nodes));
}).inject(['/generate:jsonInput']);
The Code
Below is what I would consider a fixed version of your code. It's written in a style that I find useful for both clarity and performance.
/* Dependency Injection Framework - viziion.js */
function Scope () {
this.subScopes = {};
this.components = {};
}
function Viziion (appName) {
if (typeof appName !== 'string') throw 'Viziion name must be a string.';
this.name = appName;
this.working = this.field = this.focus = null
this.scope = { '/': new Scope() };
this.hooks = {};
}
Viziion.prototype.addScope = function (scopeName) {
if (typeof scopeName !== 'string') throw 'Scope path must be a string.';
var scopeArray = scopeName.split('/'),
scope = this.scope['/'],
len = scopeArray.length,
element, sub;
for (var i = 0; i < len; i++) {
element = scopeArray[i];
if (element === '') continue;
sub = scope.subScopes[element]
if (sub) scope = sub;
else scope.subScopes[element] = new Scope();
}
return this;
};
Viziion.prototype.addComponent = function (componentName, func) {
if (typeof componentName !== 'string') throw 'Component path must be a string.';
var scopeArray = componentName.split(':'),
len, element, sub;
if (scopeArray.length != 2) throw 'Path does not include a component.';
var scope = this.scope['/'],
scopeName = scopeArray[1];
scopeArray = scopeArray[0].split('/');
len = scopeArray.length;
for (var i = 0; i <= len; i++) {
element = scopeArray[i];
if (element === '') continue;
sub = scope.subScopes[element];
if (sub) scope = sub;
else if (i === len) {
this.fragment = scope.components;
this.field = scopeName;
this.focus = scope.components[scopeName] = func;
}
else throw 'Scope path is invalid';
};
return this;
};
Viziion.prototype.returnComponent = function (componentName, callback) {
if (typeof componentName !== 'string') throw 'Component path must be a string.';
var scopeArray = componentName.split(':'),
len, element, sub;
if (scopeArray.length != 2) throw 'Path does not include a component.';
var scope = this.scope['/'],
scopeName = scopeArray[1];
scopeArray = scopeArray[0].split('/');
len = scopeArray.length;
for (var i = 0; i <= len; i++) {
element = scopeArray[i];
if (element === '') continue;
sub = scope.subScopes[element]
if (i === len) callback(scope.components[scopeName]);
else if (sub) scope = sub;
else throw 'Scope path is invalid';
}
};
Viziion.prototype.addHook = function (hook, func) {
if (typeof hook !== 'string') throw 'Hook name must be a string.';
this.fragment = null;
this.field = hook;
this.focus = this.hooks[hook] = func;
return this;
};
Viziion.prototype.inject = function (dependancyArray) {
if (!dependancyArray) return;
var dependencies = [],
len = dependancyArray.length,
element;
function push (dep) { dependencies.push(dep); }
for (var i = 0; i < len; i++) {
element = dependancyArray[i];
this.returnComponent(element, push);
}
var focus = this.focus,
fragment = this.fragment,
field = this.field,
hook = function hook () {
return this.apply(null, arguments);
}, func;
dependencies.unshift(focus);
func = Function.prototype.bind.apply(hook, dependencies);
if (fragment) fragment[field] = func;
else this.hooks[field] = func;
return this;
};
Viziion.prototype.returnUserHandle = function () { return this.hooks; };
/* JSON HTML Generator - A Simple Library Using Viziion */
var JHTML = new Viziion('JHTML');
JHTML.addScope('/generate');
JHTML.addComponent('/generate:jsonInput', [{
tag: '!DOCTYPE html'
}, {
tag: 'html',
children: [{
tag: 'head',
children: []
}, {
tag: 'body',
children: []
}]
}]);
JHTML.addComponent('/generate:process', function (nodes) {
return (function build (struct, nodes) {
var length = nodes.length, node, tag;
for (var i = 0; i < length; i++) {
node = nodes[i];
tag = node.tag;
if (!tag) throw '[JHTML] Bad syntax: Tag type is not defined on node.';
struct.push('<' + tag + '>');
if (node.children) {
build(struct, node.children)
struct.push('</' + tag + '>');
}
}
return struct;
}([], nodes));
}).inject(['/generate:jsonInput']);
JHTML.addHook('generate', function (jsonInput, process) {
return process(jsonInput);
}).inject(['/generate:jsonInput', '/generate:process']);
var handle = JHTML.returnUserHandle();
console.log(JHTML);
/* HTML Generator Syntax - Client */
console.log(handle.generate());

on collision event handlers in box2djs

I'm playing around with box2djs. I'm trying to find a way to write an 'onCollision()' callback function, but the documentation is sparse and I can't find an obvious way to do it.
Thanks!
Call back for box2djs is actually referenced as a collision "filter." Here is how you can implement it. I'll also show what I'm doing instead which maybe is a little slower but since my other approach is outside the step() I can destroy objects and stuff:
// Called whenever a collision occurs in the world
//
var JellyCollisionCallback = function()
{
// Required function - this is the function the gets called when b2ContactManager registers a collision between two bodies
//
this.ShouldCollide = function( shape1, shape2 )
{
// These are the two bodies…
//
var cBody1 = shape1.m_body;
var cBody2 = shape2.m_body;
// I'm setting userData when I create the body object
//
var jellyObject1 = cBody1.GetUserData();
var jellyObject2 = cBody2.GetUserData();
// This is the code from the default collision filter
//
if (shape1.m_groupIndex == shape2.m_groupIndex && shape1.m_groupIndex != 0)
{
return shape1.m_groupIndex > 0;
}
var collide = (shape1.m_maskBits & shape2.m_categoryBits) != 0 && (shape1.m_categoryBits & shape2.m_maskBits) != 0;
return collide;
}
return this;
}
function createWorld()
{
var world = new b2World(worldAABB, gravity, doSleep);
myCollisionCallback = new JellyCollisionCallback();
world.SetFilter(myCollisionCallback );
}
probably not as nice as a true callback, but I had originally had trouble trying to get a callback to work so I wrote this approach and ended up keeping it instead. I do this in my main loop that calls the world.step()
// Find collisions between selected objects
//
// (world is the main b2World object)
//
var aContact;
for ( aContact = world.m_contactList; aContact != null; aContact = aContact.m_next )
{
var cBody1 = aContact.m_shape1.m_body;
var cBody2 = aContact.m_shape2.m_body;
// I'm setting userData when I create the body object
//
var jellyObject1 = cBody1.GetUserData();
var jellyObject2 = cBody2.GetUserData();
// Not one of my controlled Objects
//
if ( typeof(jellyObject1) != "object" || jellyObject1 == null )
continue;
if ( typeof(jellyObject2) != "object" || jellyObject2 == null )
continue;
// Call my collision event for the colliding objects
//
jellyObject1.dink();
jellyObject2.dink();
}
documentation is pretty much unavailable from what I found, but I really like box2djs and have finally figured out everything I need to accomplish some simple hobby projects. Here are some examples that extend the original box2djs demo jellyrobotics box2djs project

How to invoke a method of js object after invoking another method?

I often saw this code in jQuery.
$('div').action1().delay(miliseconds).action2();
I could realize it in one level action in the following code.
function $(id) {
var $ = document.getElementById(id);
$.action1 = function() {
};
return $;
}
How to write the method delay() and action2() so that I could use them this way?
$('div').action1().delay(miliseconds).action2();
What you're referring to is called chaining. Aside from the fact that delay is used for animations, the key point to remember is to return this from your function.
If you'd like to see how specific jQuery functions work, check out the code for removeClass:
removeClass: function( value ) {
if ( jQuery.isFunction(value) ) {
return this.each(function(i) {
var self = jQuery(this);
self.removeClass( value.call(this, i, self.attr("class")) );
});
}
if ( (value && typeof value === "string") || value === undefined ) {
var classNames = (value || "").split(rspace);
for ( var i = 0, l = this.length; i < l; i++ ) {
var elem = this[i];
if ( elem.nodeType === 1 && elem.className ) {
if ( value ) {
var className = (" " + elem.className + " ").replace(rclass, " ");
for ( var c = 0, cl = classNames.length; c < cl; c++ ) {
className = className.replace(" " + classNames[c] + " ", " ");
}
elem.className = jQuery.trim( className );
} else {
elem.className = "";
}
}
}
}
return this;
},
Notice the return this; at the end? That's allowing you to call $('#myelement').removeClass('highlight').someOtherFunction(), because at the end of the removeClass, you're still operating on the jQuery object itself.
If you'd like to examine other functions, check out the development version (unminified) of jQuery: http://code.jquery.com/jquery-1.4.2.js
Edit: to more fully answer your question, you can write your functions to allow chaining in the following way (include after your jQuery include):
(function($){
$.fn.extend({
action1: function() { return this; },
action2: function() { return this; }
})(jQuery);
This is essentially creating your own plugin. You can find a lot of tutorials online for how to do so, or open a plugin you already have an take a look at it.
Here is one simple tutorial: http://www.queness.com/post/112/a-really-simple-jquery-plugin-tutorial
Edit2: Without getting too far into creating jQuery plugins (since your questions is about javascript in general), I just wanted to mention that if you're doing a jQuery plugin, you'll want to do:
return this.each(function() {});
so your function performs on all elements chosen by the selector.
.delay() is used for animations
Sure there's other ways you can do this, but jQuery is chainable in an awesome way. That is, you don't have to write a bunch of anonymous functions or custom callbacks if you don't want to. Convenience in chaining!
On the other hand, if you actually want to customize the callbacks of animations, you can!
$('#foo').slideDown(500, function(){
alert('foo is visible now!');
});
Check out the jQuery Effects API for more information.
It might be helpful to look at JavaScript's native setTimeout() function, too.

How to create a jQuery plugin with methods?

I'm trying to write a jQuery plugin that will provide additional functions/methods to the object that calls it. All the tutorials I read online (have been browsing for the past 2 hours) include, at the most, how to add options, but not additional functions.
Here's what I am looking to do:
//format div to be a message container by calling the plugin for that div
$("#mydiv").messagePlugin();
$("#mydiv").messagePlugin().saySomething("hello");
or something along those lines.
Here's what it boils down to: I call the plugin, then I call a function associated with that plugin. I can't seem to find a way to do this, and I've seen many plugins do it before.
Here's what I have so far for the plugin:
jQuery.fn.messagePlugin = function() {
return this.each(function(){
alert(this);
});
//i tried to do this, but it does not seem to work
jQuery.fn.messagePlugin.saySomething = function(message){
$(this).html(message);
}
};
How can I achieve something like that?
Thank you!
Update Nov 18, 2013: I've changed the correct answer to that of Hari's following comments and upvotes.
According to the jQuery Plugin Authoring page (http://docs.jquery.com/Plugins/Authoring), it's best not to muddy up the jQuery and jQuery.fn namespaces. They suggest this method:
(function( $ ){
var methods = {
init : function(options) {
},
show : function( ) { },// IS
hide : function( ) { },// GOOD
update : function( content ) { }// !!!
};
$.fn.tooltip = function(methodOrOptions) {
if ( methods[methodOrOptions] ) {
return methods[ methodOrOptions ].apply( this, Array.prototype.slice.call( arguments, 1 ));
} else if ( typeof methodOrOptions === 'object' || ! methodOrOptions ) {
// Default to "init"
return methods.init.apply( this, arguments );
} else {
$.error( 'Method ' + methodOrOptions + ' does not exist on jQuery.tooltip' );
}
};
})( jQuery );
Basically you store your functions in an array (scoped to the wrapping function) and check for an entry if the parameter passed is a string, reverting to a default method ("init" here) if the parameter is an object (or null).
Then you can call the methods like so...
$('div').tooltip(); // calls the init method
$('div').tooltip({ // calls the init method
foo : 'bar'
});
$('div').tooltip('hide'); // calls the hide method
$('div').tooltip('update', 'This is the new tooltip content!'); // calls the update method
Javascripts "arguments" variable is an array of all the arguments passed so it works with arbitrary lengths of function parameters.
Here's the pattern I have used for creating plugins with additional methods. You would use it like:
$('selector').myplugin( { key: 'value' } );
or, to invoke a method directly,
$('selector').myplugin( 'mymethod1', 'argument' );
Example:
;(function($) {
$.fn.extend({
myplugin: function(options,arg) {
if (options && typeof(options) == 'object') {
options = $.extend( {}, $.myplugin.defaults, options );
}
// this creates a plugin for each element in
// the selector or runs the function once per
// selector. To have it do so for just the
// first element (once), return false after
// creating the plugin to stop the each iteration
this.each(function() {
new $.myplugin(this, options, arg );
});
return;
}
});
$.myplugin = function( elem, options, arg ) {
if (options && typeof(options) == 'string') {
if (options == 'mymethod1') {
myplugin_method1( arg );
}
else if (options == 'mymethod2') {
myplugin_method2( arg );
}
return;
}
...normal plugin actions...
function myplugin_method1(arg)
{
...do method1 with this and arg
}
function myplugin_method2(arg)
{
...do method2 with this and arg
}
};
$.myplugin.defaults = {
...
};
})(jQuery);
What about this approach:
jQuery.fn.messagePlugin = function(){
var selectedObjects = this;
return {
saySomething : function(message){
$(selectedObjects).each(function(){
$(this).html(message);
});
return selectedObjects; // Preserve the jQuery chainability
},
anotherAction : function(){
//...
return selectedObjects;
}
};
}
// Usage:
$('p').messagePlugin().saySomething('I am a Paragraph').css('color', 'red');
The selected objects are stored in the messagePlugin closure, and that function returns an object that contains the functions associated with the plugin, the in each function you can perform the desired actions to the currently selected objects.
You can test and play with the code here.
Edit: Updated code to preserve the power of the jQuery chainability.
The problem with the currently selected answer is that you're not actually creating a new instance of the custom plugin for every element in the selector like you think you're doing... you're actually only creating a single instance and passing in the selector itself as the scope.
View this fiddle for a deeper explanation.
Instead, you'll need to loop through the selector using jQuery.each and instantiate a new instance of the custom plugin for every element in the selector.
Here's how:
(function($) {
var CustomPlugin = function($el, options) {
this._defaults = {
randomizer: Math.random()
};
this._options = $.extend(true, {}, this._defaults, options);
this.options = function(options) {
return (options) ?
$.extend(true, this._options, options) :
this._options;
};
this.move = function() {
$el.css('margin-left', this._options.randomizer * 100);
};
};
$.fn.customPlugin = function(methodOrOptions) {
var method = (typeof methodOrOptions === 'string') ? methodOrOptions : undefined;
if (method) {
var customPlugins = [];
function getCustomPlugin() {
var $el = $(this);
var customPlugin = $el.data('customPlugin');
customPlugins.push(customPlugin);
}
this.each(getCustomPlugin);
var args = (arguments.length > 1) ? Array.prototype.slice.call(arguments, 1) : undefined;
var results = [];
function applyMethod(index) {
var customPlugin = customPlugins[index];
if (!customPlugin) {
console.warn('$.customPlugin not instantiated yet');
console.info(this);
results.push(undefined);
return;
}
if (typeof customPlugin[method] === 'function') {
var result = customPlugin[method].apply(customPlugin, args);
results.push(result);
} else {
console.warn('Method \'' + method + '\' not defined in $.customPlugin');
}
}
this.each(applyMethod);
return (results.length > 1) ? results : results[0];
} else {
var options = (typeof methodOrOptions === 'object') ? methodOrOptions : undefined;
function init() {
var $el = $(this);
var customPlugin = new CustomPlugin($el, options);
$el.data('customPlugin', customPlugin);
}
return this.each(init);
}
};
})(jQuery);
And a working fiddle.
You'll notice how in the first fiddle, all divs are always moved to the right the exact same number of pixels. That is because only one options object exists for all elements in the selector.
Using the technique written above, you'll notice that in the second fiddle, each div is not aligned and is randomly moved (excluding the first div as it's randomizer is always set to 1 on line 89). That is because we are now properly instantiating a new custom plugin instance for every element in the selector. Every element has its own options object and is not saved in the selector, but in the instance of the custom plugin itself.
This means that you'll be able to access the methods of the custom plugin instantiated on a specific element in the DOM from new jQuery selectors and aren't forced to cache them, as you would be in the first fiddle.
For example, this would return an array of all options objects using the technique in the second fiddle. It would return undefined in the first.
$('div').customPlugin();
$('div').customPlugin('options'); // would return an array of all options objects
This is how you would have to access the options object in the first fiddle, and would only return a single object, not an array of them:
var divs = $('div').customPlugin();
divs.customPlugin('options'); // would return a single options object
$('div').customPlugin('options');
// would return undefined, since it's not a cached selector
I'd suggest using the technique above, not the one from the currently selected answer.
Use the jQuery UI Widget Factory.
Writing Stateful Plugins with the jQuery UI Widget Factory
How To Use the Widget Factory
Example:
$.widget( "myNamespace.myPlugin", {
options: {
// Default options
},
_create: function() {
// Initialization logic here
},
// Create a public method.
myPublicMethod: function( argument ) {
// ...
},
// Create a private method.
_myPrivateMethod: function( argument ) {
// ...
}
});
Initialization:
$('#my-element').myPlugin();
$('#my-element').myPlugin( {defaultValue:10} );
Method calling:
$('#my-element').myPlugin('myPublicMethod', 20);
(This is how the jQuery UI library is built.)
A simpler approach is to use nested functions. Then you can chain them in an object-oriented fashion. Example:
jQuery.fn.MyPlugin = function()
{
var _this = this;
var a = 1;
jQuery.fn.MyPlugin.DoSomething = function()
{
var b = a;
var c = 2;
jQuery.fn.MyPlugin.DoSomething.DoEvenMore = function()
{
var d = a;
var e = c;
var f = 3;
return _this;
};
return _this;
};
return this;
};
And here's how to call it:
var pluginContainer = $("#divSomeContainer");
pluginContainer.MyPlugin();
pluginContainer.MyPlugin.DoSomething();
pluginContainer.MyPlugin.DoSomething.DoEvenMore();
Be careful though. You cannot call a nested function until it has been created. So you cannot do this:
var pluginContainer = $("#divSomeContainer");
pluginContainer.MyPlugin();
pluginContainer.MyPlugin.DoSomething.DoEvenMore();
pluginContainer.MyPlugin.DoSomething();
The DoEvenMore function doesn't even exist because the DoSomething function hasn't been run yet which is required to create the DoEvenMore function. For most jQuery plugins, you really are only going to have one level of nested functions and not two as I've shown here.
Just make sure that when you create nested functions that you define these functions at the beginning of their parent function before any other code in the parent function gets executed.
Finally, note that the "this" member is stored in a variable called "_this". For nested functions, you should return "_this" if you need a reference to the instance in the calling client. You cannot just return "this" in the nested function because that will return a reference to the function and not the jQuery instance. Returning a jQuery reference allows you to chain intrinsic jQuery methods on return.
I got it from jQuery Plugin Boilerplate
Also described in jQuery Plugin Boilerplate, reprise
// jQuery Plugin Boilerplate
// A boilerplate for jumpstarting jQuery plugins development
// version 1.1, May 14th, 2011
// by Stefan Gabos
// remember to change every instance of "pluginName" to the name of your plugin!
(function($) {
// here we go!
$.pluginName = function(element, options) {
// plugin's default options
// this is private property and is accessible only from inside the plugin
var defaults = {
foo: 'bar',
// if your plugin is event-driven, you may provide callback capabilities
// for its events. execute these functions before or after events of your
// plugin, so that users may customize those particular events without
// changing the plugin's code
onFoo: function() {}
}
// to avoid confusions, use "plugin" to reference the
// current instance of the object
var plugin = this;
// this will hold the merged default, and user-provided options
// plugin's properties will be available through this object like:
// plugin.settings.propertyName from inside the plugin or
// element.data('pluginName').settings.propertyName from outside the plugin,
// where "element" is the element the plugin is attached to;
plugin.settings = {}
var $element = $(element), // reference to the jQuery version of DOM element
element = element; // reference to the actual DOM element
// the "constructor" method that gets called when the object is created
plugin.init = function() {
// the plugin's final properties are the merged default and
// user-provided options (if any)
plugin.settings = $.extend({}, defaults, options);
// code goes here
}
// public methods
// these methods can be called like:
// plugin.methodName(arg1, arg2, ... argn) from inside the plugin or
// element.data('pluginName').publicMethod(arg1, arg2, ... argn) from outside
// the plugin, where "element" is the element the plugin is attached to;
// a public method. for demonstration purposes only - remove it!
plugin.foo_public_method = function() {
// code goes here
}
// private methods
// these methods can be called only from inside the plugin like:
// methodName(arg1, arg2, ... argn)
// a private method. for demonstration purposes only - remove it!
var foo_private_method = function() {
// code goes here
}
// fire up the plugin!
// call the "constructor" method
plugin.init();
}
// add the plugin to the jQuery.fn object
$.fn.pluginName = function(options) {
// iterate through the DOM elements we are attaching the plugin to
return this.each(function() {
// if plugin has not already been attached to the element
if (undefined == $(this).data('pluginName')) {
// create a new instance of the plugin
// pass the DOM element and the user-provided options as arguments
var plugin = new $.pluginName(this, options);
// in the jQuery version of the element
// store a reference to the plugin object
// you can later access the plugin and its methods and properties like
// element.data('pluginName').publicMethod(arg1, arg2, ... argn) or
// element.data('pluginName').settings.propertyName
$(this).data('pluginName', plugin);
}
});
}
})(jQuery);
Too late but maybe it can help someone one day.
I was in the same situation like, creating a jQuery plugin with some methods, and after reading some articles and some tires I create a jQuery plugin boilerplate (https://github.com/acanimal/jQuery-Plugin-Boilerplate).
In addition, I develop with it a plugin to manage tags (https://github.com/acanimal/tagger.js) and wrote a two blog posts explaining step by step the creation of a jQuery plugin (https://www.acuriousanimal.com/blog/20130115/things-i-learned-creating-a-jquery-plugin-part-i).
You can do:
(function($) {
var YourPlugin = function(element, option) {
var defaults = {
//default value
}
this.option = $.extend({}, defaults, option);
this.$element = $(element);
this.init();
}
YourPlugin.prototype = {
init: function() { },
show: function() { },
//another functions
}
$.fn.yourPlugin = function(option) {
var arg = arguments,
options = typeof option == 'object' && option;;
return this.each(function() {
var $this = $(this),
data = $this.data('yourPlugin');
if (!data) $this.data('yourPlugin', (data = new YourPlugin(this, options)));
if (typeof option === 'string') {
if (arg.length > 1) {
data[option].apply(data, Array.prototype.slice.call(arg, 1));
} else {
data[option]();
}
}
});
};
});
In this way your plugins object is stored as data value in your element.
//Initialization without option
$('#myId').yourPlugin();
//Initialization with option
$('#myId').yourPlugin({
// your option
});
// call show method
$('#myId').yourPlugin('show');
What about using triggers? Does anyone know any drawback using them?
The benefit is that all internal variables are accessible via the triggers, and the code is very simple.
See on jsfiddle.
Example usage
<div id="mydiv">This is the message container...</div>
<script>
var mp = $("#mydiv").messagePlugin();
// the plugin returns the element it is called on
mp.trigger("messagePlugin.saySomething", "hello");
// so defining the mp variable is not needed...
$("#mydiv").trigger("messagePlugin.repeatLastMessage");
</script>
Plugin
jQuery.fn.messagePlugin = function() {
return this.each(function() {
var lastmessage,
$this = $(this);
$this.on('messagePlugin.saySomething', function(e, message) {
lastmessage = message;
saySomething(message);
});
$this.on('messagePlugin.repeatLastMessage', function(e) {
repeatLastMessage();
});
function saySomething(message) {
$this.html("<p>" + message + "</p>");
}
function repeatLastMessage() {
$this.append('<p>Last message was: ' + lastmessage + '</p>');
}
});
}
Here I want to suggest steps to create simple plugin with arguments.
(function($) {
$.fn.myFirstPlugin = function(options) {
// Default params
var params = $.extend({
text : 'Default Title',
fontsize : 10,
}, options);
return $(this).text(params.text);
}
}(jQuery));
$('.cls-title').myFirstPlugin({ text : 'Argument Title' });
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<h1 class="cls-title"></h1>
Here, we have added default object called params and set default values of options using extend function. Hence, If we pass blank argument then it will set default values instead otherwise it will set.
Read more: How to Create JQuery plugin
Try this one:
$.fn.extend({
"calendar":function(){
console.log(this);
var methods = {
"add":function(){console.log("add"); return this;},
"init":function(){console.log("init"); return this;},
"sample":function(){console.log("sample"); return this;}
};
methods.init(); // you can call any method inside
return methods;
}});
$.fn.calendar() // caller or
$.fn.calendar().sample().add().sample() ......; // call methods
Here is my bare-bones version of this. Similar to the ones posted before, you would call like:
$('#myDiv').MessagePlugin({ yourSettings: 'here' })
.MessagePlugin('saySomething','Hello World!');
-or access the instance directly # plugin_MessagePlugin
$elem = $('#myDiv').MessagePlugin();
var instance = $elem.data('plugin_MessagePlugin');
instance.saySomething('Hello World!');
MessagePlugin.js
;(function($){
function MessagePlugin(element,settings){ // The Plugin
this.$elem = element;
this._settings = settings;
this.settings = $.extend(this._default,settings);
}
MessagePlugin.prototype = { // The Plugin prototype
_default: {
message: 'Generic message'
},
initialize: function(){},
saySomething: function(message){
message = message || this._default.message;
return this.$elem.html(message);
}
};
$.fn.MessagePlugin = function(settings){ // The Plugin call
var instance = this.data('plugin_MessagePlugin'); // Get instance
if(instance===undefined){ // Do instantiate if undefined
settings = settings || {};
this.data('plugin_MessagePlugin',new MessagePlugin(this,settings));
return this;
}
if($.isFunction(MessagePlugin.prototype[settings])){ // Call method if argument is name of method
var args = Array.prototype.slice.call(arguments); // Get the arguments as Array
args.shift(); // Remove first argument (name of method)
return MessagePlugin.prototype[settings].apply(instance, args); // Call the method
}
// Do error handling
return this;
}
})(jQuery);
The following plugin-structure utilizes the jQuery-data()-method to provide a public interface to internal plugin-methods/-settings (while preserving jQuery-chainability):
(function($, window, undefined) {
const defaults = {
elementId : null,
shape : "square",
color : "aqua",
borderWidth : "10px",
borderColor : "DarkGray"
};
$.fn.myPlugin = function(options) {
// settings, e.g.:
var settings = $.extend({}, defaults, options);
// private methods, e.g.:
var setBorder = function(color, width) {
settings.borderColor = color;
settings.borderWidth = width;
drawShape();
};
var drawShape = function() {
$('#' + settings.elementId).attr('class', settings.shape + " " + "center");
$('#' + settings.elementId).css({
'background-color': settings.color,
'border': settings.borderWidth + ' solid ' + settings.borderColor
});
$('#' + settings.elementId).html(settings.color + " " + settings.shape);
};
return this.each(function() { // jQuery chainability
// set stuff on ini, e.g.:
settings.elementId = $(this).attr('id');
drawShape();
// PUBLIC INTERFACE
// gives us stuff like:
//
// $("#...").data('myPlugin').myPublicPluginMethod();
//
var myPlugin = {
element: $(this),
// access private plugin methods, e.g.:
setBorder: function(color, width) {
setBorder(color, width);
return this.element; // To ensure jQuery chainability
},
// access plugin settings, e.g.:
color: function() {
return settings.color;
},
// access setting "shape"
shape: function() {
return settings.shape;
},
// inspect settings
inspectSettings: function() {
msg = "inspecting settings for element '" + settings.elementId + "':";
msg += "\n--- shape: '" + settings.shape + "'";
msg += "\n--- color: '" + settings.color + "'";
msg += "\n--- border: '" + settings.borderWidth + ' solid ' + settings.borderColor + "'";
return msg;
},
// do stuff on element, e.g.:
change: function(shape, color) {
settings.shape = shape;
settings.color = color;
drawShape();
return this.element; // To ensure jQuery chainability
}
};
$(this).data("myPlugin", myPlugin);
}); // return this.each
}; // myPlugin
}(jQuery));
Now you can call internal plugin-methods to access or modify plugin data or the relevant element using this syntax:
$("#...").data('myPlugin').myPublicPluginMethod();
As long as you return the current element (this) from inside your implementation of myPublicPluginMethod() jQuery-chainability
will be preserved - so the following works:
$("#...").data('myPlugin').myPublicPluginMethod().css("color", "red").html("....");
Here are some examples (for details checkout this fiddle):
// initialize plugin on elements, e.g.:
$("#shape1").myPlugin({shape: 'square', color: 'blue', borderColor: 'SteelBlue'});
$("#shape2").myPlugin({shape: 'rectangle', color: 'red', borderColor: '#ff4d4d'});
$("#shape3").myPlugin({shape: 'circle', color: 'green', borderColor: 'LimeGreen'});
// calling plugin methods to read element specific plugin settings:
console.log($("#shape1").data('myPlugin').inspectSettings());
console.log($("#shape2").data('myPlugin').inspectSettings());
console.log($("#shape3").data('myPlugin').inspectSettings());
// calling plugin methods to modify elements, e.g.:
// (OMG! And they are chainable too!)
$("#shape1").data('myPlugin').change("circle", "green").fadeOut(2000).fadeIn(2000);
$("#shape1").data('myPlugin').setBorder('LimeGreen', '30px');
$("#shape2").data('myPlugin').change("rectangle", "red");
$("#shape2").data('myPlugin').setBorder('#ff4d4d', '40px').css({
'width': '350px',
'font-size': '2em'
}).slideUp(2000).slideDown(2000);
$("#shape3").data('myPlugin').change("square", "blue").fadeOut(2000).fadeIn(2000);
$("#shape3").data('myPlugin').setBorder('SteelBlue', '30px');
// etc. ...
This can actually be made to work in a "nice" way using defineProperty. Where "nice" means without having to use () to get plugin namespace nor having to pass function name by string.
Compatibility nit: defineProperty doesn't work in ancient browsers such as IE8 and below.
Caveat: $.fn.color.blue.apply(foo, args) won't work, you need to use foo.color.blue.apply(foo, args).
function $_color(color)
{
return this.css('color', color);
}
function $_color_blue()
{
return this.css('color', 'blue');
}
Object.defineProperty($.fn, 'color',
{
enumerable: true,
get: function()
{
var self = this;
var ret = function() { return $_color.apply(self, arguments); }
ret.blue = function() { return $_color_blue.apply(self, arguments); }
return ret;
}
});
$('#foo').color('#f00');
$('#bar').color.blue();
JSFiddle link
According to jquery standard you can create plugin as follow:
(function($) {
//methods starts here....
var methods = {
init : function(method,options) {
this.loadKeywords.settings = $.extend({}, this.loadKeywords.defaults, options);
methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
$loadkeywordbase=$(this);
},
show : function() {
//your code here.................
},
getData : function() {
//your code here.................
}
} // do not put semi colon here otherwise it will not work in ie7
//end of methods
//main plugin function starts here...
$.fn.loadKeywords = function(options,method) {
if (methods[method]) {
return methods[method].apply(this, Array.prototype.slice.call(
arguments, 1));
} else if (typeof method === 'object' || !method) {
return methods.init.apply(this, arguments);
} else {
$.error('Method ' + method + ' does not ecw-Keywords');
}
};
$.fn.loadKeywords.defaults = {
keyName: 'Messages',
Options: '1',
callback: '',
};
$.fn.loadKeywords.settings = {};
//end of plugin keyword function.
})(jQuery);
How to call this plugin?
1.$('your element').loadKeywords('show',{'callback':callbackdata,'keyName':'myKey'}); // show() will be called
Reference: link
I think this might help you...
(function ( $ ) {
$.fn.highlight = function( options ) {
// This is the easiest way to have default options.
var settings = $.extend({
// These are the defaults.
color: "#000",
backgroundColor: "yellow"
}, options );
// Highlight the collection based on the settings variable.
return this.css({
color: settings.color,
backgroundColor: settings.backgroundColor
});
};
}( jQuery ));
In the above example i had created a simple jquery highlight plugin.I had shared an article in which i had discussed about How to Create Your Own jQuery Plugin from Basic to Advance.
I think you should check it out... http://mycodingtricks.com/jquery/how-to-create-your-own-jquery-plugin/
Following is a small plug-in to have warning method for debugging purpose. Keep this code in jquery.debug.js file:
JS:
jQuery.fn.warning = function() {
return this.each(function() {
alert('Tag Name:"' + $(this).prop("tagName") + '".');
});
};
HTML:
<html>
<head>
<title>The jQuery Example</title>
<script type = "text/javascript"
src = "http://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src = "jquery.debug.js" type = "text/javascript"></script>
<script type = "text/javascript" language = "javascript">
$(document).ready(function() {
$("div").warning();
$("p").warning();
});
</script>
</head>
<body>
<p>This is paragraph</p>
<div>This is division</div>
</body>
</html>
Here is how I do it:
(function ( $ ) {
$.fn.gridview = function( options ) {
..........
..........
var factory = new htmlFactory();
factory.header(...);
........
};
}( jQuery ));
var htmlFactory = function(){
//header
this.header = function(object){
console.log(object);
}
}
What you did is basically extending jQuery.fn.messagePlugin object by new method. Which is useful but not in your case.
You have to do is using this technique
function methodA(args){ this // refers to object... }
function saySomething(message){ this.html(message); to first function }
jQuery.fn.messagePlugin = function(opts) {
if(opts=='methodA') methodA.call(this);
if(opts=='saySomething') saySomething.call(this, arguments[0]); // arguments is an array of passed parameters
return this.each(function(){
alert(this);
});
};
But you can accomplish what you want I mean there is a way to do $("#mydiv").messagePlugin().saySomething("hello"); My friend he started writing about lugins and how to extend them with your chainf of functionalities here is the link to his blog

Categories

Resources