Caret/js/command.js

104 lines
3.1 KiB
JavaScript
Raw Permalink Normal View History

define([
2013-12-16 19:29:41 +00:00
"util/text!config/commands.json",
"util/dom2"
2013-12-16 19:29:41 +00:00
], function(list) {
try {
list = JSON.parse(list);
} catch (e) {
2013-12-16 22:28:25 +00:00
console.error(e);
list = [];
}
2013-08-22 06:35:47 +00:00
/*
The command module is the heart of Caret's loosely-coupled modules. It
serves as an event bus for inter-module communication, but it also listens
to the DOM for click/change events and makes it easy to bind page interactions
to command callbacks.
Command is usually called as if synchronous, but it does support asynchronous
operation--it will pass a callback in to any subscribers, but will also
immediately pass back the return value (if any) from the those subscribers.
2013-08-22 06:35:47 +00:00
*/
var commands = {};
//commands can pass a callback, although most don't respond that way
var fire = function(command, argument, callback) {
2013-08-22 06:35:47 +00:00
if (!commands[command]) return;
var args = [].slice.call(arguments, 1);
2013-12-17 01:35:02 +00:00
//technically, a function as `argument` is a callback...
if (typeof argument == "function") {
callback = argument;
}
var registry = commands[command].slice();
registry.forEach(function(entry) {
var result = entry.callback.apply(null, args);
//immediately call back if sync-style return value was provided
if (typeof result !== "undefined" || entry.sync) {
2013-12-17 01:35:02 +00:00
//console.info("Immediate return from " + name, result);
if (callback) callback.call(null, result);
}
});
2014-02-27 06:34:02 +00:00
};
2013-08-22 06:35:47 +00:00
var register = function(command, listener, sync) {
2013-08-22 06:35:47 +00:00
if (!commands[command]) {
commands[command] = [];
}
//we allow a sync flag to be set for operations that will definitely return
2013-08-22 06:35:47 +00:00
commands[command].push({
callback: listener,
sync: sync
2013-08-22 06:35:47 +00:00
});
2014-02-27 06:34:02 +00:00
};
2013-08-22 06:35:47 +00:00
//delegate for all elements that have a command attribute
document.body.on("click", function(e) {
2013-08-23 23:03:46 +00:00
//cancel on inputs, selectboxes
if (["input", "select"].indexOf(e.target.tagName.toLowerCase()) >= 0) return;
if (e.button != 0) return;
2013-08-22 06:35:47 +00:00
//delegate all items with a command attribute
if (e.target.hasAttribute("command")) {
var command = e.target.getAttribute("command");
var arg = e.target.getAttribute("argument");
fire(command, arg);
e.preventDefault();
2013-08-22 06:35:47 +00:00
}
});
2013-08-23 23:03:46 +00:00
document.body.on("change", function(e) {
if (e.target.hasAttribute("command")) {
var command = e.target.getAttribute("command");
var arg = e.target.value;
fire(command, arg);
}
});
//handle command events directly dispatched via DOM
document.body.on("caret-command", function(e) {
if (!e.detail || !e.detail.command) return;
fire(e.detail.command, e.detail.argument);
});
//register for post-startup and fire any commands that are pending
register("init:complete", function() {
if (window.launchCommands) {
window.launchCommands.forEach(function(bundle) {
fire(bundle.message.command, bundle.message.argument, bundle.sendResponse);
});
delete window.launchCommands;
}
});
2013-12-16 16:51:56 +00:00
var facade = {
2013-08-22 06:35:47 +00:00
fire: fire,
2013-12-16 16:51:56 +00:00
on: register,
list: list
2013-08-22 06:35:47 +00:00
};
2013-12-16 16:51:56 +00:00
return facade;
2013-08-22 06:35:47 +00:00
});