console.message

Rich text console logging

此腳本不應該直接安裝,它是一個供其他腳本使用的函式庫。欲使用本函式庫,請在腳本 metadata 寫上: // @require https://update.gf.qytechs.cn/scripts/370255/612436/consolemessage.js

  1. // ==UserScript==
  2. // @name console.message
  3. // @description Rich text console logging
  4. // @version 0.1.0
  5. // ==/UserScript==
  6.  
  7. ; (function () {
  8. var cssNumbers = {
  9. columnCount: true,
  10. fillOpacity: true,
  11. flexGrow: true,
  12. flexShrink: true,
  13. fontWeight: true,
  14. lineHeight: true,
  15. opacity: true,
  16. order: true,
  17. orphans: true,
  18. widows: true,
  19. zIndex: true,
  20. zoom: true
  21. };
  22.  
  23. var support = (function () {
  24. // Taken from https://github.com/jquery/jquery-migrate/blob/master/src/core.js
  25. function uaMatch(ua) {
  26. ua = ua.toLowerCase();
  27.  
  28. var match = /(chrome)[ \/]([\w.]+)/.exec(ua) ||
  29. /(webkit)[ \/]([\w.]+)/.exec(ua) ||
  30. /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) ||
  31. /(msie) ([\w.]+)/.exec(ua) ||
  32. ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || [];
  33.  
  34. return {
  35. browser: match[1] || "",
  36. version: match[2] || "0"
  37. };
  38. }
  39. var browserData = uaMatch(navigator.userAgent);
  40.  
  41. return {
  42. isIE: browserData.browser == 'msie' || (browserData.browser == 'mozilla' && parseInt(browserData.version, 10) == 11)
  43. };
  44. })();
  45.  
  46. function ConsoleMessage() {
  47. if (!ConsoleMessage.prototype.isPrototypeOf(this)) {
  48. return new ConsoleMessage();
  49. }
  50. this._rootSpan = {
  51. styles: {},
  52. children: [],
  53. parent: null
  54. };
  55. this._currentSpan = this._rootSpan;
  56. this._waiting = 0;
  57. this._readyCallback = null;
  58. }
  59.  
  60. ConsoleMessage.prototype = {
  61. /**
  62. * Begins a group. By default the group is expanded. Provide false if you want the group to be collapsed.
  63. * @param {boolean} [expanded = true] -
  64. * @returns {ConsoleMessage} - Returns the message object itself to allow chaining.
  65. */
  66. group: function (expanded) {
  67. this._currentSpan.children.push({
  68. type: expanded === false ? 'groupCollapsed' : 'group',
  69. parent: this._currentSpan
  70. });
  71. return this;
  72. },
  73.  
  74. /**
  75. * Ends the group and returns to writing to the parent message.
  76. * @returns {ConsoleMessage} - Returns the message object itself to allow chaining.
  77. */
  78. groupEnd: function () {
  79. this._currentSpan.children.push({
  80. type: 'groupEnd',
  81. parent: this._currentSpan
  82. });
  83. return this;
  84. },
  85.  
  86. /**
  87. * Starts a span with particular style and all appended text after it will use the style.
  88. * @param {Object} styles - The CSS styles to be applied to all text until endSpan() is called
  89. * @returns {ConsoleMessage} - Returns the message object itself to allow chaining.
  90. */
  91. span: function (styles) {
  92. var span = {
  93. type: 'span',
  94. styles: apply(styles || {}, this._currentSpan.styles),
  95. children: [],
  96. parent: this._currentSpan
  97. };
  98. this._currentSpan.children.push(span);
  99. this._currentSpan = span;
  100. return this;
  101. },
  102.  
  103. /**
  104. * Ends the current span styles and backs to the previous styles or the root if there are no other parents.
  105. * @returns {ConsoleMessage} - Returns the message object itself to allow chaining.
  106. */
  107. spanEnd: function () {
  108. this._currentSpan = this._currentSpan.parent || this._currentSpan;
  109. return this;
  110. },
  111.  
  112. /**
  113. * Appends a text to the current message. All styles in the current span are applied.
  114. * @param {string} text - The text to be appended
  115. * @returns {ConsoleMessage} - Returns the message object itself to allow chaining.
  116. */
  117. text: function (text, styles) {
  118. this.span(styles);
  119. this._currentSpan.children.push({
  120. type: 'text',
  121. message: text,
  122. parent: this._currentSpan
  123. });
  124. return this.spanEnd();
  125. },
  126.  
  127. /**
  128. * Adds a new line to the output.
  129. * @returns {ConsoleMessage} - Returns the message object itself to allow chaining.
  130. */
  131. line: function (type) {
  132. this._currentSpan.children.push({
  133. type: type || 'log',
  134. parent: this._currentSpan
  135. });
  136. return this;
  137. },
  138.  
  139. /**
  140. * Adds an interactive DOM element to the output.
  141. * @param {HTMLElement} element - The DOM element to be added.
  142. * @returns {ConsoleMessage} - Returns the message object itself to allow chaining.
  143. */
  144. element: function (element) {
  145. this._currentSpan.children.push({
  146. type: 'element',
  147. element: element,
  148. parent: this._currentSpan
  149. });
  150. return this;
  151. },
  152.  
  153. /**
  154. * Adds an interactive object tree to the output.
  155. * @param {*} object - A value to be added to the output.
  156. * @returns {ConsoleMessage} - Returns the message object itself to allow chaining.
  157. */
  158. object: function (object) {
  159. this._currentSpan.children.push({
  160. type: 'object',
  161. object: object,
  162. parent: this._currentSpan
  163. });
  164. return this;
  165. },
  166.  
  167. /**
  168. * Prints the message to the console.
  169. * Until print() is called there will be no result to the console.
  170. */
  171. print: function () {
  172. if (typeof console != 'undefined') {
  173. var messages = [this._newMessage()];
  174. var message;
  175.  
  176. this._printSpan(this._rootSpan, messages);
  177.  
  178. for (var i = 0; i < messages.length; i++) {
  179. message = messages[i];
  180. if (message.text && message.text != '%c' && console[message.type]) {
  181. this._printMessage(message);
  182. }
  183. }
  184. }
  185.  
  186. return new ConsoleMessage();
  187. },
  188.  
  189. _printMessage: function (message) {
  190. Function.prototype.apply.call(
  191. console[message.type],
  192. console,
  193. [message.text].concat(message.args)
  194. );
  195. },
  196.  
  197. _printSpan: function (span, messages) {
  198. var children = span.children;
  199. var message = messages[messages.length - 1];
  200.  
  201. this._addSpanData(span, message);
  202.  
  203. for (var i = 0; i < children.length; i++) {
  204. this._handleChild(children[i], messages);
  205. }
  206. },
  207.  
  208. _handleChild: function (child, messages) {
  209. var message = messages[messages.length - 1];
  210.  
  211. switch (child.type) {
  212. case 'group':
  213. messages.push(this._newMessage('group'));
  214. break;
  215. case 'groupCollapsed':
  216. messages.push(this._newMessage('groupCollapsed'));
  217. break;
  218. case 'groupEnd':
  219. message = this._newMessage('groupEnd');
  220. message.text = ' ';
  221. messages.push(message);
  222. messages.push(this._newMessage());
  223. break;
  224. case 'span':
  225. this._printSpan(child, messages);
  226. this._addSpanData(child, message);
  227. this._addSpanData(child.parent, message);
  228. break;
  229. case 'text':
  230. message.text += child.message;
  231. break;
  232. case 'element':
  233. message.text += '%o';
  234. message.args.push(child.element);
  235. break;
  236. case 'object':
  237. message.text += '%O';
  238. message.args.push(child.object);
  239. break;
  240. case 'log':
  241. messages.push(this._newMessage(child.type));
  242. break;
  243. }
  244. },
  245.  
  246. _addSpanData: function (span, message) {
  247. if (!support.isIE) {
  248. if (message.text.substring(message.text.length - 2) == '%c') {
  249. message.args[message.args.length - 1] = this._stylesString(span.styles);
  250. } else {
  251. message.text += '%c';
  252. message.args.push(this._stylesString(span.styles));
  253. }
  254. }
  255. },
  256.  
  257. _newMessage: function (type) {
  258. return {
  259. type: type || 'log',
  260. text: '',
  261. args: []
  262. };
  263. },
  264.  
  265. _stylesString: function (styles) {
  266. var result = '';
  267. var value;
  268. var key;
  269.  
  270. for (key in styles) {
  271. value = styles[key];
  272. key = this._fixCssStyleKey(key);
  273.  
  274. if (typeof value === 'number' && !cssNumbers[key]) {
  275. value += 'px';
  276. }
  277. result += this._toDashKey(key) + ':' + value + ';';
  278. }
  279.  
  280. return result;
  281. },
  282.  
  283. _fixCssStyleKey: function (key) {
  284. return key.replace(/-\w/g, function (match) {
  285. return match.charAt(1).toUpperCase();
  286. });
  287. },
  288.  
  289. _toDashKey: function (key) {
  290. return key.replace(/[A-Z]/g, function (match) {
  291. return '-' + match.toLowerCase();
  292. });
  293. }
  294. };
  295.  
  296. function apply(options, object) {
  297. for (var key in object) {
  298. if (options[key] === undefined) {
  299. options[key] = object[key];
  300. }
  301. }
  302. return options;
  303. }
  304.  
  305. if (typeof window != 'undefined') {
  306. if (!window.console) {
  307. window.console = {};
  308. }
  309.  
  310. /**
  311. * Creates a message object.
  312. * @returns {ConsoleMessage} - The message object
  313. */
  314. window.console.message = ConsoleMessage;
  315. }
  316. })()

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址