1 /** 2 * This is the web browser implementation of `debug()`. 3 * 4 * Expose `debug()` as the module. 5 */ 6 7 exports = module.exports = require('./debug'); 8 exports.log = log; 9 exports.formatArgs = formatArgs; 10 exports.save = save; 11 exports.load = load; 12 exports.useColors = useColors; 13 exports.storage = 'undefined' != typeof chrome 14 && 'undefined' != typeof chrome.storage 15 ? chrome.storage.local 16 : localstorage(); 17 18 /** 19 * Colors. 20 */ 21 22 exports.colors = [ 23 '#0000CC', '#0000FF', '#0033CC', '#0033FF', '#0066CC', '#0066FF', '#0099CC', 24 '#0099FF', '#00CC00', '#00CC33', '#00CC66', '#00CC99', '#00CCCC', '#00CCFF', 25 '#3300CC', '#3300FF', '#3333CC', '#3333FF', '#3366CC', '#3366FF', '#3399CC', 26 '#3399FF', '#33CC00', '#33CC33', '#33CC66', '#33CC99', '#33CCCC', '#33CCFF', 27 '#6600CC', '#6600FF', '#6633CC', '#6633FF', '#66CC00', '#66CC33', '#9900CC', 28 '#9900FF', '#9933CC', '#9933FF', '#99CC00', '#99CC33', '#CC0000', '#CC0033', 29 '#CC0066', '#CC0099', '#CC00CC', '#CC00FF', '#CC3300', '#CC3333', '#CC3366', 30 '#CC3399', '#CC33CC', '#CC33FF', '#CC6600', '#CC6633', '#CC9900', '#CC9933', 31 '#CCCC00', '#CCCC33', '#FF0000', '#FF0033', '#FF0066', '#FF0099', '#FF00CC', 32 '#FF00FF', '#FF3300', '#FF3333', '#FF3366', '#FF3399', '#FF33CC', '#FF33FF', 33 '#FF6600', '#FF6633', '#FF9900', '#FF9933', '#FFCC00', '#FFCC33' 34 ]; 35 36 /** 37 * Currently only WebKit-based Web Inspectors, Firefox >= v31, 38 * and the Firebug extension (any Firefox version) are known 39 * to support "%c" CSS customizations. 40 * 41 * TODO: add a `localStorage` variable to explicitly enable/disable colors 42 */ 43 44 function useColors() { 45 // NB: In an Electron preload script, document will be defined but not fully 46 // initialized. Since we know we're in Chrome, we'll just detect this case 47 // explicitly 48 if (typeof window !== 'undefined' && window.process && window.process.type === 'renderer') { 49 return true; 50 } 51 52 // Internet Explorer and Edge do not support colors. 53 if (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/)) { 54 return false; 55 } 56 57 // is webkit? http://stackoverflow.com/a/16459606/376773 58 // document is undefined in react-native: https://github.com/facebook/react-native/pull/1632 59 return (typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance) || 60 // is firebug? http://stackoverflow.com/a/398120/376773 61 (typeof window !== 'undefined' && window.console && (window.console.firebug || (window.console.exception && window.console.table))) || 62 // is firefox >= v31? 63 // https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages 64 (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31) || 65 // double check webkit in userAgent just in case we are in a worker 66 (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)); 67 } 68 69 /** 70 * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default. 71 */ 72 73 exports.formatters.j = function(v) { 74 try { 75 return JSON.stringify(v); 76 } catch (err) { 77 return '[UnexpectedJSONParseError]: ' + err.message; 78 } 79 }; 80 81 82 /** 83 * Colorize log arguments if enabled. 84 * 85 * @api public 86 */ 87 88 function formatArgs(args) { 89 var useColors = this.useColors; 90 91 args[0] = (useColors ? '%c' : '') 92 + this.namespace 93 + (useColors ? ' %c' : ' ') 94 + args[0] 95 + (useColors ? '%c ' : ' ') 96 + '+' + exports.humanize(this.diff); 97 98 if (!useColors) return; 99 100 var c = 'color: ' + this.color; 101 args.splice(1, 0, c, 'color: inherit') 102 103 // the final "%c" is somewhat tricky, because there could be other 104 // arguments passed either before or after the %c, so we need to 105 // figure out the correct index to insert the CSS into 106 var index = 0; 107 var lastC = 0; 108 args[0].replace(/%[a-zA-Z%]/g, function(match) { 109 if ('%%' === match) return; 110 index++; 111 if ('%c' === match) { 112 // we only are interested in the *last* %c 113 // (the user may have provided their own) 114 lastC = index; 115 } 116 }); 117 118 args.splice(lastC, 0, c); 119 } 120 121 /** 122 * Invokes `console.log()` when available. 123 * No-op when `console.log` is not a "function". 124 * 125 * @api public 126 */ 127 128 function log() { 129 // this hackery is required for IE8/9, where 130 // the `console.log` function doesn't have 'apply' 131 return 'object' === typeof console 132 && console.log 133 && Function.prototype.apply.call(console.log, console, arguments); 134 } 135 136 /** 137 * Save `namespaces`. 138 * 139 * @param {String} namespaces 140 * @api private 141 */ 142 143 function save(namespaces) { 144 try { 145 if (null == namespaces) { 146 exports.storage.removeItem('debug'); 147 } else { 148 exports.storage.debug = namespaces; 149 } 150 } catch(e) {} 151 } 152 153 /** 154 * Load `namespaces`. 155 * 156 * @return {String} returns the previously persisted debug modes 157 * @api private 158 */ 159 160 function load() { 161 var r; 162 try { 163 r = exports.storage.debug; 164 } catch(e) {} 165 166 // If debug isn't set in LS, and we're in Electron, try to load $DEBUG 167 if (!r && typeof process !== 'undefined' && 'env' in process) { 168 r = process.env.DEBUG; 169 } 170 171 return r; 172 } 173 174 /** 175 * Enable namespaces listed in `localStorage.debug` initially. 176 */ 177 178 exports.enable(load()); 179 180 /** 181 * Localstorage attempts to return the localstorage. 182 * 183 * This is necessary because safari throws 184 * when a user disables cookies/localstorage 185 * and you attempt to access it. 186 * 187 * @return {LocalStorage} 188 * @api private 189 */ 190 191 function localstorage() { 192 try { 193 return window.localStorage; 194 } catch (e) {} 195 } 196