/* Copyright 2013 Twitter, Inc. Licensed under The MIT License. http://opensource.org/licenses/MIT */
define(
['./registry'],
function(registry) {
'use strict';
// ==========================================
// Search object model
// ==========================================
function traverse(util, searchTerm, options) {
options = options || {};
var obj = options.obj || window;
var path = options.path || ((obj == window) ? 'window' : '');
var props = Object.keys(obj);
props.forEach(function(prop) {
if ((tests[util] || util)(searchTerm, obj, prop)) {
console.log([path, '.', prop].join(''), '->', ['(', typeof obj[prop], ')'].join(''), obj[prop]);
}
if (Object.prototype.toString.call(obj[prop]) == '[object Object]' && (obj[prop] != obj) && path.split('.').indexOf(prop) == -1) {
traverse(util, searchTerm, {obj: obj[prop], path: [path,prop].join('.')});
}
});
}
function search(util, expected, searchTerm, options) {
if (!expected || typeof searchTerm == expected) {
traverse(util, searchTerm, options);
} else {
console.error([searchTerm, 'must be', expected].join(' '));
}
}
var tests = {
'name': function(searchTerm, obj, prop) {return searchTerm == prop;},
'nameContains': function(searchTerm, obj, prop) {return prop.indexOf(searchTerm) > -1;},
'type': function(searchTerm, obj, prop) {return obj[prop] instanceof searchTerm;},
'value': function(searchTerm, obj, prop) {return obj[prop] === searchTerm;},
'valueCoerced': function(searchTerm, obj, prop) {return obj[prop] == searchTerm;}
};
function byName(searchTerm, options) {search('name', 'string', searchTerm, options);}
function byNameContains(searchTerm, options) {search('nameContains', 'string', searchTerm, options);}
function byType(searchTerm, options) {search('type', 'function', searchTerm, options);}
function byValue(searchTerm, options) {search('value', null, searchTerm, options);}
function byValueCoerced(searchTerm, options) {search('valueCoerced', null, searchTerm, options);}
function custom(fn, options) {traverse(fn, null, options);}
// ==========================================
// Event logging
// ==========================================
var ALL = 'all'; //no filter
//log nothing by default
var logFilter = {
eventNames: [],
actions: []
}
function filterEventLogsByAction(/*actions*/) {
var actions = [].slice.call(arguments);
logFilter.eventNames.length || (logFilter.eventNames = ALL);
logFilter.actions = actions.length ? actions : ALL;
saveLogFilter();
}
function filterEventLogsByName(/*eventNames*/) {
var eventNames = [].slice.call(arguments);
logFilter.actions.length || (logFilter.actions = ALL);
logFilter.eventNames = eventNames.length ? eventNames : ALL;
saveLogFilter();
}
function hideAllEventLogs() {
logFilter.actions = [];
logFilter.eventNames = [];
saveLogFilter();
}
function showAllEventLogs() {
logFilter.actions = ALL;
logFilter.eventNames = ALL;
saveLogFilter();
}
function saveLogFilter() {
try {
if (window.localStorage) {
localStorage.setItem('logFilter_eventNames', logFilter.eventNames);
localStorage.setItem('logFilter_actions', logFilter.actions);
}
} catch (ignored) {};
}
function retrieveLogFilter() {
var eventNames, actions;
try {
eventNames = (window.localStorage && localStorage.getItem('logFilter_eventNames'));
actions = (window.localStorage && localStorage.getItem('logFilter_actions'));
} catch (ignored) {
return;
}
eventNames && (logFilter.eventNames = eventNames);
actions && (logFilter.actions = actions);
// reconstitute arrays in place
Object.keys(logFilter).forEach(function(k) {
var thisProp = logFilter[k];
if (typeof thisProp == 'string' && thisProp !== ALL) {
logFilter[k] = thisProp ? thisProp.split(',') : [];
}
});
}
return {
enable: function(enable) {
this.enabled = !!enable;
if (enable && window.console) {
console.info('Booting in DEBUG mode');
console.info('You can configure event logging with DEBUG.events.logAll()/logNone()/logByName()/logByAction()');
}
retrieveLogFilter();
window.DEBUG = this;
},
registry: registry,
find: {
byName: byName,
byNameContains: byNameContains,
byType: byType,
byValue: byValue,
byValueCoerced: byValueCoerced,
custom: custom
},
events: {
logFilter: logFilter,
// Accepts any number of action args
// e.g. DEBUG.events.logByAction("on", "off")
logByAction: filterEventLogsByAction,
// Accepts any number of event name args (inc. regex or wildcards)
// e.g. DEBUG.events.logByName(/ui.*/, "*Thread*");
logByName: filterEventLogsByName,
logAll: showAllEventLogs,
logNone: hideAllEventLogs
}
};
}
);