Web编程技术营地
研究、演示、创新

PageConsole with TrimPre Test

Basic Usage

First, import the neccessary modules on the page:

<script type="module" src="/js/esm/web-widgets/trim-pre/highlight-with-trimpre.js"></script>

And for each TrimPre widget on the page, if it was written as followed:

...

It comes with the help of PageConsole, to which a variable named pc references. Then, we can write the codes in the TrimPre widget, such as:

pc.log('Hello'); let obj = {color: 'green'}; pc.log(obj);

The effects of above are:

  1. Source codes are colorfied with supporting for both dark theme and light theme.
  2. The source codes would be run automaticlly with the awareness of PageConsole.
  3. The results of pc.log would be directed to the web page by default.
  4. A dynamic div is created below the TrimPre widget, in which shows the results of the source codes.

Compared with LiveEditor, it's light-weight, with sources un-editable, and has a broader viewport.

Direct the output

We can add a CONSOLE in the class attribute, in order to direct the outputs to the console only.

pc.log("Hello");

The available attributes are: PAGE (default setting), CONSOLE, and BOTH.

So, we can control the direction of each TrimPre widget independently.

The Freedom to Import

Writing the await import() statements in the block, we can import what we need at will.

const { getBinStr } = await import('/js/esm/BinUtils.js'); let num = 1225; pc.log(getBinStr(num, 8));

The result of importing would be automaticlly resolved, so we avoid being bothered with having to invoke the then method.

Basically, when loading a relative URL, we should have writen:

const { aModule } = await import(new URL('./SomeModule.js', window.location).href);

Since the code is so tedious, the utility has done this for us:

codeSrc = codeSrc.replaceAll(/(['"`])(\.\/.*\.js)(\1)/g, 'new URL($1$2$3, window.location).href');

So the simply writing:

const { aModule } = await import('./SomeModule.js');

would be enough.

Tabular Texts

The font-family of PageConsole is monospace, so it's a perfect place to output the tabular formatted texts, which is the shortage of the console itself.

const { getHexAddrStrFromTypedArray } = await import('/js/esm/BinUtils.js'); const { NumUtils } = await import('/js/esm/NumUtils.js'); let nums = NumUtils.GetIntsInRange(0, 0xFF, 64); let tarr = new Uint8Array(nums); let str = getHexAddrStrFromTypedArray(tarr, 16, 4, 2); pc.log('%s', str); pc.log(25);

Dealing with Exceptions

PageConsole is smart enough to handle various exceptions by default.

let a = b + 5;

And even for Promise rejections.

let promise = Promise.resolve(5); promise .then(value => { value.someFunc(); // producing an exception pc.log(value); }) .catch(e => pc.showException(e.message));

By invoking the showException in the catch method, we route the exception message from the console to page in a custom formatting.

Dealing with Long Titles and Properties

let arr = []; for (let i = 0; i < 150; i++) { arr.push(i * 2); } pc.log(arr);

For arrays with too many elements or objects with too many properties, their titles may be too long and properties may be too many.

These titles would strip some contents add ... at the end, decided by whether it's on mobile devices or desktop displays.

The child nodes to be shown would be increased by 20 items each time, if the user click on the show next ... string.

Too many properties in an object:

let p = pc.appendHTMLStr(`

A sample paragraph.

`)[0]; let cssStyleDeclaration = getComputedStyle(p); pc.log(cssStyleDeclaration);

Implementation of the Specification

PageConsole is not the static cloning of the console object, but rather a trying to implement the Console Standard from scratch.

Supporting Format Specifiers

let obj = { car: 'Ford', speed: 180 }; pc.log(`%s has a high speed of %d.`, obj.car, obj.speed); pc.log(`%f + %f = %f`, 1.2, 2.3); // less than the required specifiers pc.log(`sum of %i and %i is %i`, 3, 5, 8, "The end."); // more than the required specifiers // supporting generic JavaScript object formatting pc.log(`%O`, obj); // supporting optimally useful formatting let p = document.createElement('p'); p.textContent = "This is a HTML Element."; p.style = "color: steelblue"; pc.log(`%o`, p);

Logging Multiple Values in a Shot

let obj = { car: 'Ford', speed: 180 }; pc.log(2, 3, "35"); pc.log(1, 2, 3); pc.log([1, 2, 3]); pc.log(1, 2, obj, 3, 4, null, [5, 6, 7], 8);

For such multiple values in an invokation, they are grouped into a cell, separated by ,, with simple data types sharing a line and compound data types occuping the whole line to be freely expanded.

Pre-implementation

pc.log("%c, %d, %c, %s", "color: orange;", 25, "color: darkcyan; font-size: 1.5em;", 'Custom String');

The %c specifier would apply the CSS style, yet it is in a state of future in the specification. So we're going ahead little bit here.

String Representations

In the following situations, the representation of strings should be surrounded with "...":

pc.log(2, 3, "35", 8); // distinguised from other number type pc.log('Hello, World'); // a whole string pc.log('Hello', 'World'); // two strings let obj = { car: 'Ford', speed: 180 }; pc.log(obj); // string properties

However, under the circumstances of specifiers, strings should not be surrounded with "..." by default:

pc.log("%s and %s are good friends.", "Tom", "Mike"); pc.log("%s is a programming language.", "JavaScript");

In such case, if necessary, we can add "..." or '...' manually.

pc.log("'%s' or '%s' is up to you.", "Good", "bad");

Grouping

Grouping is a nested, expandable stack container.

pc.group(); pc.group('2nd level group'); pc.log('Texts in 2nd level group.'); pc.log('%d + %d = %d', 2, 3, 5); pc.group('3rd level group'); pc.log('Hello'); pc.groupEnd(); pc.log('Back forwards a level'); pc.log([1, 2, 3]); pc.group("A new group from the current level"); pc.log(33); pc.groupEnd(); pc.groupEnd(); pc.log('Back to the 2nd level.'); pc.groupEnd(); pc.groupCollapsed('A collapsed group at the top level'); pc.log(55);

Tables

pc.group('Table from Array'); pc.group('All'); pc.table(["row1", "row2", "row3"]); pc.groupEnd(); pc.group('Filtered'); pc.table(["row1", "row2", "row3"], ['row1', 'row3']); pc.groupEnd(); pc.groupEnd(); pc.group('Table from Object'); let obj = { name: 'Mike', age: 25, gender: 'Male' }; pc.group('All'); pc.table(obj); pc.groupEnd(); pc.group('Filtered'); pc.table(obj, ['age', 'gender']); pc.groupEnd(); pc.groupEnd();

Assertion

let number = 10; // pass pc.assert(number === 10); // fails pc.assert(number < 0); pc.assert(number < 0, number); pc.assert(number < 0, `assert: %s < %d, but %s = %d`, 'number', 0, 'number', number); pc.assert(number < 0, 'Too big'); pc.assert(number < 0, 15, 25, 35);

Error

pc.error('Something is wrong!'); pc.error('Number (%d) is too big!', 10); pc.error(35); let obj = { color: 'orange', size: 18 }; pc.error(obj);

Information

pc.info('%s', 'This is an info message.'); pc.info('%d + %d = %d', 2, 3, 5);

Warning

pc.warn("%s", "A warining message here."); pc.warn("The meaning of '%s' seems unclear.", "too fast");

Extra JavaScript Source

Suppose we have a file named setup-canvas.js with the contents:

const { geoGrp: g } = await import('/js/esm/geoGrp.js'); let canvas = document.createElement('canvas'); pc.appendChild(canvas);

Add an attribute just as:

pc.log("%O", canvas);

Then the running order would be:

  1. pc is initialized first
  2. canvas is created and appended to the DOM tree with the help of pc
  3. the canvas would be logged finally

In this way, we can move lots of same common source codes in a page into a specific file, saving spaces and times.

See also

For stand-alone usage of PageConsole, see Page Console Test

For stand-alone usage of TrimPre, see TrimPre Test

For high-lighted features of TrimPre, see Highlight with TrimPre Test

参考资源

  1. Console Standard
  2. Console (MDN)