Zepto is a minimalist JavaScript library for modern browsers with a largely jQuery-compatible API
Flexible callback list management for event handling and plugin development. The Callbacks system provides a powerful way to manage lists of callbacks with configurable behavior patterns.
Create callback lists with configurable options to control firing behavior.
/**
* Create a callback list with configurable options
* @param options - Configuration string (space-separated flags)
* @returns Callbacks object for managing callback lists
*/
$.Callbacks(options);Configuration Options:
once - Callbacks can only be fired oncememory - Remember previous fire arguments for new callbacksunique - Prevent duplicate callbacks from being addedstopOnFalse - Stop firing when a callback returns falseMethods for adding, removing, and controlling callbacks.
/**
* Add callback function(s) to the list
* @param callbacks - One or more callback functions
* @returns Callbacks object for chaining
*/
$.fn.add(...callbacks);
/**
* Remove callback function(s) from the list
* @param callbacks - One or more callback functions to remove
* @returns Callbacks object for chaining
*/
$.fn.remove(...callbacks);
/**
* Check if callback function exists in the list
* @param callback - Optional specific callback to check for
* @returns Boolean indicating presence of callback(s)
*/
$.fn.has(callback);
/**
* Remove all callbacks from the list
* @returns Callbacks object for chaining
*/
$.fn.empty();Methods for executing callbacks with different contexts and arguments.
/**
* Fire all callbacks with given arguments
* @param args - Arguments to pass to callbacks
* @returns Callbacks object for chaining
*/
$.fn.fire(...args);
/**
* Fire all callbacks with specific context and arguments
* @param context - Context (this) for callback execution
* @param args - Arguments array to pass to callbacks
* @returns Callbacks object for chaining
*/
$.fn.fireWith(context, args);
/**
* Check if callbacks have been fired at least once
* @returns Boolean indicating if fire() has been called
*/
$.fn.fired();Methods for controlling the state and behavior of the callback list.
/**
* Disable the callback list (no more firing)
* @returns Callbacks object for chaining
*/
$.fn.disable();
/**
* Check if the callback list is disabled
* @returns Boolean indicating disabled state
*/
$.fn.disabled();
/**
* Lock the callback list (no more callbacks can be added)
* @returns Callbacks object for chaining
*/
$.fn.lock();
/**
* Check if the callback list is locked
* @returns Boolean indicating locked state
*/
$.fn.locked();// Create a basic callback list
const callbacks = $.Callbacks();
// Define some callback functions
function logMessage(message) {
console.log('Log:', message);
}
function alertMessage(message) {
alert('Alert: ' + message);
}
function processMessage(message) {
return message.toUpperCase();
}
// Add callbacks to the list
callbacks.add(logMessage, alertMessage);
// Fire all callbacks
callbacks.fire('Hello World');
// Output: "Log: Hello World" and alert dialog
// Add more callbacks
callbacks.add(processMessage);
// Fire again
callbacks.fire('Another message');
// All three callbacks execute// Create callback list with memory
const memoryCallbacks = $.Callbacks('memory');
// Add initial callback and fire
memoryCallbacks.add((msg) => console.log('First:', msg));
memoryCallbacks.fire('Initial message');
// Add callback later - it immediately receives the last fired arguments
memoryCallbacks.add((msg) => console.log('Second:', msg));
// Immediately outputs: "Second: Initial message"
// Fire again - both callbacks execute
memoryCallbacks.fire('New message');
// Outputs: "First: New message" and "Second: New message"// Create callback list that fires only once
const onceCallbacks = $.Callbacks('once');
onceCallbacks.add(
() => console.log('First execution'),
() => console.log('Also first execution')
);
onceCallbacks.fire();
// Outputs both messages
onceCallbacks.fire();
// No output - callbacks already fired once
// Adding new callbacks after firing has no effect with 'once'
onceCallbacks.add(() => console.log('Will not execute'));
onceCallbacks.fire(); // Still no output// Create callback list that prevents duplicates
const uniqueCallbacks = $.Callbacks('unique');
function duplicateCallback() {
console.log('This will only be added once');
}
uniqueCallbacks.add(duplicateCallback);
uniqueCallbacks.add(duplicateCallback); // Ignored due to 'unique'
uniqueCallbacks.add(duplicateCallback); // Also ignored
uniqueCallbacks.fire();
// Only executes once despite multiple add() calls// Create callback list that stops when a callback returns false
const stoppableCallbacks = $.Callbacks('stopOnFalse');
stoppableCallbacks.add(
() => { console.log('First callback'); return true; },
() => { console.log('Second callback'); return false; },
() => { console.log('Third callback - will not execute'); return true; }
);
stoppableCallbacks.fire();
// Outputs: "First callback" and "Second callback"
// Third callback doesn't execute because second returned false// Combine multiple options
const advancedCallbacks = $.Callbacks('once memory unique stopOnFalse');
function validator1(data) {
console.log('Validating format...');
return data && data.length > 0;
}
function validator2(data) {
console.log('Validating content...');
return data && !data.includes('invalid');
}
function validator3(data) {
console.log('This runs only if previous validators pass');
return true;
}
// Add validators (unique prevents duplicates)
advancedCallbacks.add(validator1, validator2, validator3);
advancedCallbacks.add(validator1); // Ignored due to 'unique'
// Fire validation (once + memory + stopOnFalse)
const result = advancedCallbacks.fire('valid data');
console.log('All validators passed');
// Later callbacks added will receive memory of last fire
advancedCallbacks.add((data) => {
console.log('Late validator received:', data);
});// Using fireWith for specific context
const contextCallbacks = $.Callbacks();
function contextualCallback(message) {
console.log(`${this.name} says: ${message}`);
}
contextCallbacks.add(contextualCallback);
// Fire with specific context
const speaker1 = { name: 'Alice' };
const speaker2 = { name: 'Bob' };
contextCallbacks.fireWith(speaker1, ['Hello from Alice']);
// Output: "Alice says: Hello from Alice"
contextCallbacks.fireWith(speaker2, ['Hello from Bob']);
// Output: "Bob says: Hello from Bob"const stateCallbacks = $.Callbacks();
// Add callbacks
stateCallbacks.add(() => console.log('Callback 1'));
stateCallbacks.add(() => console.log('Callback 2'));
console.log('Has callbacks:', stateCallbacks.has()); // true
console.log('Fired:', stateCallbacks.fired()); // false
console.log('Disabled:', stateCallbacks.disabled()); // false
console.log('Locked:', stateCallbacks.locked()); // false
// Fire callbacks
stateCallbacks.fire();
console.log('Fired after fire():', stateCallbacks.fired()); // true
// Lock the list (no more adding)
stateCallbacks.lock();
console.log('Locked after lock():', stateCallbacks.locked()); // true
stateCallbacks.add(() => console.log('Will not be added')); // Ignored
stateCallbacks.fire(); // Still works
// Disable the list (no more firing)
stateCallbacks.disable();
console.log('Disabled after disable():', stateCallbacks.disabled()); // true
stateCallbacks.fire(); // Ignored - list is disabled// Simple event system using callbacks
function EventEmitter() {
this.events = {};
}
EventEmitter.prototype.on = function(event, callback) {
if (!this.events[event]) {
this.events[event] = $.Callbacks('memory unique');
}
this.events[event].add(callback);
return this;
};
EventEmitter.prototype.off = function(event, callback) {
if (this.events[event]) {
this.events[event].remove(callback);
}
return this;
};
EventEmitter.prototype.emit = function(event, ...args) {
if (this.events[event]) {
this.events[event].fire(...args);
}
return this;
};
// Usage
const emitter = new EventEmitter();
emitter.on('data', (data) => console.log('Received:', data));
emitter.emit('data', { value: 123 });// Plugin system with hooks
const PluginSystem = {
hooks: {},
addHook(hookName, callback, options = '') {
if (!this.hooks[hookName]) {
this.hooks[hookName] = $.Callbacks(options);
}
this.hooks[hookName].add(callback);
},
runHook(hookName, ...args) {
if (this.hooks[hookName]) {
return this.hooks[hookName].fire(...args);
}
},
removeHook(hookName, callback) {
if (this.hooks[hookName]) {
this.hooks[hookName].remove(callback);
}
}
};
// Plugins can register hooks
PluginSystem.addHook('beforeSave', (data) => {
console.log('Validating data before save');
return data.isValid;
}, 'stopOnFalse');
PluginSystem.addHook('afterSave', (result) => {
console.log('Data saved successfully');
});
// Application uses hooks
function saveData(data) {
// Run pre-save hooks
const canSave = PluginSystem.runHook('beforeSave', data);
if (canSave) {
// Simulate save
const result = { success: true, id: Date.now() };
// Run post-save hooks
PluginSystem.runHook('afterSave', result);
return result;
}
}