2020年6月9日 星期二
2020年5月28日 星期四
project 對 dom.tree 先廣域搜索指定的節點,再排序
const getCommentLis = {
main(root) {
let commentList = [];
let dataList = [{
level: [1],
node: root
}];
// 位數
let digit = dataList[0].level.length;
let i = 0;
let data;
while (null != (data = dataList[i++])) {
// debugger;
const level = data.level;
const node = data.node;
if (node.tagName != null) {
node.childNodes.forEach((child, i) => {
let _level = level.slice()
_level.push(i + 1);
if (_level.length > digit) {
digit = _level.length;
}
dataList.push({
level: _level,
node: child
});
});
} else {
if (node.nodeType == 8) {
let parent = node.parentNode;
commentList.push({
parent: parent,
node: node,
level
});
}
}
} // endWhile
// debugger;
console.dir(commentList);
commentList.sort((a, b) => {
if (Array.isArray(a.level)) {
a.level = this.getLevel(digit, a.level);
}
if (Array.isArray(b.level)) {
b.level = this.getLevel(digit, b.level);
}
return (a.level - b.level);
});
console.dir(commentList);
return commentList;
},
getLevel(digit, level) {
debugger;
let j = digit - level.length;
// debugger;
// 基數
let p = 1;
for (let i = 0; i < j; i++) {
p *= 10;
}
// debugger;
let res = 0;
let num;
while (null != (num = level.pop())) {
res = res + num * p;
// 十進位
p *= 10;
}
return res;
}
}
2019年3月7日 星期四
worker 環境判定
if(typeof Window !== 'undefined'){
// browser
}else if(typeof WorkerGlobalScope !== 'undefined'){
// browser worker
}else if(typeof module !== 'undefined'){
// node.js
const {isMainThread} = require('worker_threads');
if(isMainThread){
// MainThread
}else{
// worker
}
}
// browser
}else if(typeof WorkerGlobalScope !== 'undefined'){
// browser worker
}else if(typeof module !== 'undefined'){
// node.js
const {isMainThread} = require('worker_threads');
if(isMainThread){
// MainThread
}else{
// worker
}
}
2019年2月26日 星期二
拖曳一個小方塊.......不錯用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="./js_lib/jquery-3.3.1.js"></script>
<style>
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
body {
position: relative;
}
div.container_1 {
height: 1000px;
background-color: #ffc;
position: relative;
}
#moveEvent {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
border: 1px dashed;
z-index: 99999;
display: none;
user-select: none;
opacity: 0;
}
#box_1 {
width: 100px;
height: 100px;
position: absolute;
top: 50px;
left: 100px;
z-index: 100;
background-color: #00F;
user-select: none;
}
</style>
</head>
<body>
<div id="moveEvent">
<!-- 全螢幕的畫布 -->
</div>
<div class="container_1">
<p id="box_1">
box
</p>
</div>
<script>
// screen 與 #box_1 的座標差
let topOffset;
let leftOffset;
let callback;
$('#box_1').on('mousedown', function (e) {
console.dir(e);
let { left, top } = $(this).position();
topOffset = top - e.screenY;
leftOffset = left - e.screenX;
//-----------------------
callback = (function (leftOffset, topOffset, x, y) {
let left = x + leftOffset;
let top = y + topOffset;
$('#box_1').css({
top: top,
left: left
});
}).bind(this, leftOffset, topOffset);
//-----------------------
$('#moveEvent').css('display', 'block');
});
$('#moveEvent').on('mousemove', function (e) {
console.log('offset:(%s, %s)', e.offsetX, e.offsetY);
console.log('screen(%s, %s)', e.screenX, e.screenY);
if(callback){
callback(e.screenX, e.screenY);
}
});
$('#moveEvent').on('mouseup', function () {
callback = undefined;
$('#moveEvent').css('display', '');
});
</script>
</body>
</html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="./js_lib/jquery-3.3.1.js"></script>
<style>
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
body {
position: relative;
}
div.container_1 {
height: 1000px;
background-color: #ffc;
position: relative;
}
#moveEvent {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
border: 1px dashed;
z-index: 99999;
display: none;
user-select: none;
opacity: 0;
}
#box_1 {
width: 100px;
height: 100px;
position: absolute;
top: 50px;
left: 100px;
z-index: 100;
background-color: #00F;
user-select: none;
}
</style>
</head>
<body>
<div id="moveEvent">
<!-- 全螢幕的畫布 -->
</div>
<div class="container_1">
<p id="box_1">
box
</p>
</div>
<script>
// screen 與 #box_1 的座標差
let topOffset;
let leftOffset;
let callback;
$('#box_1').on('mousedown', function (e) {
console.dir(e);
let { left, top } = $(this).position();
topOffset = top - e.screenY;
leftOffset = left - e.screenX;
//-----------------------
callback = (function (leftOffset, topOffset, x, y) {
let left = x + leftOffset;
let top = y + topOffset;
$('#box_1').css({
top: top,
left: left
});
}).bind(this, leftOffset, topOffset);
//-----------------------
$('#moveEvent').css('display', 'block');
});
$('#moveEvent').on('mousemove', function (e) {
console.log('offset:(%s, %s)', e.offsetX, e.offsetY);
console.log('screen(%s, %s)', e.screenX, e.screenY);
if(callback){
callback(e.screenX, e.screenY);
}
});
$('#moveEvent').on('mouseup', function () {
callback = undefined;
$('#moveEvent').css('display', '');
});
</script>
</body>
</html>
2019年2月25日 星期一
yahoo serialize
/*
Copyright (c) 2014, Yahoo! Inc. All rights reserved.
Copyrights licensed under the New BSD License.
See the accompanying LICENSE file for terms.
*/
'use strict';
// Generate an internal UID to make the regexp pattern harder to guess.
var UID = Math.floor(Math.random() * 0x10000000000).toString(16);
var PLACE_HOLDER_REGEXP = new RegExp('"@__(F|R|D)-' + UID + '-(\\d+)__@"', 'g');
var IS_NATIVE_CODE_REGEXP = /\{\s*\[native code\]\s*\}/g;
var UNSAFE_CHARS_REGEXP = /[<>\/\u2028\u2029]/g;
// Mapping of unsafe HTML and invalid JavaScript line terminator chars to their
// Unicode char counterparts which are safe to use in JavaScript strings.
var ESCAPED_CHARS = {
'<' : '\\u003C',
'>' : '\\u003E',
'/' : '\\u002F',
'\u2028': '\\u2028',
'\u2029': '\\u2029'
};
function escapeUnsafeChars(unsafeChar) {
return ESCAPED_CHARS[unsafeChar];
}
module.exports = function serialize(obj, options) {
options || (options = {});
// Backwards-compatability for `space` as the second argument.
if (typeof options === 'number' || typeof options === 'string') {
options = {space: options};
}
var functions = [];
var regexps = [];
var dates = [];
// Returns placeholders for functions and regexps (identified by index)
// which are later replaced by their string representation.
function replacer(key, value) {
if (!value) {
return value;
}
// If the value is an object w/ a toJSON method, toJSON is called before
// the replacer runs, so we use this[key] to get the non-toJSONed value.
var origValue = this[key];
var type = typeof origValue;
if (type === 'object') {
if(origValue instanceof RegExp) {
return '@__R-' + UID + '-' + (regexps.push(origValue) - 1) + '__@';
}
if(origValue instanceof Date) {
return '@__D-' + UID + '-' + (dates.push(origValue) - 1) + '__@';
}
}
if (type === 'function') {
return '@__F-' + UID + '-' + (functions.push(origValue) - 1) + '__@';
}
return value;
}
var str;
// Creates a JSON string representation of the value.
// NOTE: Node 0.12 goes into slow mode with extra JSON.stringify() args.
if (options.isJSON && !options.space) {
str = JSON.stringify(obj);
} else {
str = JSON.stringify(obj, options.isJSON ? null : replacer, options.space);
}
// Protects against `JSON.stringify()` returning `undefined`, by serializing
// to the literal string: "undefined".
if (typeof str !== 'string') {
return String(str);
}
// Replace unsafe HTML and invalid JavaScript line terminator chars with
// their safe Unicode char counterpart. This _must_ happen before the
// regexps and functions are serialized and added back to the string.
str = str.replace(UNSAFE_CHARS_REGEXP, escapeUnsafeChars);
if (functions.length === 0 && regexps.length === 0 && dates.length === 0) {
return str;
}
// Replaces all occurrences of function, regexp and date placeholders in the
// JSON string with their string representations. If the original value can
// not be found, then `undefined` is used.
return str.replace(PLACE_HOLDER_REGEXP, function (match, type, valueIndex) {
if (type === 'D') {
return "new Date(\"" + dates[valueIndex].toISOString() + "\")";
}
if (type === 'R') {
return regexps[valueIndex].toString();
}
var fn = functions[valueIndex];
var serializedFn = fn.toString();
if (IS_NATIVE_CODE_REGEXP.test(serializedFn)) {
throw new TypeError('Serializing native function: ' + fn.name);
}
return serializedFn;
});
}
Copyright (c) 2014, Yahoo! Inc. All rights reserved.
Copyrights licensed under the New BSD License.
See the accompanying LICENSE file for terms.
*/
'use strict';
// Generate an internal UID to make the regexp pattern harder to guess.
var UID = Math.floor(Math.random() * 0x10000000000).toString(16);
var PLACE_HOLDER_REGEXP = new RegExp('"@__(F|R|D)-' + UID + '-(\\d+)__@"', 'g');
var IS_NATIVE_CODE_REGEXP = /\{\s*\[native code\]\s*\}/g;
var UNSAFE_CHARS_REGEXP = /[<>\/\u2028\u2029]/g;
// Mapping of unsafe HTML and invalid JavaScript line terminator chars to their
// Unicode char counterparts which are safe to use in JavaScript strings.
var ESCAPED_CHARS = {
'<' : '\\u003C',
'>' : '\\u003E',
'/' : '\\u002F',
'\u2028': '\\u2028',
'\u2029': '\\u2029'
};
function escapeUnsafeChars(unsafeChar) {
return ESCAPED_CHARS[unsafeChar];
}
module.exports = function serialize(obj, options) {
options || (options = {});
// Backwards-compatability for `space` as the second argument.
if (typeof options === 'number' || typeof options === 'string') {
options = {space: options};
}
var functions = [];
var regexps = [];
var dates = [];
// Returns placeholders for functions and regexps (identified by index)
// which are later replaced by their string representation.
function replacer(key, value) {
if (!value) {
return value;
}
// If the value is an object w/ a toJSON method, toJSON is called before
// the replacer runs, so we use this[key] to get the non-toJSONed value.
var origValue = this[key];
var type = typeof origValue;
if (type === 'object') {
if(origValue instanceof RegExp) {
return '@__R-' + UID + '-' + (regexps.push(origValue) - 1) + '__@';
}
if(origValue instanceof Date) {
return '@__D-' + UID + '-' + (dates.push(origValue) - 1) + '__@';
}
}
if (type === 'function') {
return '@__F-' + UID + '-' + (functions.push(origValue) - 1) + '__@';
}
return value;
}
var str;
// Creates a JSON string representation of the value.
// NOTE: Node 0.12 goes into slow mode with extra JSON.stringify() args.
if (options.isJSON && !options.space) {
str = JSON.stringify(obj);
} else {
str = JSON.stringify(obj, options.isJSON ? null : replacer, options.space);
}
// Protects against `JSON.stringify()` returning `undefined`, by serializing
// to the literal string: "undefined".
if (typeof str !== 'string') {
return String(str);
}
// Replace unsafe HTML and invalid JavaScript line terminator chars with
// their safe Unicode char counterpart. This _must_ happen before the
// regexps and functions are serialized and added back to the string.
str = str.replace(UNSAFE_CHARS_REGEXP, escapeUnsafeChars);
if (functions.length === 0 && regexps.length === 0 && dates.length === 0) {
return str;
}
// Replaces all occurrences of function, regexp and date placeholders in the
// JSON string with their string representations. If the original value can
// not be found, then `undefined` is used.
return str.replace(PLACE_HOLDER_REGEXP, function (match, type, valueIndex) {
if (type === 'D') {
return "new Date(\"" + dates[valueIndex].toISOString() + "\")";
}
if (type === 'R') {
return regexps[valueIndex].toString();
}
var fn = functions[valueIndex];
var serializedFn = fn.toString();
if (IS_NATIVE_CODE_REGEXP.test(serializedFn)) {
throw new TypeError('Serializing native function: ' + fn.name);
}
return serializedFn;
});
}
2019年2月2日 星期六
操控點位移(不錯的版本)
<pre>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style media="screen">
*{
padding: 0;
margin: 0;
box-sizing: border-box;
}
.main_container{
width: 400px;
height:300px;
background-color: #FCC;
position: relative;
}
.symbol {
width: 100%;
height: 100%;
}
.operator{
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
p.box{
position: absolute;
left: 0;
top: 0;
width: 20px;
height: 20px;
background-color: #666;
}
</style>
<script src="./js_lib/jquery-3.3.1.min.js" charset="utf-8"></script>
</head>
<body>
<div>
<button type="button" onclick=t_1()>go</button>
</div>
<div class="main_container">
<div id="symbol" class="symbol">
</div>
<div id="operator" class="operator">
<p class="box" id="box_1"></p>
</div>
</div>
<script>
function V(){
this.symbol;
this.operator;
this.box;
this.box_click_left;
this.box_click_top;
this.__construct();
};
(function(){
this.__construct = function(){
debugger;
this.symbol = document.querySelector('#symbol');
this.operator = document.querySelector('#operator');
this.box = document.querySelector('#box_1');
$(this.box).on('mousedown', (function(e){
this.event_1(e);
}).bind(this));
$(this.operator).on('mouseup', (function(e){
this.event_2(e);
}).bind(this));
};
//----------------------------
this.event_1 = function(e){
// debugger;
this.box_click_left = e.offsetX;
this.box_click_top = e.offsetY;
$(this.box).appendTo(this.symbol);
$(this.operator).on('mousemove', (function(e){
this.event_3(e);
}).bind(this));
};
//----------------------------
this.event_2 = function(e){
$(this.operator).off('mousemove');
$(this.box).appendTo(this.operator);
};
//----------------------------
this.event_3 = function(e){
console.log('(%s, %s)', e.offsetX, e.offsetY);
let x= e.offsetX - this.box_click_left;
let y = e.offsetY - this.box_click_top;
$(this.box).css({
left: x,
top: y
});
};
}).call(V.prototype);
new V();
</script>
</body>
</html>
</pre>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style media="screen">
*{
padding: 0;
margin: 0;
box-sizing: border-box;
}
.main_container{
width: 400px;
height:300px;
background-color: #FCC;
position: relative;
}
.symbol {
width: 100%;
height: 100%;
}
.operator{
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
p.box{
position: absolute;
left: 0;
top: 0;
width: 20px;
height: 20px;
background-color: #666;
}
</style>
<script src="./js_lib/jquery-3.3.1.min.js" charset="utf-8"></script>
</head>
<body>
<div>
<button type="button" onclick=t_1()>go</button>
</div>
<div class="main_container">
<div id="symbol" class="symbol">
</div>
<div id="operator" class="operator">
<p class="box" id="box_1"></p>
</div>
</div>
<script>
function V(){
this.symbol;
this.operator;
this.box;
this.box_click_left;
this.box_click_top;
this.__construct();
};
(function(){
this.__construct = function(){
debugger;
this.symbol = document.querySelector('#symbol');
this.operator = document.querySelector('#operator');
this.box = document.querySelector('#box_1');
$(this.box).on('mousedown', (function(e){
this.event_1(e);
}).bind(this));
$(this.operator).on('mouseup', (function(e){
this.event_2(e);
}).bind(this));
};
//----------------------------
this.event_1 = function(e){
// debugger;
this.box_click_left = e.offsetX;
this.box_click_top = e.offsetY;
$(this.box).appendTo(this.symbol);
$(this.operator).on('mousemove', (function(e){
this.event_3(e);
}).bind(this));
};
//----------------------------
this.event_2 = function(e){
$(this.operator).off('mousemove');
$(this.box).appendTo(this.operator);
};
//----------------------------
this.event_3 = function(e){
console.log('(%s, %s)', e.offsetX, e.offsetY);
let x= e.offsetX - this.box_click_left;
let y = e.offsetY - this.box_click_top;
$(this.box).css({
left: x,
top: y
});
};
}).call(V.prototype);
new V();
</script>
</body>
</html>
</pre>
2019年1月8日 星期二
特殊字符\u2028導致的Javascript腳本異常
網上查詢得知,這個編碼為2028的字符為行分隔符,會被瀏覽器理解為換行,而在Javascript的字符串表達式中是不允許換行的,從而導致錯誤。
解決方法
把特殊字符轉義替換即可,代碼如下所示:
1
str = str.Replace("\u2028", "\\u2028");
替換後,用之前有問題的文章測試,加載正常,問題解決。
另外,Javascript中的特殊字符一共有13個,建議都進行轉義處理,如下:
Unicode 字符值 轉義序列 含義 類別
\u0008 \b Backspace
\u0009 \t Tab 空白
\u000A \n 換行符(換行) 行結束符
\u000B \v 垂直製表符 空白
\u000C \f 換頁 空白
\u000D \r 回車 行結束符
\u0022 \" 雙引號 (")
\u0027 \' 單引號 (')
\u005C \\ 反斜槓 (\)
\u00A0 不間斷空格 空白
\u2028 行分隔符 行結束符
\u2029 段落分隔符 行結束符
\uFEFF 字節順序標記 空白
解決方法
把特殊字符轉義替換即可,代碼如下所示:
1
str = str.Replace("\u2028", "\\u2028");
替換後,用之前有問題的文章測試,加載正常,問題解決。
另外,Javascript中的特殊字符一共有13個,建議都進行轉義處理,如下:
Unicode 字符值 轉義序列 含義 類別
\u0008 \b Backspace
\u0009 \t Tab 空白
\u000A \n 換行符(換行) 行結束符
\u000B \v 垂直製表符 空白
\u000C \f 換頁 空白
\u000D \r 回車 行結束符
\u0022 \" 雙引號 (")
\u0027 \' 單引號 (')
\u005C \\ 反斜槓 (\)
\u00A0 不間斷空格 空白
\u2028 行分隔符 行結束符
\u2029 段落分隔符 行結束符
\uFEFF 字節順序標記 空白
2018年12月18日 星期二
javascript 另一種模板編組
function compile(template) {
const evalExpr = /<%=(.+?)%>/g;
const expr = /<%([\s\S]+?)%>/g;
template = template.replace(evalExpr, '`); \n echo( $1 ); \n echo(`');
template = template.replace(expr, '`); \n $1 \n echo(`');
template = 'echo(`' + template + '`);';
console.log(template);
let script =
`let output = "";
function echo(html){
output += html;
}
${template}
return output;`;
return new Function(script);
}
let content = "<ul>\
<% for(let i=0; i < 4; i++){ %>\
<li><%= i %>--${i*2}</li>\
<% } %>\
</ul>";
let res = compile(content);
console.log(res());
console.log('--------------------');
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
https://johnresig.com/blog/javascript-micro-templating/
function compile(template) {
let functionStr = compile_1(template);
functionStr = "data = data || {};\n\
for(let k in data){\n\
let command = 'var '+ k + '= data[\"'+k+'\"];';\n\
eval(command);\n\
}\n\
" + functionStr;
console.log(functionStr);
let fun = new Function('print', 'data', functionStr);
function print(html) {
return html;
}
return (fun).bind(null, print);
}
function compile_1(template) {
const expr = /([\s\S]*?)<%([\s\S]+?)%>/g;
const evalExpr = /([\s\S]*?)<%=([\s\S]+?)%>/g;
reg_1 = /<%[^=-][\s\S]+?%>/;
reg_2 = /<%=[\s\S]+?%>/;
reg_3 = /<%-[^-][\s\S]+?%>/;
let reg = [];
reg.push("(" + reg_1.source + ")");
reg.push("(" + reg_2.source + ")");
reg.push("(" + reg_3.source + ")");
reg = reg.join("|");
reg = `([\\s\\S]*?)(?:${reg})`;
console.log(reg);
reg = RegExp(reg, 'g');
let source = "let source = [];\n";
template = template.replace(reg, function (m, g1, g2, g3, g4) {
debugger;
if (g1) {
source += `source.push(\`${g1}\`);\n`;
}
if (g2) {
// <% %>
g2 = g2.replace(/%>$/, '').replace(/^<%/, '');
source += `\n${g2}\n`;
} else if (g3) {
// <%= %>
g3 = g3.replace(/%>$/, '').replace(/^<%=/, '');
source += `source.push(print(${g3}));\n`;
} else if (g4) {
// <%- %>
g4 = g4.replace(/%>$/, '').replace(/^<%-/, '');
source += `source.push(print(${g4}));\n`;
}
return '';
});
if (template) {
source += `source.push(\`${template}\`);\n`;
}
source += 'return (source.join(""));\n';
return source;
}
let content = "<ul>\
<% for(let i=0; i < a.length; i++){ %>\
<li><%= i*2 %>--${a[i]*2}</li>\
<% } %>\
</ul>";
let res = compile(content);
console.dir(res);
const evalExpr = /<%=(.+?)%>/g;
const expr = /<%([\s\S]+?)%>/g;
template = template.replace(evalExpr, '`); \n echo( $1 ); \n echo(`');
template = template.replace(expr, '`); \n $1 \n echo(`');
template = 'echo(`' + template + '`);';
console.log(template);
let script =
`let output = "";
function echo(html){
output += html;
}
${template}
return output;`;
return new Function(script);
}
let content = "<ul>\
<% for(let i=0; i < 4; i++){ %>\
<li><%= i %>--${i*2}</li>\
<% } %>\
</ul>";
let res = compile(content);
console.log(res());
console.log('--------------------');
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
https://johnresig.com/blog/javascript-micro-templating/
function compile(template) {
let functionStr = compile_1(template);
functionStr = "data = data || {};\n\
for(let k in data){\n\
let command = 'var '+ k + '= data[\"'+k+'\"];';\n\
eval(command);\n\
}\n\
" + functionStr;
console.log(functionStr);
let fun = new Function('print', 'data', functionStr);
function print(html) {
return html;
}
return (fun).bind(null, print);
}
function compile_1(template) {
const expr = /([\s\S]*?)<%([\s\S]+?)%>/g;
const evalExpr = /([\s\S]*?)<%=([\s\S]+?)%>/g;
reg_1 = /<%[^=-][\s\S]+?%>/;
reg_2 = /<%=[\s\S]+?%>/;
reg_3 = /<%-[^-][\s\S]+?%>/;
let reg = [];
reg.push("(" + reg_1.source + ")");
reg.push("(" + reg_2.source + ")");
reg.push("(" + reg_3.source + ")");
reg = reg.join("|");
reg = `([\\s\\S]*?)(?:${reg})`;
console.log(reg);
reg = RegExp(reg, 'g');
let source = "let source = [];\n";
template = template.replace(reg, function (m, g1, g2, g3, g4) {
debugger;
if (g1) {
source += `source.push(\`${g1}\`);\n`;
}
if (g2) {
// <% %>
g2 = g2.replace(/%>$/, '').replace(/^<%/, '');
source += `\n${g2}\n`;
} else if (g3) {
// <%= %>
g3 = g3.replace(/%>$/, '').replace(/^<%=/, '');
source += `source.push(print(${g3}));\n`;
} else if (g4) {
// <%- %>
g4 = g4.replace(/%>$/, '').replace(/^<%-/, '');
source += `source.push(print(${g4}));\n`;
}
return '';
});
if (template) {
source += `source.push(\`${template}\`);\n`;
}
source += 'return (source.join(""));\n';
return source;
}
let content = "<ul>\
<% for(let i=0; i < a.length; i++){ %>\
<li><%= i*2 %>--${a[i]*2}</li>\
<% } %>\
</ul>";
let res = compile(content);
console.dir(res);
2018年11月21日 星期三
json deepCopy
// 比 JSON.parse(JSON.stringify(data)) 還略慢
module.exports = deepCopy;
let jobList = [];
// for test
// 與 JSON.stringify() 對比速度用
function deepCopy(value) {
// debugger;
let dataSet = new DataSet(value);
jobList.push(dataSet);
let index = 0;
while ((dataSet = jobList[index++]) != null) {
// debugger;
let _value = dataSet.originalValue;
if (Array.isArray(_value)) {
for (let i = 0; i < _value.length; i++) {
let v = _value[i];
let ds = new DataSet(v, dataSet, i);
jobList.push(ds);
}
} else if (typeof (_value) == "object") {
for (let k in _value) {
let v = _value[k];
let ds = new DataSet(v, dataSet, k);
jobList.push(ds);
}
} else {
continue;
}
}
//-----------------------
let res;
let d;
while ((d = jobList.pop()) != null) {
res = d;
d.solve();
}
return res.value;
}
//======================================
function DataSet(v, p, k) {
this.parent; // DataSet
this.parentKey;
this.value;
this.originalValue;
this.__construct(v, p, k);
}
(function () {
this.__construct = function (v, p, k) {
this.originalValue = v;
if (p) {
this.parent = p;
this.parentKey = k;
}
this._makeValue();
};
//--------------------------------------
this._makeValue = function () {
if (Array.isArray(this.originalValue)) {
this.value = [];
} else if (typeof (this.originalValue) == "object") {
this.value = {};
} else {
this.value = this.originalValue;
}
};
//--------------------------------------
this.solve = function () {
if (this.parent == null) {
return;
}
let data = this.parent.value;
data[this.parentKey] = this.value;
this._destory();
};
//--------------------------------------
this._destory = function () {
this.parent = undefined;
this.parentKey = undefined;
this.value = undefined;
this.originalValue = undefined;
};
}).call(DataSet.prototype);
module.exports = deepCopy;
let jobList = [];
// for test
// 與 JSON.stringify() 對比速度用
function deepCopy(value) {
// debugger;
let dataSet = new DataSet(value);
jobList.push(dataSet);
let index = 0;
while ((dataSet = jobList[index++]) != null) {
// debugger;
let _value = dataSet.originalValue;
if (Array.isArray(_value)) {
for (let i = 0; i < _value.length; i++) {
let v = _value[i];
let ds = new DataSet(v, dataSet, i);
jobList.push(ds);
}
} else if (typeof (_value) == "object") {
for (let k in _value) {
let v = _value[k];
let ds = new DataSet(v, dataSet, k);
jobList.push(ds);
}
} else {
continue;
}
}
//-----------------------
let res;
let d;
while ((d = jobList.pop()) != null) {
res = d;
d.solve();
}
return res.value;
}
//======================================
function DataSet(v, p, k) {
this.parent; // DataSet
this.parentKey;
this.value;
this.originalValue;
this.__construct(v, p, k);
}
(function () {
this.__construct = function (v, p, k) {
this.originalValue = v;
if (p) {
this.parent = p;
this.parentKey = k;
}
this._makeValue();
};
//--------------------------------------
this._makeValue = function () {
if (Array.isArray(this.originalValue)) {
this.value = [];
} else if (typeof (this.originalValue) == "object") {
this.value = {};
} else {
this.value = this.originalValue;
}
};
//--------------------------------------
this.solve = function () {
if (this.parent == null) {
return;
}
let data = this.parent.value;
data[this.parentKey] = this.value;
this._destory();
};
//--------------------------------------
this._destory = function () {
this.parent = undefined;
this.parentKey = undefined;
this.value = undefined;
this.originalValue = undefined;
};
}).call(DataSet.prototype);
2018年9月20日 星期四
2018年6月13日 星期三
gseries.js
function gseries(fn, data) {
return new Promise(function (res, rej) {
let it = fn();
job(data);
//----------------------------
function job(d) {
// 主要要不斷重複的步驟
let g = it.next(d);
let p = g.value;
// p.then(...)
if (g.done) {
res(p);
} else if (p instanceof Promise) {
p.then(function (d) {
job(d);
}, function (err) {
rej(err);
});
}else{
job(p);
}
}
});
}
return new Promise(function (res, rej) {
let it = fn();
job(data);
//----------------------------
function job(d) {
// 主要要不斷重複的步驟
let g = it.next(d);
let p = g.value;
// p.then(...)
if (g.done) {
res(p);
} else if (p instanceof Promise) {
p.then(function (d) {
job(d);
}, function (err) {
rej(err);
});
}else{
job(p);
}
}
});
}
2018年6月5日 星期二
讓 js.generator 不斷往下執行
let gseries = require('../node_modules/gseries');
function asynce(index) {
return new Promise(function (res, rej) {
console.log('index(%s) start', index);
setTimeout(function () {
console.log('index(%s) end', index);
res(index);
}, 3000);
});
}
function* main() {
yield asynce(0);
yield asynce(1);
return asynce(2);
}
let p = gseries(main);
--------------------------------------------------------
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
module.exports = gseries;
function gseries(fn, data) {
return new Promise(function (res, rej) {
let it = fn();
job(data);
//----------------------------
function job(d) {
// 主要要不斷重複的步驟
let g = it.next(d);
let p = g.value;
// p.then(...)
if (g.done) {
res(p);
} else if (p instanceof Promise) {
p.then(function (d) {
job(d);
}, function (err) {
rej(err);
});
}else{
job(p);
}
}
});
}
function asynce(index) {
return new Promise(function (res, rej) {
console.log('index(%s) start', index);
setTimeout(function () {
console.log('index(%s) end', index);
res(index);
}, 3000);
});
}
function* main() {
yield asynce(0);
yield asynce(1);
return asynce(2);
}
let p = gseries(main);
--------------------------------------------------------
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
module.exports = gseries;
function gseries(fn, data) {
return new Promise(function (res, rej) {
let it = fn();
job(data);
//----------------------------
function job(d) {
// 主要要不斷重複的步驟
let g = it.next(d);
let p = g.value;
// p.then(...)
if (g.done) {
res(p);
} else if (p instanceof Promise) {
p.then(function (d) {
job(d);
}, function (err) {
rej(err);
});
}else{
job(p);
}
}
});
}
2018年5月29日 星期二
TinyMCE
https://www-archive.mozilla.org/editor/midas-spec.html
https://www.tinymce.com/
TinyMCE
http://blog.pulipuli.info/2017/08/htmltinymce-online-html-editor.html
https://ckeditor.com/ckeditor-4/
(html5)
http://xing.github.io/wysihtml5/
(html5)
https://archive.codeplex.com/?p=jhtmlarea
https://github.com/crpietschmann/jHtmlArea
(html5)
http://www.nicedit.com/
https://kevinroth.com/rte/
https://kevinroth.com/rte/demo.htm
http://www.freetextbox.com
http://www.unverse.net
http://markitup.jaysalvat.com/home/
http://www.themaninblue.com/experiment/widgEditor/
http://www.freetextbox.com
http://www.wymeditor.org/demo/
http://www.openwebware.com
http://www.xstandard.com
http://www.nicedit.com/index.php
https://www.tinymce.com/
TinyMCE
http://blog.pulipuli.info/2017/08/htmltinymce-online-html-editor.html
https://ckeditor.com/ckeditor-4/
(html5)
http://xing.github.io/wysihtml5/
(html5)
https://archive.codeplex.com/?p=jhtmlarea
https://github.com/crpietschmann/jHtmlArea
(html5)
http://www.nicedit.com/
https://kevinroth.com/rte/
https://kevinroth.com/rte/demo.htm
http://www.freetextbox.com
http://www.unverse.net
http://markitup.jaysalvat.com/home/
http://www.themaninblue.com/experiment/widgEditor/
http://www.freetextbox.com
http://www.wymeditor.org/demo/
http://www.openwebware.com
http://www.xstandard.com
http://www.nicedit.com/index.php
2018年5月25日 星期五
baidutemplate
'<p>5</p>\
<% for(var i = 0; i < 5; i++){ %>\
<% if(i<3){ %>\
<p>111111</p>\
<% _template_fun_array.push(x()); %>\
<% }else{ %>\
<p>222222</p>\
<% } %>\
<% } %>'
紅色的地方可化為 echo (x());
<% for(var i = 0; i < 5; i++){ %>\
<% if(i<3){ %>\
<p>111111</p>\
<% _template_fun_array.push(x()); %>\
<% }else{ %>\
<p>222222</p>\
<% } %>\
<% } %>'
紅色的地方可化為 echo (x());
2018年4月19日 星期四
js 仿製 php (serialize)
module.exports = serialize;
function serialize(data) {
let res = '';
for (let i = 0, method; method = serialize.methods[i]; i++) {
let temp;
try {
temp = method(data);
res = temp;
break;
} catch (error) {
if (error instanceof TypeError) {
continue;
} else {
throw error;
}
}
}
return res;
}
//==============================================================================
(function (self) {
self.methods = [
function (data) {
// string
if (typeof data !== 'string') {
throw new TypeError();
}
let res = 'String:' + String(data.length) + ':"' + data + '"';
return res;
},
function (data) {
// number
if (typeof data !== 'number') {
throw new TypeError();
}
let res = 'Number:' + data;
return res;
},
function (data) {
// undefined
if (typeof data !== 'undefined') {
throw new TypeError();
}
let res = 'undefined';
return res;
},
function (data) {
// null
if (data !== null) {
throw new TypeError();
}
let res = 'null';
return res;
},
function (data) {
// array
if (!Array.isArray(data)) {
throw new TypeError();
}
//----------------------------
let res = 'Array:' + data.length + ':{';
for (let i = 0; i < data.length; i++) {
res += 'Number:' + i + ';';
// 進入遞迴
let _res = serialize(data[i]);
res += _res + ';'
}
res += '}';
return res;
},
//============================
function (data) {
// {}
if (typeof data !== 'object' && data == null) {
throw new TypeError();
}
let type = Object.prototype.toString.call(data);
if (!/\[object Object\]/.test(data)) {
throw new TypeError();
}
//----------------------------
let length = Object.keys(data).length;
let res = 'Object:' + length + ':{';
for (let k in data) {
if (data.hasOwnProperty(k)) {
// 進入遞迴
let _k = serialize(k);
let _res = serialize(data[k]);
res += _k + ';' + _res + ';';
}
}
res += '}';
return res;
},
//============================
function (data) {
// Map
if (!(data instanceof Map)) {
throw new TypeError();
}
let length = data.size;
let res = 'Map:' + length + ':{';
data.forEach(function (v, k) {
// 進入遞迴
k = serialize(k);
v = serialize(v);
res += (k + ';' + v + ';');
});
res += '}';
return res;
},
function (data) {
// 從函式實例化的物件
}
];
})(serialize);
///////////////////////////////////////////////////////////////////////////////////////////
module.exports = unserialize;
function unserialize(data) {
++unserialize.count;
//----------------------------
let res;
let objectType;
data.replace(/^([^\:]+)/g, function (m, g) {
objectType = g;
});
if (objectType in unserialize.methos) {
res = unserialize.methos[objectType](data);
} else {
throw new Error(JSON.stringify(data) + ' no this method');
}
//----------------------------
if (--unserialize.count === 0) {
unserialize.jobs.length = 0;
}
return res;
}
(function (self) {
self.UID = Math.floor(Math.random() * 0x10000000000).toString(16);
self.count = 0;
self.jobs = [];
//==========================================================================
// 從變數陣列中區分出 key, value
self.getKeyValue = function (child_str) {
// 避開 string 的影響
// 清除所有 string 內部的內容,避免干擾發生
child_str = self.prevProccessingString(child_str);
// console.log(child_str);
//----------------------------
// 找尋屬於他的變數
let str_variables = [];
// 從左往右解
while (child_str.length > 0) {
let judge = 0;
for (let i = 0; i < child_str.length; i++) {
let char = child_str.charAt(i);
if (char === '{') {
++judge;
}
if (char === '}') {
--judge;
}
if ((char === ';' || i === (child_str.length - 1)) && judge === 0) {
// 取出一個區段
let target = child_str.slice(0, i + 1);
str_variables.push(target);
child_str = child_str.slice(i + 1);
break;
}
}
}
let res = {
key: [],
value: []
};
str_variables.forEach(function (v, i) {
if (i % 2 === 0) {
res.key.push(v);
} else {
res.value.push(v);
}
});
return res;
};
//==========================================================================
self.checkString = function (str) {
let reg = new RegExp('@_' + unserialize.UID + '_(\\d+)_@');
while (reg.test(str)) {
res = reg.exec(str);
let i = Number(res[1]);
if (typeof unserialize.jobs[i] !== 'undefined') {
let s = unserialize.jobs[i];
str = str.replace(reg, s);
} else {
throw new Error('no find match string recorder');
}
}
return str;
};
//==========================================================================
// 這邊要加強
// 對 unicode......等的加強
self.prevProccessingString = function (str) {
let res, reg = /String:(\d+):"/g;
let positionList = [];
while (res = reg.exec(str)) {
// 匹配的字數
let i = res[0].length;
// 匹配的位置
let index = res.index;
// 文字的長度
let length = parseInt(res[1], 10);
if (length === 0) {
// 沒有內容就不需處理
continue;
}
let data = {
s: (index + i),
e: (index + i + length - 1)
};
data.target = str.slice(data.s, data.e + 1);
positionList.unshift(data);
// console.log(res);
}
positionList.forEach(function (d) {
let start = d.s;
let end = d.e;
let index = unserialize.jobs.length;
let replace = '@_' + unserialize.UID + '_' + index + '_@';
let head = str.slice(0, start);
let foot = str.slice(end + 1);
let middle = str.slice(start, end + 1);
unserialize.jobs[index] = middle;
str = head + replace + foot;
});
return str;
};
//==========================================================================
self.methos = {
String: function (data) {
let res = /"(.*)"/.exec(data);
return res[1];
},
//======================================
Number: function (data) {
let res = /Number:(\d*)/.exec(data);
return Number(res[1]);
},
//======================================
Object: function (data) {
let res = {};
// 物件本身的描述
let self_str = '';
// 孩子的描述
let child_str;
let keyLength = 0;
data.replace(/^([^\{\}]+?)\{(.*)\}/g, function (m, g1, g2) {
self_str = g1;
child_str = (g2 == null ? '' : g2);
return '';
});
//----------------------------
self_str.replace(/^[^:\d]+:(\d+):/g, function (m, g1) {
keyLength = Number(g1);
});
//----------------------------
let d = self.getKeyValue(child_str);
let keyList = d.key;
let valueList = d.value;
// 變數長度檢查
if (keyLength !== keyList.length || keyList.length !== valueList.length) {
throw new Error(data + ' variable length have trouble');
}
//----------------------------
keyList.forEach(function (k, i) {
console.dir(data);
let v = valueList[i];
k = unserialize.checkString(k);
v = unserialize.checkString(v);
// 遞迴
k = unserialize(k);
v = unserialize(v);
res[k] = v;
});
//----------------------------
if (keyLength !== Object.keys(res).length) {
throw new Error("analyze error(" + data + ")");
}
return res;
},
//======================================
Map: function (data) {
let res = new Map();
// 物件本身的描述
let self_str = '';
// 孩子的描述
let child_str;
let keyLength = 0;
data.replace(/^([^\{\}]+?)\{(.*)\}/g, function (m, g1, g2) {
self_str = g1;
child_str = (g2 == null ? '' : g2);
return '';
});
//----------------------------
self_str.replace(/^[^:\d]+:(\d+):/g, function (m, g1) {
keyLength = Number(g1);
});
//----------------------------
let d = self.getKeyValue(child_str);
// console.dir(d);
let keyList = d.key;
let valueList = d.value;
// 變數長度檢查
if (keyLength !== keyList.length || keyList.length !== valueList.length) {
throw new Error(data + ' variable length have trouble');
}
keyList.forEach(function (k, i) {
let v = valueList[i];
k = unserialize.checkString(k);
v = unserialize.checkString(v);
// 遞迴
k = unserialize(k);
v = unserialize(v);
res.set(k, v);
});
//----------------------------
return res;
},
Array: function (data) {
let res = [];
// 物件本身的描述
let self_str = '';
// 孩子的描述
let child_str;
let keyLength = 0;
data.replace(/^([^\{\}]+?)\{(.*)\}/g, function (m, g1, g2) {
self_str = g1;
child_str = (g2 == null ? '' : g2);
return '';
});
//----------------------------
self_str.replace(/^[^:\d]+:(\d+):/g, function (m, g1) {
keyLength = Number(g1);
});
//----------------------------
let d = self.getKeyValue(child_str);
// console.dir(d);
let keyList = d.key;
let valueList = d.value;
// 變數長度檢查
if (keyLength !== keyList.length || keyList.length !== valueList.length) {
throw new Error(data + ' variable length have trouble');
}
keyList.forEach(function (k, i) {
let v = valueList[i];
k = unserialize.checkString(k);
v = unserialize.checkString(v);
// 遞迴
k = unserialize(k);
v = unserialize(v);
res[k] = v;
});
//----------------------------
return res;
},
O: function (data) {
// 非預設物件
// 從函式實例化的物件
},
}
})(unserialize);
2018年4月7日 星期六
js htmlEntity
function htmlEntity() {
var p = document.createElement("p");
p.textContent = str;
var converted = p.innerHTML;
p = undefined;
return converted;
}
var p = document.createElement("p");
p.textContent = str;
var converted = p.innerHTML;
p = undefined;
return converted;
}
2018年1月26日 星期五
HTML 事件属性
Window 事件屬性
針對 window 對象觸發的事件(應用到 <body> 標籤):
| 屬性 | 值 | 描述 |
|---|---|---|
| onafterprint | script | 文檔打印之後運行的腳本。 |
| onbeforeprint | script | 文檔打印之前運行的腳本。 |
| onbeforeunload | script | 文檔卸載之前運行的腳本。 |
| onerror | script | 在錯誤發生時運行的腳本。 |
| onhaschange | script | 當文檔已改變時運行的腳本。 |
| onload | script | 頁面結束加載之後觸發。 |
| onmessage | script | 在消息被觸發時運行的腳本。 |
| onoffline | script | 當文檔離線時運行的腳本。 |
| ononline | script | 當文檔上線時運行的腳本。 |
| onpagehide | script | 當窗口隱藏時運行的腳本。 |
| onpageshow | script | 當窗口成為可見時運行的腳本。 |
| onpopstate | script | 當窗口歷史記錄改變時運行的腳本。 |
| onredo | script | 當文檔執行撤銷(redo)時運行的腳本。 |
| onresize | script | 當瀏覽器窗口被調整大小時觸發。 |
| onstorage | script | 在 Web Storage 區域更新後運行的腳本。 |
| onundo | script | 在文檔執行 undo 時運行的腳本。 |
| onunload | script | 一旦頁面已下載時觸發(或者瀏覽器窗口已被關閉)。 |
Form 事件
由 HTML 表單內的動作觸發的事件(應用到幾乎所有 HTML 元素,但最常用在 form 元素中):
| 屬性 | 值 | 描述 |
|---|---|---|
| onblur | script | 元素失去焦點時運行的腳本。 |
| onchange | script | 在元素值被改變時運行的腳本。 |
| oncontextmenu | script | 當上下文菜單被觸發時運行的腳本。 |
| onfocus | script | 當元素獲得焦點時運行的腳本。 |
| onformchange | script | 在表單改變時運行的腳本。 |
| onforminput | script | 當表單獲得用戶輸入時運行的腳本。 |
| oninput | script | 當元素獲得用戶輸入時運行的腳本。 |
| oninvalid | script | 當元素無效時運行的腳本。 |
| onreset | script | 當表單中的重置按鈕被點擊時觸發。HTML5 中不支持。 |
| onselect | script | 在元素中文本被選中後觸發。 |
| onsubmit | script | 在提交表單時觸發。 |
Keyboard 事件
| 屬性 | 值 | 描述 |
|---|---|---|
| onkeydown | script | 在用戶按下按鍵時觸發。 |
| onkeypress | script | 在用戶敲擊按鈕時觸發。 |
| onkeyup | script | 當用戶釋放按鍵時觸發。 |
Mouse 事件
由鼠標或類似用戶動作觸發的事件:
| 屬性 | 值 | 描述 |
|---|---|---|
| onclick | script | 元素上發生鼠標點擊時觸發。 |
| ondblclick | script | 元素上發生鼠標雙擊時觸發。 |
| ondrag | script | 元素被拖動時運行的腳本。 |
| ondragend | script | 在拖動操作末端運行的腳本。 |
| ondragenter | script | 當元素元素已被拖動到有效拖放區域時運行的腳本。 |
| ondragleave | script | 當元素離開有效拖放目標時運行的腳本。 |
| ondragover | script | 當元素在有效拖放目標上正在被拖動時運行的腳本。 |
| ondragstart | script | 在拖動操作開端運行的腳本。 |
| ondrop | script | 當被拖元素正在被拖放時運行的腳本。 |
| onmousedown | script | 當元素上按下鼠標按鈕時觸發。 |
| onmousemove | script | 當鼠標指針移動到元素上時觸發。 |
| onmouseout | script | 當鼠標指針移出元素時觸發。 |
| onmouseover | script | 當鼠標指針移動到元素上時觸發。 |
| onmouseup | script | 當在元素上釋放鼠標按鈕時觸發。 |
| onmousewheel | script | 當鼠標滾輪正在被滾動時運行的腳本。 |
| onscroll | script | 當元素滾動條被滾動時運行的腳本。 |
Media 事件
由媒介(比如視頻、圖像和音頻)觸發的事件(適用於所有 HTML 元素,但常見於媒介元素中,比如 <audio>、<embed>、<img>、<object> 以及 <video>):
| 屬性 | 值 | 描述 |
|---|---|---|
| onabort | script | 在退出時運行的腳本。 |
| oncanplay | script | 當文件就緒可以開始播放時運行的腳本(緩衝已足夠開始時)。 |
| oncanplaythrough | script | 當媒介能夠無需因緩衝而停止即可播放至結尾時運行的腳本。 |
| ondurationchange | script | 當媒介長度改變時運行的腳本。 |
| onemptied | script | 當發生故障並且文件突然不可用時運行的腳本(比如連接意外斷開時)。 |
| onended | script | 當媒介已到達結尾時運行的腳本(可發送類似「感謝觀看」之類的消息)。 |
| onerror | script | 當在文件加載期間發生錯誤時運行的腳本。 |
| onloadeddata | script | 當媒介數據已加載時運行的腳本。 |
| onloadedmetadata | script | 當元數據(比如分辨率和時長)被加載時運行的腳本。 |
| onloadstart | script | 在文件開始加載且未實際加載任何數據前運行的腳本。 |
| onpause | script | 當媒介被用戶或程序暫停時運行的腳本。 |
| onplay | script | 當媒介已就緒可以開始播放時運行的腳本。 |
| onplaying | script | 當媒介已開始播放時運行的腳本。 |
| onprogress | script | 當瀏覽器正在獲取媒介數據時運行的腳本。 |
| onratechange | script | 每當回放速率改變時運行的腳本(比如當用戶切換到慢動作或快進模式)。 |
| onreadystatechange | script | 每當就緒狀態改變時運行的腳本(就緒狀態監測媒介數據的狀態)。 |
| onseeked | script | 當 seeking 屬性設置為 false(指示定位已結束)時運行的腳本。 |
| onseeking | script | 當 seeking 屬性設置為 true(指示定位是活動的)時運行的腳本。 |
| onstalled | script | 在瀏覽器不論何種原因未能取回媒介數據時運行的腳本。 |
| onsuspend | script | 在媒介數據完全加載之前不論何種原因終止取回媒介數據時運行的腳本。 |
| ontimeupdate | script | 當播放位置改變時(比如當用戶快進到媒介中一個不同的位置時)運行的腳本。 |
| onvolumechange | script | 每當音量改變時(包括將音量設置為靜音)時運行的腳本。 |
| onwaiting | script | 當媒介已停止播放但打算繼續播放時(比如當媒介暫停已緩衝更多數據)運行腳本 |
訂閱:
文章 (Atom)


