glint-block
Version:
161 lines (140 loc) • 3.56 kB
JavaScript
/**********************
* Module Dependencies.
*********************/
var debug = require('debug')('glint-block');
var isBrowser = require('is-browser');
var slice = require('sliced');
var inherits = require('inherits');
var EventEmitter = require('events').EventEmitter;
/**
* Expose Block element.
*/
exports = module.exports = Block;
inherits(Block, EventEmitter);
/**
* Initialize a new `Block` element.
* @param {[type]} options [description]
*/
function Block(block) {
if (!(this instanceof Block)) return new Block(block);
this.buffer = [];
this.delegate(block);
this.init();
}
/****************
* API Functions.
***************/
Block.prototype.api = Block.api = 'block';
['id', 'selector', 'el', 'place'].forEach(function(attribute) {
Block.prototype[attribute] = function(value) {
this.emit(attribute, value);
if (typeof value !== 'undefined') {
this.send(attribute, value);
return this;
}
return this.send(attribute);
};
});
// blocks must implement:
// - load, edit, save
// the other methods are optional:
// - cancel, hasChanged, isValid
['load', 'edit', 'save', 'cancel', 'hasChanged', 'isValid',].forEach(function(name) {
Block.prototype[name] = function(arg) {
var errorReturn = '';
var args = slice(arguments);
this.emit.apply(this, ['pre-' + name].concat(args));
var result = errorReturn;
try {
result = this.send.apply(this, [name].concat(args));
} catch (e) {
var message = 'block command "' + name + '" was not successful';
debug(message, e.message, e.stack);
console.log(message, ',arguments', args, ',selector', this.selector(), ',el', this.el());
result = arg || errorReturn;
}
this.emit.apply(this, ['post-' + name].concat(args));
return result;
};
});
/**
* Forward function calls to this Implementation
*/
Block.prototype.delegate = function(block) {
if (!block) return this.block;
this.block = block;
// execute buffered commands
while (this.buffer.length > 0) {
var cmd = this.buffer.shift();
this.exec(cmd);
}
return this;
};
Block.prototype.undelegate = function(block) {
this.block = undefined;
};
/**
* Use the given `plugin`.
*
* @param {Function} plugin
* @api private
*/
Block.prototype.use = function(plugin) {
plugin(this);
return this;
};
/**
* Mixin the given `mixins` functions.
* @param {Object} mixins e.g.
*
* { key : function fn () {} }
*
* @returns {Block}
*/
Block.prototype.mixin = function(mixins) {
var self = this;
Object.keys(mixins).forEach(function(key) {
self[key] = mixins[key];
});
return this;
};
/****************
* Base functions.
***************/
Block.prototype.init = function() {
this.on('selector', function(selector) {
if (isBrowser && selector) this.send('el', document.querySelector(selector));
});
};
Block.prototype.send = function(command, rest) {
var args = slice(arguments);
if (!this.block) {
// buffer
this.buffer.push(args);
return this;
} else {
// send
return this.exec(args);
}
};
/**
* Don't call this method directly.
*
* @param args
* @api private
*/
Block.prototype.exec = function(args) {
var command = args.shift();
var impl = this.block[command];
if (typeof impl == 'function') {
// call function
return this.block[command].apply(this.block, args);
} else if (args.length > 0) {
// set attribute
this.block[command] = args.shift();
return this;
} else {
// get attribute
return this.block[command];
}
};