/**
* @name CeL log function
* @fileoverview
* 本檔案包含了記錄用 functions。
*
* @since 2009/11/17
* @see
* Firebug Lite,
* Venkman JavaScript Debugger project page
*/
// http://blogs.msdn.com/b/webdevtools/archive/2007/03/02/jscript-intellisense-in-orcas.aspx
///
TODO:
https://developers.google.com/web/tools/chrome-devtools/console/console-write#styling_console_output_with_css
console.log("%c", 將 CSS 樣式規則應用到第二個參數指定的輸出字符串)
emergency/urgent situation alert
會盡量以網頁上方/頂部黄色的導航條/警告條展示
「不再顯示」功能
.format()
將 div format 成 log panel。
分群, http://developer.yahoo.com/yui/examples/uploader/uploader-simple-button.html
*/
/**
*
to include:
include code_for_including
var SL = new Debug.log('debug_panel'), sl = function() { SL.log.apply(SL, arguments); }, error = function() { SL.error.apply(SL, arguments); }, warn = function() { SL.warn.apply(SL, arguments); };
http://www.comsharp.com/GetKnowledge/zh-CN/TeamBlogTimothyPage_K742.aspx
if possible, use Firebug Lite instead.
http://benalman.com/projects/javascript-debug-console-log/
*/
'use strict';
// --------------------------------------------------------------------------------------------
// 不採用 if 陳述式,可以避免 Eclipse JSDoc 與 format 多縮排一層。
typeof CeL === 'function' && CeL.run({
// module name
name : 'application.debug.log',
// Object.is()
require : 'data.code.compatibility.',
// 設定不匯出的子函式。
no_extend : 'this,do_log,extend',
// 為了方便格式化程式碼,因此將 module 函式主體另外抽出。
code : module_code,
finish : finish
});
function module_code(library_namespace) {
// WScript.Echo(this);
var
// class private -----------------------------------
// class name, 需要用到這個都不是好方法。
// cn = 'Debug.log',
/**
* private storage pool
*
* @ignore
*/
p = [],
//
has_performance_now,
//
log_data = function(message, options) {
// 由於 .set_method() 會用到 .debug(),
// 若在 log 的 core 中用上 .set_method() 會循環呼叫,造成 stack overflow。
// ** NG: library_namespace.set_method(this, options);
if (library_namespace.is_Object(options))
Object.assign(this, options);
this.date = new Date();
if (has_performance_now)
this.time = performance.now();
this.message = message;
return this;
},
/**
* default write/show log function
*
* @ignore
* @param {string}id
* element id
*/
write_log = function(id) {
// console.log(id);
var o, m, c, _p = p[id], _t = _p.instance,
/**
* buffer
*
* @inner
* @ignore
*/
b = _p.buf, B = _p.board, F = _p.do_function, level;
if (_p.clean)
_t.clear(), _p.clean = 0;
if (!B && !F)
return;
while (b.length) {
// 預防 multi-threading 時重複顯示。
m = b.shift();
if (F)
F(m);
// IE8: 'constructor' 是 null 或不是一個物件
try {
c = m.constructor;
if (false)
alert((m.constructor === log_data) + '\n' + m.constructor
+ '\n' + m);
} catch (e) {
}
if (c === log_data) {
if (!isNaN(m.level) && m.level < library_namespace.set_debug())
continue;
c = m.level in _t.className_set ? m.level : 0;
o = m.add_class;
// 添加各種標記。
m = [ _t.message_prefix(c), _t.show_time(m.date, m.time),
m.message ];
c = _t.className_set[c];
if (o)
c += ' ' + o;
} else {
// add default style set
if (c = _t.message_prefix('log'))
m = [ c, m ];
c = _t.className_set.log || 0;
}
_p.lbuf.push(m);
if (B
// && typeof document === 'object'
) {
o = _p.instance.log_tag;
if (o) {
o = document.createElement(o);
if (c)
o.className = c;
new_node(m, o);
} else {
o = document.createTextNode(m);
}
// TODO: pause
B.appendChild(o);
while (B.childNodes.length > _p.max_logs) {
B.removeChild(B.firstChild);
}
}
}
if (false) {
if (_t.auto_hide)
B.style.display = B.innerHTML ? 'block' : 'none';
}
// TODO: 有時無法捲到最新。
if (B && _t.auto_scroll)
B.scrollTop = B.scrollHeight - B.clientHeight;
},
/**
* save log.
*
* @ignore
* @param m
* message
* @param {string}
* id element id
* @param force
* force to clean the message area
*/
do_save_log = function(m, id, force) {
// console.log(m);
var _p = p[id], _t = _p.instance,
// log file handler
f = _p.logF, s = _t.save_log;
if (!s || typeof s === 'function' && !s(m, l))
return;
if (m)
_p.sbuf
.push(m = (_t.save_date && typeof gDate === 'function' ? _t.save_line_separator
+ gDate() + _t.save_line_separator
: '')
+ m);
if (force || _t.flush || _p.sbufL > _t.save_limit)
try {
if (f
|| _t.log_file
&& (f = _p.logF = fso.OpenTextFile(_t.log_file,
/* ForAppending */8, /* create */true,
_t.log_encoding)))
f.Write(_p.sbuf.join(_t.save_line_separator)),
_p.sbuf = [], _p.sbufL = 0, _t.error_message = 0;
} catch (e) {
// error(e);
_t.error_message = e;
}
else if (m)
_p.sbufL += m.length;
},
using_DOM_new_node = false,
// 使 log 能用到 new_node 的功能。
// @see function_placeholder() @ module.js
new_node = function(o, layer) {
// console.log(o);
if (library_namespace.is_Function(library_namespace.new_node)) {
// alert('開始利用 library 之 new_node。');
using_DOM_new_node = true;
return (new_node = library_namespace.new_node)(o, layer);
}
var list = [];
// workaround: 簡易版 new_node().
(function add(o) {
var node, tag, child;
if (Array.isArray(o))
for (node = 0; node < o.length; node++)
add(o[node]);
else if (library_namespace.is_Object(o)) {
if (o.$) {
tag = o.$;
list.push('<' + tag);
delete o.$;
}
for (node in o) {
if (tag)
list.push(' ' + node + '="'
+ ('' + o[node]).replace(/"/g, '"') + '"');
else {
tag = node;
list.push('<' + tag);
child = o[node] || null;
}
}
if (child === null)
list.push(' />');
else {
list.push('>');
add(child);
list.push('' + tag + '>');
}
} else
list.push(o);
})(o);
layer.innerHTML = list.join('');
return using_DOM_new_node;
},
show_date = function(date) {
var h = date.getHours(), m = date.getMinutes(), s = date.getSeconds(), ms = date
.getMilliseconds();
return (h || m || s ? (h || m ? (h ? h + ':' : '') + m + ':' : '') + s
: '')
+ '.' + (ms > 99 ? '' : ms > 9 ? '0' : '00') + ms;
},
has_caller,
// instance constructor ---------------------------
// (document object)
/**
*
_ = this
TODO:
set class in each input
input array
show file path & directory functional 可從 FSO operation.hta 移植。
count
c.f.: GLog
dependency:
*/
/**
* initial a log tool's instance/object
*
* @class log function
* @_see usage: _module_.extend
* @since 2008/8/20 23:9:48
* @requires gDate(),line_separator,fso
*
* @constructor
* @_name _module_
* @param {String|object
* HTMLElement} obj log target: message area element or id
* @param {Object}
* [className_set] class name set
*/
_// JSDT:_tmp;_module_
= function(obj, className_set) {
// Initial instance object. You can set it yourself.
/**
* log 時 warning/error message 之 className
*
* @_name _module_.prototype.className_set
*/
this.className_set = className_set || {
/**
* @_description 當呼叫 {@link _module_.prototype.log} 時使用的 className,
* DEFAULT className.
* @_name _module_.prototype.className_set.log
*/
log : 'debug_log',
/**
* @_description 當呼叫 {@link _module_.prototype.warn} 時使用的 className
* @_name _module_.prototype.className_set.warn
*/
warn : 'debug_warn',
/**
* @_description 當呼叫 {@link _module_.prototype.error} 時使用的 className
* @_name _module_.prototype.className_set.error
*/
error : 'debug_error',
/**
* @_description 當顯示時間時使用的 className
* @_name _module_.prototype.className_set.time
*/
time : 'debug_time',
/**
* @_description 當呼叫 {@link _module_.prototype.set_board} 時設定 log
* panel 使用的 className
* @_name _module_.prototype.className_set.panel
*/
panel : 'debug_panel'
};
this.class_hide = {};
var prefix = {
/**
* @_description 當呼叫 {@link _module_.prototype.log} 時使用的 prefix,
* DEFAULT prefix.
* @_name _module_.prototype.message_prefix.log
*/
log : '',
/**
* @_description 當呼叫 {@link _module_.prototype.warn} 時使用的 prefix
* @_name _module_.prototype.message_prefix.warn
*/
warn : '',
/**
* @_description 表示當呼叫 {@link _module_.prototype.error}, 是錯誤 error
* message 時使用的 prefix
* @_name _module_.prototype.message_prefix.error
*/
error : '!! Error !! '
};
/**
* log 時 warning/error message 之 prefix。
*
* @_name _module_.prototype.message_prefix
*/
this.message_prefix = function(level) {
return level in prefix ? prefix[level] : '';
};
this.id = p.length;
p.push({
instance : this,
/** write buffer */
buf : [],
/** save buffer when we need to save the messages */
sbuf : [],
/** length of save buffer */
sbufL : 0,
/** now logged buffer */
lbuf : []
});
this.set_board(obj);
};
try {
has_performance_now = performance.now() > 0;
} catch (e) {
}
try {
has_caller = function(a) {
'use strict';
return arguments.callee.caller !== undefined;
};
has_caller = (function() {
return has_caller();
})();
} catch (e) {
has_caller = false;
}
// class public interface ---------------------------
_// JSDT:_module_
.
/**
* do the log action
*
* @_memberOf _module_
* @private
*/
do_log = function(id) {
/**
*
這段應該只在 module namespace 重複定義時才會發生
var I = p[id];
if (!I) {
alert('.do_log: not exist: [' + id + ']');
return;
}
I = I.instance;
*/
var I = p[id].instance;
if (I.do_log)
I.do_log();
};
_// JSDT:_module_
.
/**
* 對各種不同 error object 作應對,獲得可理解的 error message。
*
* @param e
* error object
* @param line_separator
* line separator
* @param caller
* function caller
* @_memberOf _module_
* @see http://msdn.microsoft.com/en-us/library/ms976144.aspx The facility
* code establishes who originated the error. For example, all internal
* script engine errors generated by the JScript engine have a facility
* code of "A".
* http://msdn.microsoft.com/en-us/library/ms690088(VS.85).aspx
* @see http://msdn.microsoft.com/en-us/library/t9zk6eay.aspx
* http://msdn.microsoft.com/en-us/library/microsoft.jscript.errorobject.aspx
* Specifies the name of the type of the error. Possible values include
* Error, EvalError, RangeError, ReferenceError, SyntaxError,
* TypeError, and URIError.
*/
get_error_message = function get_error_message(e, line_separator, caller) {
if (!line_separator)
line_separator = _.prototype.save_line_separator;
if (!caller || typeof caller !== 'string') {
if (typeof caller !== 'function' && has_caller)
caller = get_error_message.caller;
if (caller === null)
caller = 'from the top level';
else if (typeof caller === 'function')
caller = '@'
+ (library_namespace.get_function_name(caller) || caller);
else
caller = '@' + library_namespace.Class;
}
// from popErr()
// type
var T = library_namespace.is_type(e),
// message
m = T === 'Error' ? 'Error '
+ caller
+ ': '
/**
*
http://msdn.microsoft.com/en-us/library/cc231198(PROT.10).aspx
Winerror.h: error code definitions for the Win32 API functions
(e.number & 0xFFFF): See 錯誤代碼 /錯誤提示碼 System Error Codes
http://social.msdn.microsoft.com/Search/zh-TW/?Query=%22System+Error+Codes%22+740&AddEnglish=1
http://msdn.microsoft.com/en-us/library/aa394559(VS.85).aspx
net helpmsg (e.number & 0xFFFF)
*/
+ (e.number & 0xFFFF)
+ (e.name ? ' [' + e.name + '] ' : ' ')
+ '(facility code '
+ (e.number >> 16 & 0x1FFF)
+ '): '
+ line_separator
+ (e.message || '').replace(/\r?\n/g, '
')
// .message 為主,.description 是舊的。
+ (!e.description || e.description === e.message ? ''
: line_separator
+ line_separator
+ ('' + e.description).replace(/\r?\n/g,
'
'))
: T === 'DOMException' ?
// http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-17189187
'[' + T + '] ' + e.code + ': ' + e.message
//
: !e || T === 'string' ? e
//
: '[' + T + '] ' + (e.message || e);
if (library_namespace.is_debug(2) && typeof e === 'object' && e)
for (T in e)
try {
// Firefox has (new Error).stack
// http://eriwen.com/javascript/js-stack-trace/
m += '
'
+ T
+ ': '
+ (typeof e[T] === 'string' && T === 'stack' ? e[T]
.replace(/[\r\n]+$/, '')
.replace(/(@)([a-z\-]+:\/\/.+)(:)(\d+)$/gm,
'$1$2$3$4')
.replace(/\n/g, '
- ')
: typeof e[T] === 'string'
&& T === 'fileName' ? ''
+ e[T] + ''
: e[T]);
} catch (e) {
// TODO: handle exception
}
// m += ' (' + arguments.callee.caller + ')';
return m;
};
_// JSDT:_module_
.
/**
* get node description
*
* @param node
* HTML node
* @_memberOf _module_
*/
node_description = function(node, flag) {
// console.log(node);
if (typeof node === 'string')
node = document.getElementById(node);
if (!node)
return;
var description = '';
if (node.id)
description += '#' + node.id;
if (node.className)
description += '.' + node.className;
if (node.tagName)
description = '<' + node.tagName + description + '>';
if (!description && node.innerHTML) {
description = node.innerHTML;
if (description.length > 40)
description = description.slice(0, 40);
description = description.replace(/
// status logger
var SL = new _module_('log'), sl = SL[1], warn = SL[2], error = SL[3];
sl(msg);
sl(msg, clear);
// general log
function_set = new _module_.extend('panel', {});
// 1.
function_set = new CeL.code.log.extend('panel', {});
logger = function_set[1];
// 2.
log_only = (new CeL.code.log.extend('panel', {}))[1];
* @_memberOf _module_
* @since 2009/8/24 20:15:31
*/
extend = function(obj, className_set) {
if (false) {
CeL.Log = new CeL.code.log(
function(m) {
var F = typeof JSalert === 'function' ? JSalert
: typeof alert === 'function' ? alert
: WScript.Echo;
F(typeof m === 'object' ? '[' + m.level + '] '
+ m.message : m);
});
}
/**
* new instance
*
* @_type _module_
* @inner
* @ignore
*/
var log_controller = new _// JSDT:_module_
(obj || _.default_log_target, className_set);
// TODO: do not use arguments
return [ log_controller, function() {
// console.log(arguments);
log_controller.log.apply(log_controller, arguments);
}, function() {
log_controller.warn.apply(log_controller, arguments);
}, function() {
log_controller.error.apply(log_controller, arguments);
} ];
};
/**
*
_.option_open=function(p){
};
_.option_file=function(p){
};
_.option_folder=function(p){
};
*/
// class constructor ---------------------------
_// JSDT:_module_
.prototype = {
// instance public interface -------------------
/**
* 當執行寫檔案或任何錯誤發生時之錯誤訊息。
* while error occurred.. should read only
*
* @_name _module_.prototype.error_message
*/
error_message : '',
/**
* 超過這長度才 save。<=0 表示 autoflash,非數字則不紀錄。
*
* @_name _module_.prototype.save_limit
* @type Number
*/
save_limit : 4000,
/**
* 在 log 結束時執行,相當於 VB 中 DoEvent() 或 。
*
* @_name _module_.prototype.do_event
*/
do_event : library_namespace.DoNoting || null,
/**
* log 時使用之 tagName, 可用 div / span 等。若不設定會用 document.createTextNode
*
* @_name _module_.prototype.log_tag
*/
log_tag : 'div',
/**
* boolean or function(message, log level) return save or not
*
* @_name _module_.prototype.save_log
* @type Boolean
*/
save_log : false,
/**
* save log to this file path
*
* @_name _module_.prototype.log_file
* @type Boolean
*/
log_file : false,
/**
* auto save log. 若未設定,記得在 onunload 時 .save()
*
* @_name _module_.prototype.flush
* @type Boolean
*/
flush : false,
/**
* 在 save log 時 add date
*
* @_name _module_.prototype.save_date
* @type Boolean
*/
save_date : true,
/**
* 在 save log 時的換行
*
* @_name _module_.prototype.save_line_separator
* @type string
*/
save_line_separator : library_namespace.env.line_separator || '\r\n',
/**
* 在 save log 時的 encoding
*
* @_name _module_.prototype.log_encoding
*/
log_encoding : -1,// -1: TristateTrue
/**
* 自動捲動
*
* @_name _module_.prototype.auto_scroll
* @type Boolean
*/
auto_scroll : true,
/**
* 沒有內容時自動隱藏
*
* @deprecated TODO
* @_name _module_.prototype.auto_hide
* @type Boolean
*/
auto_hide : false,
/**
* 等待多久才顯示 log。若為 0 則直接顯示。
* e.g., 即時顯示,不延遲顯示: CeL.Log.interval = 0;
* (WScript 沒有 setTimeout)
*
* @_name _module_.prototype.interval
*/
interval : typeof setTimeout === 'undefined' ? 0 : 1,
/**
* log function (no delay)
*
* @_name _module_.prototype.do_log
*/
do_log : function(level) {
if (false)
if (p[this.id].th)
clearTimeout(p[this.id].th);
// reset timeout handler
p[this.id].th = 0;
// TODO: 提升效率.
if ('controller' in this)
this.set_controller();
write_log(this.id);
},
/**
* class instance 預設作 log 之 function
*
* @param {String}
* message message
* @param {Boolean}clean
* clean message area
* @param {Object}options
* 選擇性項目. { level : log level, 記錄複雜度. }
* @return
* @_name _module_.prototype.log
*/
log : function(message, clean, options) {
// console.log(message);
var t = this, _p = p[t.id], level, force_save;
if (library_namespace.is_Object(options)) {
level = options.level;
force_save = options.save;
} else if (options) {
force_save = level = options;
(options = {}).level = level;
}
/**
*
var message_head = (arguments.callee.caller + '')
.match(/function\do_save_log([^\(]+)/);
if (message_head)
message_head = message_head[1] + ' ';
*/
do_save_log(message, t.id, force_save);
// window.status = message;
if (options) {
message = new log_data(message, options);
}
if (clean) {
// clean log next time
_p.clean = 1, _p.buf = [ message ];
} else {
_p.buf.push(message);
}
if (!(t.interval > 0))
t.do_log();
else if (!_p.th)
// no window.setTimeout @ node.js
if (typeof setTimeout === 'undefined')
t.interval = 0, t.do_log();
else
// _p.th = setTimeout(cn + '.do_log(' + t.id + ');',
// t.interval);
_p.th = setTimeout(function() {
_.do_log(t.id);
}, t.interval);
if (t.do_event)
t.do_event();
},
/*
* TODO: other methods: INFO,DEBUG,WARNING,ERROR,FATAL,UNKNOWN
*/
/**
* save message
*
* @_name _module_.prototype.save
*/
save : function() {
do_save_log('', this.id, 1/* force */);
},
/**
*
** important ** 這邊不能作 object 之 initialization,否則因為 object 只會 copy reference,因此 new 時東西會一樣。initialization 得在 _() 中作!
*/
// className_set : {},
/**
* log a warning / caution / alert / 警告.
*
* @_name _module_.prototype.warn
*/
warn : function(m, clean) {
this.log(m, clean, 'warn');
},
/**
* deal with error message
*
* @_name _module_.prototype.error
*/
error : function error(e, clean) {
var caller = '';
if (has_caller) {
caller = '' + error.caller;
if (caller.indexOf('.error.apply(') !== -1)
// ** 判斷 call from _.extend. TODO: 應該避免!
caller = caller.caller;
}
this.log(Array.isArray(e) || library_namespace.is_Object(e) ? e : _
.get_error_message(e, this.save_line_separator, caller),
clean, 'error');
},
timezone_offset : /* msPerMinute */60000 * (new Date)
.getTimezoneOffset(),
/**
* 在 log 中依照格式顯示時間。
*
* @param {Date}date
* @returns {String} 依照格式顯示成之時間。
* @_name _module_.prototype.show_time
* @since 2012/3/16 22:36:46
*/
show_time : function show_time(date, time) {
var add_s, _diff_ms,
//
date_stamp = (date.getMonth() + 1) + '/' + date.getDate() + ' '
+ show_date(date),
//
diff_ms = has_performance_now && this.last_show ? time
- this.last_show : (_diff_ms = date
- (this.last_show || this.timezone_offset));
if (diff_ms > 0)
if (diff_ms < 60000) {
add_s = diff_ms >= 1000 && (diff_ms /= 1000);
diff_ms = diff_ms.to_fixed ? String(diff_ms.to_fixed(3))
.replace(/^0/, '')
// : diff_ms.toFixed ? diff_ms.toFixed(3)
: (diff_ms | 0);
if (add_s)
diff_ms += 's';
} else
diff_ms = show_date(new Date(diff_ms + this.timezone_offset));
this.last_show = has_performance_now ? time : date;
// 不用 CSS.quotes: 在舊版 browser 上可能無效,但本 module 須在舊版上亦正常作動。
return '['
+ diff_ms + '] ';
},
/**
* 當記錄太長時,限制記錄數目在 max_logs。超過這個數目就會把之前的最舊的紀錄消除掉。
*
* @param {Natural}max_logs
* 最大記錄數目
*/
set_max_logs : function(max_logs) {
var _t = this, _p = p[_t.id];
max_logs = Math.floor(max_logs);
// accept NaN
_p.max_logs = max_logs < 0 ? 0 : max_logs;
},
/**
* 設定寫入到哪
* set log board for each instance (document object)
*
* @_name _module_.prototype.set_board
*/
set_board : function(o) {
var _t = this, _p = p[_t.id];
if (o)
if (typeof o === 'function')
_p.do_function = o;
else {
if (typeof o !== 'object' && typeof document === 'object')
o = document.getElementById(o);
if (o
// TODO
// && library_namespace.is_HTML_obj(o)
) {
_p.board = o;
_t.set_controller();
if (_t = _t.className_set.panel)
o.className += ' ' + _t;
delete _p.do_function;
}
}
return _p.board;
},
// TODO: 若之後才 include 'interact.DOM',則 controller 沒辦法顯示出來 @ Chrome/25。
set_controller : function(c) {
var b = p[this.id].board;
if (b && (c || (c = this.controller))
&& (c = new_node(c, [ b, 0 ])) !== using_DOM_new_node) {
if ('controller' in this)
delete this.controller;
// c.style.height = '1em';
// c.style.height = '';
}
},
/**
* 獲取當前 buffer 中的 log。
*
* @_name _module_.prototype.get_log
*/
get_log : function() {
return p[this.id].lbuf;
},
/**
* show/hide log board. 切換可見狀態。
*
* @_name _module_.prototype.toggle
*/
toggle : function(s) {
return library_namespace.toggle_display(p[this.id].board, s) !== 'none';
},
/**
* clear log board. TODO: use .remove_all_child().
*
* @_name _module_.prototype.clear_board
*/
clear_board : function(b) {
b.innerHTML = '';
},
/**
* 清除全部訊息 clear message
*
* @_name _module_.prototype.clear
*/
clear : function() {
var _p = p[this.id];
if (_p.board) {
this.clear_board(_p.board);
}
_p.lbuf = [];
}
};
return (_// JSDT:_module_
);
}
// ----------------------------------------------------------------------------------------------------------------------------------------------------------//
function finish(name_space) {
// 為 module log 所作的初始化工作。
var module_name = this.id;
// 確認 cssRules 之後才作 delete,否則就得按順序先增者後減。因為刪掉 [2] 之後,後面全部皆會遞補,[3] 會變成 [2]。
// TODO: 一般化。
function search_CSS_rule(style_sheet, selector) {
var rules = style_sheet.cssRules || style_sheet.rules, i = 0, l = rules.length;
for (; i < l; i++)
if (selector === rules[i].selectorText)
return i;
}
// WScript.Echo(n.extend);
if (false)
code_for_including[generateCode.dLK] = '*var Debug={log:code_for_including()};';
// include resources of module.
CeL.run(CeL.get_module_path(module_name, 'log.css'));
// 為本 library 用
if (!CeL.Log) {
var i, l, log_controller = name_space.extend(), has_caller,
// 偵錯等級, debug level, log level.
log_icon = {
/**
* MEMO (U+1F4DD).
* http://codepoints.net/U+1F4DD http://wiki.livedoor.jp/qvarie/
*/
log : '📝',
/**
* emphasized text
* U+2383 EMPHASIS SYMBOL
* http://codepoints.net/U+2383
*/
em : '⎃',
/**
* 資訊,消息,報告,通知,情報
* WARNING SIGN (U+26A0) @ Miscellaneous Symbols.
*/
warn : '⚠',
/**
* error / fault
* U+2620 SKULL AND CROSSBONES
*/
error : '☠',
/**
* U+2139 INFORMATION SOURCE
* http://en.wiktionary.org/wiki/%E2%84%B9
*/
info : 'ℹ',
/**
* U+1F41B BUG
*/
debug : '🐛',
/**
* U+1F463 footprints
* https://unicode.org/emoji/charts/full-emoji-list.html
*/
trace : '👣'
},
// base path of icon
icon_path = CeL.get_module_path(module_name, 'icon/');
try {
has_caller = function(a) {
'use strict';
return arguments.callee.caller !== undefined;
};
has_caller = (function() {
return has_caller();
})();
} catch (e) {
has_caller = false;
}
// console.log('override: CeL.Log = ' + log_controller[0]);
CeL.Log = log_controller[0];
// console.log('setup CeL.Log.className_set');
Object.assign(CeL.Log.className_set, {
info : 'debug_info',
em : 'debug_em',
debug : 'debug_debug'
});
// log 支援 gettext.
CeL.Log.message_prefix = function(level) {
if (level in log_icon) {
return {
img : null,
'class' : 'debug_icon',
src : icon_path + level + '.png',
alt : '[' + log_icon[level] + ']',
title : log_icon[level] + ' '
// gettext_config:{"id":"log-type-fatal","mark_type":"combination_message_id"}
// gettext_config:{"id":"log-type-error","mark_type":"combination_message_id"}
// gettext_config:{"id":"log-type-warn","mark_type":"combination_message_id"}
// gettext_config:{"id":"log-type-em","mark_type":"combination_message_id"}
// gettext_config:{"id":"log-type-info","mark_type":"combination_message_id"}
// gettext_config:{"id":"log-type-log","mark_type":"combination_message_id"}
// gettext_config:{"id":"log-type-debug","mark_type":"combination_message_id"}
// gettext_config:{"id":"log-type-trace","mark_type":"combination_message_id"}
+ CeL.gettext('log-type-' + level)
};
}
return '';
};
// TODO: copy result, paste code.
var controller = [ ':', {
// U+239A CLEAR SCREEN SYMBOL
a : '⎚',
href : '#',
title : "clear / 清除所有訊息",
onclick : function() {
CeL.Log.clear();
return false;
}
}, {
// toggle / switch
// U+1F50C ELECTRIC PLUG
a : '🔌',
href : '#',
title : "切換訊息面板\nshow/hidden log panel",
onclick : function() {
CeL.set_class(this, 'debug_hide', {
remove : CeL.Log.toggle()
});
return false;
}
}, {
span : '↑',
title : "提升偵錯等級",
S : 'cursor:pointer;font-size:.7em;',
onselect : function() {
return false;
},
onclick : function() {
CeL.set_debug(CeL.is_debug() + 1);
CeL.debug('提升偵錯等級至 ' + CeL.is_debug(), 1, 'Log.controller');
return false;
}
}, {
span : '↓',
title : "降低偵錯等級",
S : 'cursor:pointer;font-size:.7em;',
onselect : function() {
return false;
},
onclick : function() {
CeL.set_debug(CeL.is_debug() - 1);
CeL.debug('降低偵錯等級至 ' + CeL.is_debug(), 0, 'Log.controller');
return false;
}
}, {
span : '↓',
title : "取消 debug",
S : 'cursor:pointer;font-size:.7em;text-decoration:underline;',
onselect : function() {
return false;
},
onclick : function() {
CeL.set_debug(0);
return false;
}
}, {
br : null
} ];
l = {
debug : 0,
log : 0,
info : 'information',
em : 'emphasis',
warn : 'warning',
error : 'error'
};
for (i in l) {
controller.push(' ', {
a : log_icon[i],
href : '#',
title : 'toggle [' + i + ']\n切換 ' + (l[i] || i) + ' 訊息',
onclick : function() {
var tag = this.title.match(/\[([^\]]+)\]/);
if (tag)
CeL.set_class(this, 'debug_hide', {
remove : CeL.toggle_log(tag[1])
});
return false;
}
});
}
// 增加 group 以便在多項輸入時亦可 toggle 或排版。
CeL.Log.controller = {
div : [ {
a : 'log',
href : '#',
title : 'log 控制項',
onclick : function() {
var parentNode = this.parentNode;
if (parentNode.force_show) {
// DOM 不可使用 delete @ IE9
// delete parentNode.force_show;
parentNode.force_show = false;
} else {
CeL.toggle_display(this.nextSibling,
//
parentNode.force_show = true);
}
return false;
}
}, {
span : controller,
C : 'debug_controller'
} ],
// TODO: 即使僅是移動 mouse 進入 child,也會執行多次。
onmouseover : function() {
CeL.toggle_display(this.firstChild.nextSibling, 1);
},
onmouseout : function() {
if (!this.force_show) {
CeL.toggle_display(this.firstChild.nextSibling, 0);
}
},
C : 'debug_controller_panel'
};
// 在 CeL.log 被重新設定前先 cache 一下。
var log_buffer = CeL.log && CeL.log.buffer;
// --------------------------------------------------------------------------------------------
// front ends of log function
/**
* 警告: 在 node.js v0.10.25, v0.11.16 中,不使用 var 的模式設定 function,會造成:
* In strict mode code, functions can only be declared at top level or
* immediately within another function.
*
* 在 node.js v4.2.1 中可以順利 pass。
*/
var log_front_end_fatal =
// fatal: the most serious 致命錯誤。
function log_front_end_fatal(message, error_to_throw) {
if (CeL.is_WWW())
try {
console.trace(error_to_throw);
// 模擬 throw 以 get .stack
throw CeL.is_type(error_to_throw, 'Error') ? error_to_throw
: new Error(error_to_throw || 'Fatal error');
} catch (e) {
// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
CeL.error(e.stack ? message
+ '
stack:
CeL.test([ [ 'aa', {
type : String
} ], [ 456, {
type : 123
} ], [ {}, {
type : Object
} ], [ false, {
type : Boolean
} ] ], 'type test');
// --------------------------------------
// TODO:
// may ignore:
CeL.setup_test(test_group_name);
CeL.test(test_group_name, conditions, options);
// conditions #1: [
// [ test value: true / false, 'test_group_name' ],
// [ test value: true / false, {name:'test_group_name'} ],
// [ test value: true / false, {options} ],
// [ test value: true / false ],
// test value: true / false,
//
// [ [ test value 1, test value 2 ], 'test_group_name' ],
// [ [ test value 1, test value 2 ], {name:'test_group_name'} ],
// [ [ test value 1, test value 2 ], {options} ],
// [ [ test value 1, test value 2 ] ],
//
// [ function tester(), 'test_group_name' ],
// [ function tester() ],
// [ function tester(callback), {need_callback:true} ],
// function tester(),
// function tester() { return new Promise },
// async function tester(),
//
// ]
// conditions #2:
// function async_tester(assert)
// async function async_tester(assert)
//
// CeL.test(test_group_name, function async_tester(assert, callback), {need_callback:true});
//
// assert(test value: true / false, 'test_group_name');
// assert(test value: true / false, options);
// assert(test value: true / false);
// assert([ test value 1, test value 2 ], 'test_group_name');
// assert([ test value 1, test value 2 ]);
CeL.test_finished();
*
* @param {String}[test_group_name]
* test name 此次測試名稱。
* @param {Array|Function}conditions
* condition list passed to assert(): [ [ condition / test
* value, options ], [], ... ].