kaiwa/clientapp/libraries/ui.js

448 lines
7.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

var ui = {};
;(function(exports){
/**
* Expose `Emitter`.
*/
exports.Emitter = Emitter;
/**
* Initialize a new `Emitter`.
*
* @api public
*/
function Emitter() {
this.callbacks = {};
};
/**
* Listen on the given `event` with `fn`.
*
* @param {String} event
* @param {Function} fn
* @return {Emitter}
* @api public
*/
Emitter.prototype.on = function(event, fn){
(this.callbacks[event] = this.callbacks[event] || [])
.push(fn);
return this;
};
/**
* Adds an `event` listener that will be invoked a single
* time then automatically removed.
*
* @param {String} event
* @param {Function} fn
* @return {Emitter}
* @api public
*/
Emitter.prototype.once = function(event, fn){
var self = this;
function on() {
self.off(event, on);
fn.apply(this, arguments);
}
this.on(event, on);
return this;
};
/**
* Remove the given callback for `event` or all
* registered callbacks.
*
* @param {String} event
* @param {Function} fn
* @return {Emitter}
* @api public
*/
Emitter.prototype.off = function(event, fn){
var callbacks = this.callbacks[event];
if (!callbacks) return this;
// remove all handlers
if (1 == arguments.length) {
delete this.callbacks[event];
return this;
}
// remove specific handler
var i = callbacks.indexOf(fn);
callbacks.splice(i, 1);
return this;
};
/**
* Emit `event` with the given args.
*
* @param {String} event
* @param {Mixed} ...
* @return {Emitter}
*/
Emitter.prototype.emit = function(event){
var args = [].slice.call(arguments, 1)
, callbacks = this.callbacks[event];
if (callbacks) {
for (var i = 0, len = callbacks.length; i < len; ++i) {
callbacks[i].apply(this, args);
}
}
return this;
};
})(ui);
;(function(exports, html){
/**
* Expose `Overlay`.
*/
exports.Overlay = Overlay;
/**
* Return a new `Overlay` with the given `options`.
*
* @param {Object} options
* @return {Overlay}
* @api public
*/
exports.overlay = function(options){
return new Overlay(options);
};
/**
* Initialize a new `Overlay`.
*
* @param {Object} options
* @api public
*/
function Overlay(options) {
ui.Emitter.call(this);
var self = this;
options = options || {};
this.closable = options.closable;
this.el = $(html);
this.el.appendTo('body');
if (this.closable) {
this.el.click(function(){
self.emit('close');
self.hide();
});
}
}
/**
* Inherit from `Emitter.prototype`.
*/
Overlay.prototype = new ui.Emitter;
/**
* Show the overlay.
*
* Emits "show" event.
*
* @return {Overlay} for chaining
* @api public
*/
Overlay.prototype.show = function(){
this.emit('show');
this.el.removeClass('hide');
return this;
};
/**
* Hide the overlay.
*
* Emits "hide" event.
*
* @return {Overlay} for chaining
* @api public
*/
Overlay.prototype.hide = function(){
var self = this;
this.emit('hide');
this.el.addClass('hide');
setTimeout(function(){
self.el.remove();
}, 2000);
return this;
};
})(ui, "<div id=\"overlay\" class=\"hide\"></div>");
;(function(exports, html){
/**
* Active dialog.
*/
var active;
/**
* Expose `Dialog`.
*/
exports.Dialog = Dialog;
/**
* Return a new `Dialog` with the given
* (optional) `title` and `msg`.
*
* @param {String} title or msg
* @param {String} msg
* @return {Dialog}
* @api public
*/
exports.dialog = function(title, msg){
switch (arguments.length) {
case 2:
return new Dialog({ title: title, message: msg });
case 1:
return new Dialog({ message: title });
}
};
/**
* Initialize a new `Dialog`.
*
* Options:
*
* - `title` dialog title
* - `message` a message to display
*
* Emits:
*
* - `show` when visible
* - `hide` when hidden
*
* @param {Object} options
* @api public
*/
function Dialog(options) {
ui.Emitter.call(this);
options = options || {};
this.template = html;
this.el = $(this.template);
this.render(options);
if (active && !active.hiding) active.hide();
if (Dialog.effect) this.effect(Dialog.effect);
active = this;
};
/**
* Inherit from `Emitter.prototype`.
*/
Dialog.prototype = new ui.Emitter;
/**
* Render with the given `options`.
*
* @param {Object} options
* @api public
*/
Dialog.prototype.render = function(options){
var el = this.el
, title = options.title
, msg = options.message
, self = this;
el.find('.close').click(function(){
self.emit('close');
self.hide();
return false;
});
el.find('h1').text(title);
if (!title) el.find('h1').remove();
// message
if ('string' == typeof msg) {
el.find('p').text(msg);
} else if (msg) {
el.find('p').replaceWith(msg.el || msg);
}
setTimeout(function(){
el.removeClass('hide');
}, 0);
};
/**
* Enable the dialog close link.
*
* @return {Dialog} for chaining
* @api public
*/
Dialog.prototype.closable = function(){
this.el.addClass('closable');
return this;
};
/**
* Set the effect to `type`.
*
* @param {String} type
* @return {Dialog} for chaining
* @api public
*/
Dialog.prototype.effect = function(type){
this._effect = type;
this.el.addClass(type);
return this;
};
/**
* Make it modal!
*
* @return {Dialog} for chaining
* @api public
*/
Dialog.prototype.modal = function(){
this._overlay = ui.overlay();
return this;
};
/**
* Add an overlay.
*
* @return {Dialog} for chaining
* @api public
*/
Dialog.prototype.overlay = function(){
var self = this;
var overlay = ui.overlay({ closable: true });
overlay.on('hide', function(){
self.closedOverlay = true;
self.hide();
});
overlay.on('close', function(){
self.emit('close');
});
this._overlay = overlay;
return this;
};
/**
* Close the dialog when the escape key is pressed.
*
* @api private
*/
Dialog.prototype.escapable = function(){
var self = this;
$(document).bind('keydown.dialog', function(e){
if (27 != e.which) return;
$(this).unbind('keydown.dialog');
self.emit('escape');
self.hide();
});
};
/**
* Show the dialog.
*
* Emits "show" event.
*
* @return {Dialog} for chaining
* @api public
*/
Dialog.prototype.show = function(){
var overlay = this._overlay;
this.emit('show');
if (overlay) {
overlay.show();
this.el.addClass('modal');
}
// escape
if (!overlay || overlay.closable) this.escapable();
this.el.appendTo('body');
this.el.css({ marginLeft: -(this.el.width() / 2) + 'px' });
this.emit('show');
return this;
};
/**
* Hide the dialog with optional delay of `ms`,
* otherwise the dialog is removed immediately.
*
* Emits "hide" event.
*
* @return {Number} ms
* @return {Dialog} for chaining
* @api public
*/
Dialog.prototype.hide = function(ms){
var self = this;
// prevent thrashing
this.hiding = true;
// duration
if (ms) {
setTimeout(function(){
self.hide();
}, ms);
return this;
}
// hide / remove
this.el.addClass('hide');
if (this._effect) {
setTimeout(function(){
self.remove();
}, 500);
} else {
self.remove();
}
// modal
if (this._overlay && !self.closedOverlay) this._overlay.hide();
return this;
};
/**
* Hide the dialog without potential animation.
*
* @return {Dialog} for chaining
* @api public
*/
Dialog.prototype.remove = function(){
this.emit('hide');
this.el.remove();
$(document).unbind('keydown.dialog');
return this;
};
})(ui, "<div id=\"dialog\" class=\"hide\">\n <div class=\"content\">\n <h1>Title</h1>\n <a href=\"#\" class=\"close\">×</a>\n <p>Message</p>\n </div>\n</div>");