diff --git a/_server/README.md b/_server/README.md
index 521ce1cc..d23bfb43 100644
--- a/_server/README.md
+++ b/_server/README.md
@@ -1,5 +1,7 @@
# editor
+[重构](refactoring.md)
+
>! 以下均是v2.0时的说明, 未及时改动
本目录下所有文件,以及`../editor.html`和`../启动服务.exe`([源码](http://github.com/ckcz123/mota-js-server/))是地图编辑器的所有组件.
@@ -31,7 +33,7 @@
``` js
editor.mapInit();//清空地图
editor.changeFloor('MT2')//切换地图
-editor.guid()//产生一个可以作为id的长随机字符串
+editor.util.guid()//产生一个可以作为id的长随机字符串
```
`editor.updateMap`中画未定义快的报错
diff --git a/_server/editor.js b/_server/editor.js
index b675d7ff..03b0cf01 100644
--- a/_server/editor.js
+++ b/_server/editor.js
@@ -41,31 +41,9 @@ editor.info
/////////// 数据相关 ///////////
editor.prototype.init = function (callback) {
- var afterCoreReset = function () {
- editor.idsInit(core.maps, core.icons.icons); // 初始化图片素材信息
- editor.drawInitData(core.icons.icons); // 初始化绘图
-
- editor.fetchMapFromCore();
- editor.updateMap();
- editor.buildMark();
- editor.drawEventBlock();
-
- editor.pos = {x: 0, y: 0};
- editor.mode.loc();
- editor.info = editor.ids[editor.indexs[201]];
- editor.mode.enemyitem();
- editor.mode.floor();
- editor.mode.tower();
- editor.mode.functions();
- editor.mode.commonevent();
- editor.mode.showMode('tower');
-
- editor_multi = editor_multi();
- editor_blockly = editor_blockly();
- if (Boolean(callback)) callback();
-
- }
+ editor_util_wrapper(editor);
+ editor_table_wrapper(editor);
var afterMainInit = function () {
core.floors = JSON.parse(JSON.stringify(core.floors, function (k, v) {
@@ -97,6 +75,33 @@ editor.prototype.init = function (callback) {
core.events.setInitData(null);
});
}
+
+ var afterCoreReset = function () {
+
+ editor.idsInit(core.maps, core.icons.icons); // 初始化图片素材信息
+ editor.drawInitData(core.icons.icons); // 初始化绘图
+
+ editor.fetchMapFromCore();
+ editor.updateMap();
+ editor.buildMark();
+ editor.drawEventBlock();
+
+ editor.pos = {x: 0, y: 0};
+ editor.mode.loc();
+ editor.info = editor.ids[editor.indexs[201]];
+ editor.mode.enemyitem();
+ editor.mode.floor();
+ editor.mode.tower();
+ editor.mode.functions();
+ editor.mode.commonevent();
+ editor.mode.showMode('tower');
+
+ editor_multi = editor_multi();
+ editor_blockly = editor_blockly();
+ if (Boolean(callback)) callback();
+
+ }
+
afterMainInit();
}
@@ -354,21 +359,6 @@ editor.prototype.moveViewport=function(x,y){
editor.drawPosSelection();
}
-/////////// 通用 ///////////
-
-editor.prototype.guid = function () {
- return 'id_' + 'xxxxxxxx_xxxx_4xxx_yxxx_xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
- var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
- return v.toString(16);
- });
-}
-
-editor.prototype.HTMLescape = function (str_) {
- return String(str_).split('').map(function (v) {
- return '' + v.charCodeAt(0) + ';'
- }).join('');
-}
-
/////////// 界面交互相关 ///////////
editor.prototype.drawInitData = function (icons) {
diff --git a/_server/editor_file.js b/_server/editor_file.js
index 545867b2..89b7f6c5 100644
--- a/_server/editor_file.js
+++ b/_server/editor_file.js
@@ -94,7 +94,7 @@ editor_file = function (editor, callback) {
}
// format 更改实现方式以支持undefined删除
var tempJsonObj=Object.assign({},editor.currentFloorData);
- var tempMap=[['map',editor.guid()],['bgmap',editor.guid()],['fgmap',editor.guid()]];
+ var tempMap=[['map',editor.util.guid()],['bgmap',editor.util.guid()],['fgmap',editor.util.guid()]];
tempMap.forEach(function(v){
v[2]=tempJsonObj[v[0]];
tempJsonObj[v[0]]=v[1];
@@ -764,7 +764,7 @@ editor_file = function (editor, callback) {
var fmap = {};
var fjson = JSON.stringify(functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a, function (k, v) {
if (v instanceof Function) {
- var id_ = editor.guid();
+ var id_ = editor.util.guid();
fmap[id_] = v.toString();
return id_;
} else return v
@@ -853,11 +853,11 @@ editor_file = function (editor, callback) {
var plmap = {};
var pljson = JSON.stringify(plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1, function (k, v) {
if (v instanceof Function) {
- var id_ = editor.guid();
+ var id_ = editor.util.guid();
plmap[id_] = v.toString();
return id_;
} else if(v===null){
- var id_ = editor.guid();
+ var id_ = editor.util.guid();
plmap[id_] = 'null';
return id_;
} return v
@@ -980,7 +980,7 @@ editor_file = function (editor, callback) {
var emap = {};
var estr = JSON.stringify(maps_90f36752_8815_4be8_b32b_d7fad1d0542e, function (k, v) {
if (v.id != null) {
- var id_ = editor.guid();
+ var id_ = editor.util.guid();
emap[id_] = JSON.stringify(v);
return id_;
} else return v
@@ -1014,7 +1014,7 @@ editor_file = function (editor, callback) {
var emap = {};
var estr = JSON.stringify(enemys_fcae963b_31c9_42b4_b48c_bb48d09f3f80, function (k, v) {
if (v.hp != null) {
- var id_ = editor.guid();
+ var id_ = editor.util.guid();
emap[id_] = JSON.stringify(v);
return id_;
} else return v
diff --git a/_server/editor_mode.js b/_server/editor_mode.js
index c70b8a57..d38a69e1 100644
--- a/_server/editor_mode.js
+++ b/_server/editor_mode.js
@@ -38,305 +38,6 @@ editor_mode = function (editor) {
if (Boolean(callback)) callback();
}
-/////////////////////////////////////////////////////////////////////////////
- /**
- * 把来自数据文件的obj和来自*comment.js的commentObj组装成表格
- * commentObj在无视['_data']的意义下与obj同形
- * 即: commentObj['_data']['a']['_data']['b'] 与 obj['a']['b'] 是对应的
- * 在此意义下, 两者的结构是一致的
- * 在commentObj没有被定义的obj的分支, 会取defaultcobj作为默认值
- * 因此在深度优先遍历时,维护
- * field="['a']['b']"
- * cfield="['_data']['a']['_data']['b']"
- * vobj=obj['a']['b']
- * cobj=commentObj['_data']['a']['_data']['b']
- * cobj
- * cobj = Object.assign({}, defaultcobj, pcobj['_data'][ii])
- * 每一项若未定义,就从defaultcobj中取
- * 当其是函数不是具体值时,把args = {field: field, cfield: cfield, vobj: vobj, cobj: cobj}代入算出该值
- * 得到的叶节点的
结构如下
- * tr>td[title=field]
- * >td[title=comment,cobj=cobj:json]
- * >td>div>input[value=thiseval]
- * 返回结果
- * 返回一个对象, 假设被命名为tableinfo
- * 在把一个 table 的 innerHTML 赋值为 tableinfo.HTML 后
- * 再调 tableinfo.listen(tableinfo.guids) 进行绑定事件
- * @param {Object} obj
- * @param {Object} commentObj
- * @returns {{"HTML":String,"guids":String[],"listen":Function}}
- */
- editor_mode.prototype.objToTable_ = function (obj, commentObj) {
- // 表格抬头
- var outstr = ["\n
| 条目 | 注释 | 值 |
\n"];
- var guids = [];
- var defaultcobj = {
- // 默认是文本域
- _type: 'textarea',
- _data: '',
- _string: function (args) {//object~[field,cfield,vobj,cobj]
- var thiseval = args.vobj;
- return (typeof(thiseval) === typeof('')) && thiseval[0] === '"';
- },
- // 默认情况下 非对象和数组的视为叶节点
- _leaf: function (args) {//object~[field,cfield,vobj,cobj]
- var thiseval = args.vobj;
- if (thiseval == null || thiseval == undefined) return true;//null,undefined
- if (typeof(thiseval) === typeof('')) return true;//字符串
- if (Object.keys(thiseval).length === 0) return true;//数字,true,false,空数组,空对象
- return false;
- },
- }
- /**
- * 深度优先遍历, p*即为父节点的四个属性
- * @param {String} pfield
- * @param {String} pcfield
- * @param {Object} pvobj
- * @param {Object} pcobj
- */
- var recursionParse = function (pfield, pcfield, pvobj, pcobj) {
- var keysForTableOrder={};
- var voidMark={};
- // 1. 按照pcobj排序生成
- if (pcobj && pcobj['_data']){
- for (var ii in pcobj['_data']) keysForTableOrder[ii]=voidMark;
- }
- // 2. 对每个pvobj且不在pcobj的,再添加到最后
- keysForTableOrder=Object.assign(keysForTableOrder,pvobj)
- for (var ii in keysForTableOrder) {
- // 3. 对于pcobj有但是pvobj中没有的, 弹出提示, (正常情况下editor_file会补全成null)
- // 事实上能执行到这一步工程没崩掉打不开,就继续吧..
- if(keysForTableOrder[ii]===voidMark){
- if(typeof id_815975ad_ee6f_4684_aac7_397b7e392702==="undefined"){
- alert('comment和data不匹配,请在群 HTML5造塔技术交流群 959329661 内反馈')
- console.error('comment和data不匹配,请在群 HTML5造塔技术交流群 959329661 内反馈')
- id_815975ad_ee6f_4684_aac7_397b7e392702=1;
- }
- pvobj[ii]=null;
- }
- var field = pfield + "['" + ii + "']";
- var cfield = pcfield + "['_data']['" + ii + "']";
- var vobj = pvobj[ii];
- var cobj = null;
- if (pcobj && pcobj['_data'] && pcobj['_data'][ii]) {
- // cobj存在时直接取
- cobj = Object.assign({}, defaultcobj, pcobj['_data'][ii]);
- } else {
- // 当其函数时代入参数算出cobj, 不存在时只取defaultcobj
- if (pcobj && (pcobj['_data'] instanceof Function)) cobj = Object.assign({}, defaultcobj, pcobj['_data'](ii));
- else cobj = Object.assign({}, defaultcobj);
- }
- var args = {field: field, cfield: cfield, vobj: vobj, cobj: cobj}
- // 当cobj的参数为函数时,代入args算出值
- for (var key in cobj) {
- if (key === '_data') continue;
- if (cobj[key] instanceof Function) cobj[key] = cobj[key](args);
- }
- // 标记为_hide的属性不展示
- if (cobj._hide)continue;
- if (!cobj._leaf) {
- // 不是叶节点时, 插入展开的标记并继续遍历, 此处可以改成按钮用来添加新项或折叠等
- outstr.push(["| ---- | ---- | ", field, " |
\n"].join(''));
- recursionParse(field, cfield, vobj, cobj);
- } else {
- // 是叶节点时, 调objToTr_渲染
- var leafnode = editor_mode.objToTr_(obj, commentObj, field, cfield, vobj, cobj);
- outstr.push(leafnode[0]);
- guids.push(leafnode[1]);
- }
- }
- }
- // 开始遍历
- recursionParse("", "", obj, commentObj);
- var checkRange = function (cobj, thiseval) {
- if (cobj._range) {
- return eval(cobj._range);
- }
- if (cobj._select) {
- return cobj._select.values.indexOf(thiseval)!==-1;
- }
- if (cobj._bool) {
- return [true,false].indexOf(thiseval)!==-1;
- }
- return true;
- }
- var listen = function (guids) {
- // 每个叶节点的事件绑定
- guids.forEach(function (guid) {
- // tr>td[title=field]
- // >td[title=comment,cobj=cobj:json]
- // >td>div>input[value=thiseval]
- var thisTr = document.getElementById(guid);
- var input = thisTr.children[2].children[0].children[0];
- var field = thisTr.children[0].getAttribute('title');
- var cobj = JSON.parse(thisTr.children[1].getAttribute('cobj'));
- var modeNode = thisTr.parentNode;
- while (!editor_mode._ids.hasOwnProperty(modeNode.getAttribute('id'))) {
- modeNode = modeNode.parentNode;
- }
- input.onchange = function () {
- editor_mode.onmode(editor_mode._ids[modeNode.getAttribute('id')]);
- var thiseval = null;
- if (input.checked != null) input.value = input.checked;
- try {
- thiseval = JSON.parse(input.value);
- } catch (ee) {
- printe(field + ' : ' + ee);
- throw ee;
- }
- if (checkRange(cobj, thiseval)) {
- editor_mode.addAction(['change', field, thiseval]);
- editor_mode.onmode('save');//自动保存 删掉此行的话点保存按钮才会保存
- } else {
- printe(field + ' : 输入的值不合要求,请鼠标放置在注释上查看说明');
- }
- }
- // 双击表格时
- // 正常编辑: 尝试用事件编辑器或多行文本编辑器打开
- // 添加: 在该项的同一级创建一个内容为null新的项, 刷新后生效并可以继续编辑
- // 删除: 删除该项, 刷新后生效
- // 在点击按钮 添加/删除 后,下一次双击将被视为 添加/删除
- var dblclickfunc=function () {
- if(editor_mode.doubleClickMode==='change'){
- if (cobj._type === 'event') editor_blockly.import(guid, {type: cobj._event});
- if (cobj._type === 'textarea') editor_multi.import(guid, {lint: cobj._lint, string: cobj._string});
- }
- if(editor_mode.doubleClickMode==='add'){
- editor_mode.doubleClickMode='change';
- addfunc()
- }
- if(editor_mode.doubleClickMode==='delete'){
- editor_mode.doubleClickMode='change';
- deletefunc()
- }
- }
- input.ondblclick = dblclickfunc
- var doubleClickCheck=[0];
- thisTr.onclick = function(){
- var newClick = new Date().getTime();
- var lastClick = doubleClickCheck.shift();
- doubleClickCheck.push(newClick);
- if(newClick-lastClick<500){
- dblclickfunc()
- }
- }
- var deletefunc=function(){
- editor_mode.onmode(editor_mode._ids[modeNode.getAttribute('id')]);
- if (checkRange(cobj, null)) {
- editor_mode.addAction(['delete', field, undefined]);
- editor_mode.onmode('save');//自动保存 删掉此行的话点保存按钮才会保存
- } else {
- printe(field + ' : 该值不允许为null,无法删除');
- }
- }
- var addfunc=function(){
- editor_mode.onmode(editor_mode._ids[modeNode.getAttribute('id')]);
-
- var mode = document.getElementById('editModeSelect').value;
-
- // 1.输入id
- var newid=prompt('请输入新项的ID(仅公共事件支持中文ID)');
- if (newid == null || newid.length==0) {
- return;
- }
-
- // 检查commentEvents
- if (mode !== 'commonevent') {
- // 2.检查id是否符合规范或与已有id重复
- if (!/^[a-zA-Z0-9_]+$/.test(newid)){
- printe('id不符合规范, 请使用大小写字母数字下划线来构成');
- return;
- }
- }
-
- var conflict=true;
- var basefield=field.replace(/\[[^\[]*\]$/,'');
- if (basefield==="['main']"){
- printe("全塔属性 ~ ['main'] 不允许添加新值");
- return;
- }
- try {
- var baseobj=eval('obj'+basefield);
- conflict=newid in baseobj;
- } catch (ee) {
- // 理论上这里不会发生错误
- printe(ee);
- throw ee;
- }
- if (conflict){
- printe('id已存在, 请直接修改该项的值');
- return;
- }
- // 3.添加
- editor_mode.addAction(['add',basefield+"['"+newid+"']",null]);
- editor_mode.onmode('save');//自动保存 删掉此行的话点保存按钮才会保存
- }
- });
- }
- return {"HTML": outstr.join(''), "guids": guids, "listen": listen};
- }
-
- /**
- * 返回叶节点
形如
- * tr>td[title=field]
- * >td[title=comment,cobj=cobj:json]
- * >td>div>input[value=thiseval]
- * 参数意义在 objToTable_ 中已解释
- * @param {Object} obj
- * @param {Object} commentObj
- * @param {String} field
- * @param {String} cfield
- * @param {Object} vobj
- * @param {Object} cobj
- */
- editor_mode.prototype.objToTr_ = function (obj, commentObj, field, cfield, vobj, cobj) {
- var guid = editor.guid();
- var thiseval = vobj;
- var comment = String(cobj._data);
-
- var charlength = 10;
- // "['a']['b']" => "b"
- var shortField = field.split("']").slice(-2)[0].split("['").slice(-1)[0];
- // 把长度超过 charlength 的字符改成 固定长度+...的形式
- shortField = (shortField.length < charlength ? shortField : shortField.slice(0, charlength) + '...');
-
- // 完整的内容转义后供悬停查看
- var commentHTMLescape = editor.HTMLescape(comment);
- // 把长度超过 charlength 的字符改成 固定长度+...的形式
- var shortCommentHTMLescape = (comment.length < charlength ? commentHTMLescape : editor.HTMLescape(comment.slice(0, charlength)) + '...');
-
- var cobjstr = Object.assign({}, cobj);
- delete cobjstr._data;
- // 把cobj塞到第二个td的[cobj]中, 方便绑定事件时取
- cobjstr = editor.HTMLescape(JSON.stringify(cobjstr));
-
- var outstr = ['
| ', shortField, ' | ',
- '', shortCommentHTMLescape, ' | ',
- '', editor_mode.objToTd_(obj, commentObj, field, cfield, vobj, cobj), ' |
\n',
- ];
- return [outstr.join(''), guid];
- }
-
- editor_mode.prototype.objToTd_ = function (obj, commentObj, field, cfield, vobj, cobj) {
- var thiseval = vobj;
- if (cobj._select) {
- var values = cobj._select.values;
- var outstr = ['');
- return outstr.join('');
- } else if (cobj._input) {
- return ["\n"].join('');
- } else if (cobj._bool) {
- return ["\n"].join('');
- } else {
- var num = 0;//editor_mode.indent(field);
- return ["\n'].join('');
- }
- }
-
editor_mode.prototype.indent = function (field) {
var num = '\t';
if (field.indexOf("['main']") === 0) return 0;
@@ -429,7 +130,7 @@ editor_mode = function (editor) {
//console.log(objs_)
});
//只查询不修改时,内部实现不是异步的,所以可以这么写
- var tableinfo = editor_mode.objToTable_(objs[0], objs[1]);
+ var tableinfo = editor.table.objToTable(objs[0], objs[1]);
document.getElementById('table_3d846fc4_7644_44d1_aa04_433d266a73df').innerHTML = tableinfo.HTML;
tableinfo.listen(tableinfo.guids);
editor.drawPosSelection();
@@ -472,7 +173,7 @@ editor_mode = function (editor) {
});
}
//只查询不修改时,内部实现不是异步的,所以可以这么写
- var tableinfo = editor_mode.objToTable_(objs[0], objs[1]);
+ var tableinfo = editor.table.objToTable(objs[0], objs[1]);
document.getElementById('table_a3f03d4c_55b8_4ef6_b362_b345783acd72').innerHTML = tableinfo.HTML;
tableinfo.listen(tableinfo.guids);
@@ -486,7 +187,7 @@ editor_mode = function (editor) {
//console.log(objs_)
});
//只查询不修改时,内部实现不是异步的,所以可以这么写
- var tableinfo = editor_mode.objToTable_(objs[0], objs[1]);
+ var tableinfo = editor.table.objToTable(objs[0], objs[1]);
document.getElementById('table_4a3b1b09_b2fb_4bdf_b9ab_9f4cdac14c74').innerHTML = tableinfo.HTML;
tableinfo.listen(tableinfo.guids);
if (Boolean(callback)) callback();
@@ -499,7 +200,7 @@ editor_mode = function (editor) {
//console.log(objs_)
});
//只查询不修改时,内部实现不是异步的,所以可以这么写
- var tableinfo = editor_mode.objToTable_(objs[0], objs[1]);
+ var tableinfo = editor.table.objToTable(objs[0], objs[1]);
document.getElementById('table_b6a03e4c_5968_4633_ac40_0dfdd2c9cde5').innerHTML = tableinfo.HTML;
tableinfo.listen(tableinfo.guids);
if (Boolean(callback)) callback();
@@ -512,7 +213,7 @@ editor_mode = function (editor) {
//console.log(objs_)
});
//只查询不修改时,内部实现不是异步的,所以可以这么写
- var tableinfo = editor_mode.objToTable_(objs[0], objs[1]);
+ var tableinfo = editor.table.objToTable(objs[0], objs[1]);
document.getElementById('table_e260a2be_5690_476a_b04e_dacddede78b3').innerHTML = tableinfo.HTML;
tableinfo.listen(tableinfo.guids);
if (Boolean(callback)) callback();
@@ -525,7 +226,7 @@ editor_mode = function (editor) {
//console.log(objs_)
});
//只查询不修改时,内部实现不是异步的,所以可以这么写
- var tableinfo = editor_mode.objToTable_(objs[0], objs[1]);
+ var tableinfo = editor.table.objToTable(objs[0], objs[1]);
document.getElementById('table_b7bf0124_99fd_4af8_ae2f_0017f04a7c7d').innerHTML = tableinfo.HTML;
tableinfo.listen(tableinfo.guids);
if (Boolean(callback)) callback();
@@ -538,7 +239,7 @@ editor_mode = function (editor) {
//console.log(objs_)
});
//只查询不修改时,内部实现不是异步的,所以可以这么写
- var tableinfo = editor_mode.objToTable_(objs[0], objs[1]);
+ var tableinfo = editor.table.objToTable(objs[0], objs[1]);
document.getElementById('table_e2c034ec_47c6_48ae_8db8_4f8f32fea2d6').innerHTML = tableinfo.HTML;
tableinfo.listen(tableinfo.guids);
if (Boolean(callback)) callback();
@@ -773,21 +474,8 @@ editor_mode = function (editor) {
}
selectAppend.onchange();
- var getPixel=function(imgData, x, y) {
- var offset = (x + y * imgData.width) * 4;
- var r = imgData.data[offset+0];
- var g = imgData.data[offset+1];
- var b = imgData.data[offset+2];
- var a = imgData.data[offset+3];
- return [r,g,b,a];
- }
- var setPixel=function(imgData, x, y, rgba) {
- var offset = (x + y * imgData.width) * 4;
- imgData.data[offset+0]=rgba[0];
- imgData.data[offset+1]=rgba[1];
- imgData.data[offset+2]=rgba[2];
- imgData.data[offset+3]=rgba[3];
- }
+ var getPixel=editor.util.getPixel
+ var setPixel=editor.util.setPixel
var autoAdjust = function (image, callback) {
var changed = false;
@@ -946,113 +634,9 @@ editor_mode = function (editor) {
var nimgData=new ImageData(imgData.width,imgData.height);
// ImageData .data 形如一维数组,依次排着每个点的 R(0~255) G(0~255) B(0~255) A(0~255)
var convert=function(rgba,delta){
- var round=Math.round;
- // rgbToHsl hue2rgb hslToRgb from https://github.com/carloscabo/colz.git
- //--------------------------------------------
- // The MIT License (MIT)
- //
- // Copyright (c) 2014 Carlos Cabo
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to deal
- // in the Software without restriction, including without limitation the rights
- // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- // copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in all
- // copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- // SOFTWARE.
- //--------------------------------------------
- // https://github.com/carloscabo/colz/blob/master/public/js/colz.class.js
- var rgbToHsl = function (rgba) {
- var arg, r, g, b, h, s, l, d, max, min;
-
- arg = rgba;
-
- if (typeof arg[0] === 'number') {
- r = arg[0];
- g = arg[1];
- b = arg[2];
- } else {
- r = arg[0][0];
- g = arg[0][1];
- b = arg[0][2];
- }
-
- r /= 255;
- g /= 255;
- b /= 255;
-
- max = Math.max(r, g, b);
- min = Math.min(r, g, b);
- l = (max + min) / 2;
-
- if (max === min) {
- h = s = 0; // achromatic
- } else {
- d = max - min;
- s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
-
- switch (max) {
- case r: h = (g - b) / d + (g < b ? 6 : 0); break;
- case g: h = (b - r) / d + 2; break;
- case b: h = (r - g) / d + 4; break;
- }
-
- h /= 6;
- }
-
- //CARLOS
- h = round(h * 360);
- s = round(s * 100);
- l = round(l * 100);
-
- return [h, s, l];
- }
- //
- var hue2rgb = function (p, q, t) {
- if (t < 0) { t += 1; }
- if (t > 1) { t -= 1; }
- if (t < 1 / 6) { return p + (q - p) * 6 * t; }
- if (t < 1 / 2) { return q; }
- if (t < 2 / 3) { return p + (q - p) * (2 / 3 - t) * 6; }
- return p;
- }
- var hslToRgb = function (hsl) {
- var arg, r, g, b, h, s, l, q, p;
-
- arg = hsl;
-
- if (typeof arg[0] === 'number') {
- h = arg[0] / 360;
- s = arg[1] / 100;
- l = arg[2] / 100;
- } else {
- h = arg[0][0] / 360;
- s = arg[0][1] / 100;
- l = arg[0][2] / 100;
- }
-
- if (s === 0) {
- r = g = b = l; // achromatic
- } else {
-
- q = l < 0.5 ? l * (1 + s) : l + s - l * s;
- p = 2 * l - q;
- r = hue2rgb(p, q, h + 1 / 3);
- g = hue2rgb(p, q, h);
- b = hue2rgb(p, q, h - 1 / 3);
- }
- return [round(r * 255), round(g * 255), round(b * 255)];
- }
+ var rgbToHsl = editor.util.rgbToHsl
+ var hue2rgb = editor.util.hue2rgb
+ var hslToRgb = editor.util.hslToRgb
//
var hsl=rgbToHsl(rgba)
hsl[0]=(hsl[0]+delta)%360
diff --git a/_server/editor_multi.js b/_server/editor_multi.js
index 5125c4e3..9ccd00c9 100644
--- a/_server/editor_multi.js
+++ b/_server/editor_multi.js
@@ -103,7 +103,7 @@ editor_multi = function () {
var tmap = {};
var tstr = JSON.stringify(tobj, function (k, v) {
if (typeof(v) === typeof('') && v.slice(0, 8) === 'function') {
- var id_ = editor.guid();
+ var id_ = editor.util.guid();
tmap[id_] = v.toString();
return id_;
} else return v
@@ -146,7 +146,7 @@ editor_multi = function () {
var tmap = {};
var tstr = JSON.stringify(tobj, function (k, v) {
if (v instanceof Function) {
- var id_ = editor.guid();
+ var id_ = editor.util.guid();
tmap[id_] = v.toString();
return id_;
} else return v
diff --git a/_server/editor_table.js b/_server/editor_table.js
new file mode 100644
index 00000000..09009ab2
--- /dev/null
+++ b/_server/editor_table.js
@@ -0,0 +1,382 @@
+editor_table_wrapper = function (editor) {
+
+ editor_table = function () {
+
+ }
+
+ /////////////////////////////////////////////////////////////////////////////
+ // HTML模板
+
+ editor_table.prototype.select = function (value, values) {
+ return `\n`
+ }
+ editor_table.prototype.option = function (value) {
+ return `\n`
+ }
+ editor_table.prototype.text = function (value) {
+ return `\n`
+ }
+ editor_table.prototype.checkbox = function (value) {
+ return `\n`
+ }
+ editor_table.prototype.textarea = function (value, indent) {
+ return `\n`
+ }
+
+ editor_table.prototype.title = function () {
+ return `\n| 条目 | 注释 | 值 |
\n`
+ }
+
+ editor_table.prototype.gap = function (field) {
+ return `| ---- | ---- | ${field} |
\n`
+ }
+
+ editor_table.prototype.tr = function (guid, field, shortField, commentHTMLescape, cobjstr, shortCommentHTMLescape, tdstr) {
+ return `
+ | ${shortField} |
+ ${shortCommentHTMLescape} |
+ ${tdstr} |
+
\n`
+ }
+
+
+ /////////////////////////////////////////////////////////////////////////////
+ // 表格生成的控制
+
+ /**
+ * 注释对象的默认值
+ */
+ editor_table.prototype.defaultcobj = {
+ // 默认是文本域
+ _type: 'textarea',
+ _data: '',
+ _string: function (args) {//object~[field,cfield,vobj,cobj]
+ var thiseval = args.vobj;
+ return (typeof (thiseval) === typeof ('')) && thiseval[0] === '"';
+ },
+ // 默认情况下 非对象和数组的视为叶节点
+ _leaf: function (args) {//object~[field,cfield,vobj,cobj]
+ var thiseval = args.vobj;
+ if (thiseval == null || thiseval == undefined) return true;//null,undefined
+ if (typeof (thiseval) === typeof ('')) return true;//字符串
+ if (Object.keys(thiseval).length === 0) return true;//数字,true,false,空数组,空对象
+ return false;
+ },
+ }
+
+ /**
+ * 把来自数据文件的obj和来自*comment.js的commentObj组装成表格
+ * commentObj在无视['_data']的意义下与obj同形
+ * 即: commentObj['_data']['a']['_data']['b'] 与 obj['a']['b'] 是对应的
+ * 在此意义下, 两者的结构是一致的
+ * 在commentObj没有被定义的obj的分支, 会取defaultcobj作为默认值
+ * 因此在深度优先遍历时,维护
+ * field="['a']['b']"
+ * cfield="['_data']['a']['_data']['b']"
+ * vobj=obj['a']['b']
+ * cobj=commentObj['_data']['a']['_data']['b']
+ * cobj
+ * cobj = Object.assign({}, defaultcobj, pcobj['_data'][ii])
+ * 每一项若未定义,就从defaultcobj中取
+ * 当其是函数不是具体值时,把args = {field: field, cfield: cfield, vobj: vobj, cobj: cobj}代入算出该值
+ * 得到的叶节点的结构如下
+ * tr>td[title=field]
+ * >td[title=comment,cobj=cobj:json]
+ * >td>div>input[value=thiseval]
+ * 返回结果
+ * 返回一个对象, 假设被命名为tableinfo
+ * 在把一个 table 的 innerHTML 赋值为 tableinfo.HTML 后
+ * 再调 tableinfo.listen(tableinfo.guids) 进行绑定事件
+ * @param {Object} obj
+ * @param {Object} commentObj
+ * @returns {{"HTML":String,"guids":String[],"listen":Function}}
+ */
+ editor_table.prototype.objToTable = function (obj, commentObj) {
+ // 表格抬头
+ var outstr = [editor.table.title()];
+ var guids = [];
+ var defaultcobj = this.defaultcobj
+ /**
+ * 深度优先遍历, p*即为父节点的四个属性
+ * @param {String} pfield
+ * @param {String} pcfield
+ * @param {Object} pvobj
+ * @param {Object} pcobj
+ */
+ var recursionParse = function (pfield, pcfield, pvobj, pcobj) {
+ var keysForTableOrder = {};
+ var voidMark = {};
+ // 1. 按照pcobj排序生成
+ if (pcobj && pcobj['_data']) {
+ for (var ii in pcobj['_data']) keysForTableOrder[ii] = voidMark;
+ }
+ // 2. 对每个pvobj且不在pcobj的,再添加到最后
+ keysForTableOrder = Object.assign(keysForTableOrder, pvobj)
+ for (var ii in keysForTableOrder) {
+ // 3. 对于pcobj有但是pvobj中没有的, 弹出提示, (正常情况下editor_file会补全成null)
+ // 事实上能执行到这一步工程没崩掉打不开,就继续吧..
+ if (keysForTableOrder[ii] === voidMark) {
+ if (typeof id_815975ad_ee6f_4684_aac7_397b7e392702 === "undefined") {
+ alert('comment和data不匹配,请在群 HTML5造塔技术交流群 959329661 内反馈')
+ console.error('comment和data不匹配,请在群 HTML5造塔技术交流群 959329661 内反馈')
+ id_815975ad_ee6f_4684_aac7_397b7e392702 = 1;
+ }
+ pvobj[ii] = null;
+ }
+ var field = pfield + "['" + ii + "']";
+ var cfield = pcfield + "['_data']['" + ii + "']";
+ var vobj = pvobj[ii];
+ var cobj = null;
+ if (pcobj && pcobj['_data'] && pcobj['_data'][ii]) {
+ // cobj存在时直接取
+ cobj = Object.assign({}, defaultcobj, pcobj['_data'][ii]);
+ } else {
+ // 当其函数时代入参数算出cobj, 不存在时只取defaultcobj
+ if (pcobj && (pcobj['_data'] instanceof Function)) cobj = Object.assign({}, defaultcobj, pcobj['_data'](ii));
+ else cobj = Object.assign({}, defaultcobj);
+ }
+ var args = { field: field, cfield: cfield, vobj: vobj, cobj: cobj }
+ // 当cobj的参数为函数时,代入args算出值
+ for (var key in cobj) {
+ if (key === '_data') continue;
+ if (cobj[key] instanceof Function) cobj[key] = cobj[key](args);
+ }
+ // 标记为_hide的属性不展示
+ if (cobj._hide) continue;
+ if (!cobj._leaf) {
+ // 不是叶节点时, 插入展开的标记并继续遍历, 此处可以改成按钮用来添加新项或折叠等
+ outstr.push(editor.table.gap(field));
+ recursionParse(field, cfield, vobj, cobj);
+ } else {
+ // 是叶节点时, 调objToTr_渲染
+ var leafnode = editor.table.objToTr(obj, commentObj, field, cfield, vobj, cobj);
+ outstr.push(leafnode[0]);
+ guids.push(leafnode[1]);
+ }
+ }
+ }
+ // 开始遍历
+ recursionParse("", "", obj, commentObj);
+
+ var listen = function (guids) {
+ // 每个叶节点的事件绑定
+ guids.forEach(editor.table.guidListen);
+ }
+ return { "HTML": outstr.join(''), "guids": guids, "listen": listen };
+ }
+
+ /**
+ * 返回叶节点
形如
+ * tr>td[title=field]
+ * >td[title=comment,cobj=cobj:json]
+ * >td>div>input[value=thiseval]
+ * 参数意义在 objToTable 中已解释
+ * @param {Object} obj
+ * @param {Object} commentObj
+ * @param {String} field
+ * @param {String} cfield
+ * @param {Object} vobj
+ * @param {Object} cobj
+ */
+ editor_table.prototype.objToTr = function (obj, commentObj, field, cfield, vobj, cobj) {
+ var guid = editor.util.guid();
+ var thiseval = vobj;
+ var comment = String(cobj._data);
+
+ var charlength = 10;
+ // "['a']['b']" => "b"
+ var shortField = field.split("']").slice(-2)[0].split("['").slice(-1)[0];
+ // 把长度超过 charlength 的字符改成 固定长度+...的形式
+ shortField = (shortField.length < charlength ? shortField : shortField.slice(0, charlength) + '...');
+
+ // 完整的内容转义后供悬停查看
+ var commentHTMLescape = editor.util.HTMLescape(comment);
+ // 把长度超过 charlength 的字符改成 固定长度+...的形式
+ var shortCommentHTMLescape = (comment.length < charlength ? commentHTMLescape : editor.util.HTMLescape(comment.slice(0, charlength)) + '...');
+
+ var cobjstr = Object.assign({}, cobj);
+ delete cobjstr._data;
+ // 把cobj塞到第二个td的[cobj]中, 方便绑定事件时取
+ cobjstr = editor.util.HTMLescape(JSON.stringify(cobjstr));
+
+ var tdstr = editor.table.objToTd(obj, commentObj, field, cfield, vobj, cobj)
+ var outstr = editor.table.tr(guid, field, shortField, commentHTMLescape, cobjstr, shortCommentHTMLescape, tdstr)
+ return [outstr, guid];
+ }
+
+ editor_table.prototype.objToTd = function (obj, commentObj, field, cfield, vobj, cobj) {
+ var thiseval = vobj;
+ if (cobj._select) {
+ var values = cobj._select.values;
+ return editor.table.select(thiseval, values);
+ } else if (cobj._input) {
+ return editor.table.text(thiseval);
+ } else if (cobj._bool) {
+ return editor.table.checkbox(thiseval);
+ } else {
+ var indent = 0;
+ return editor.table.textarea(thiseval, indent);
+ }
+ }
+
+ /////////////////////////////////////////////////////////////////////////////
+ // 表格的用户交互
+
+ /**
+ * 检查一个值是否允许被设置为当前输入
+ * @param {Object} cobj
+ * @param {*} thiseval
+ */
+ editor_table.prototype.checkRange = function (cobj, thiseval) {
+ if (cobj._range) {
+ return eval(cobj._range);
+ }
+ if (cobj._select) {
+ return cobj._select.values.indexOf(thiseval) !== -1;
+ }
+ if (cobj._bool) {
+ return [true, false].indexOf(thiseval) !== -1;
+ }
+ return true;
+ }
+
+ /**
+ * 监听一个guid对应的表格项
+ * @param {String} guid
+ */
+ editor_table.prototype.guidListen = function (guid) {
+ // tr>td[title=field]
+ // >td[title=comment,cobj=cobj:json]
+ // >td>div>input[value=thiseval]
+ var thisTr = document.getElementById(guid);
+ var input = thisTr.children[2].children[0].children[0];
+ var field = thisTr.children[0].getAttribute('title');
+ var cobj = JSON.parse(thisTr.children[1].getAttribute('cobj'));
+ var modeNode = thisTr.parentNode;
+ while (!editor_mode._ids.hasOwnProperty(modeNode.getAttribute('id'))) {
+ modeNode = modeNode.parentNode;
+ }
+ input.onchange = function () {
+ editor.table.onchange(guid, thisTr, input, field, cobj, modeNode)
+ }
+ // 用检测两次单击的方式来实现双击(以支持手机端的双击)
+ var doubleClickCheck = [0];
+ thisTr.onclick = function () {
+ var newClick = new Date().getTime();
+ var lastClick = doubleClickCheck.shift();
+ doubleClickCheck.push(newClick);
+ if (newClick - lastClick < 500) {
+ editor.table.dblclickfunc(guid, thisTr, input, field, cobj, modeNode)
+ }
+ }
+ }
+
+ /**
+ * 表格的值变化时
+ */
+ editor_table.prototype.onchange = function (guid, thisTr, input, field, cobj, modeNode) {
+ editor_mode.onmode(editor_mode._ids[modeNode.getAttribute('id')]);
+ var thiseval = null;
+ if (input.checked != null) input.value = input.checked;
+ try {
+ thiseval = JSON.parse(input.value);
+ } catch (ee) {
+ printe(field + ' : ' + ee);
+ throw ee;
+ }
+ if (editor.table.checkRange(cobj, thiseval)) {
+ editor_mode.addAction(['change', field, thiseval]);
+ editor_mode.onmode('save');//自动保存 删掉此行的话点保存按钮才会保存
+ } else {
+ printe(field + ' : 输入的值不合要求,请鼠标放置在注释上查看说明');
+ }
+ }
+
+ /**
+ * 双击表格时
+ * 正常编辑: 尝试用事件编辑器或多行文本编辑器打开
+ * 添加: 在该项的同一级创建一个内容为null新的项, 刷新后生效并可以继续编辑
+ * 删除: 删除该项, 刷新后生效
+ * 在点击按钮 添加/删除 后,下一次双击将被视为 添加/删除
+ */
+ editor_table.prototype.dblclickfunc = function (guid, thisTr, input, field, cobj, modeNode) {
+ if (editor_mode.doubleClickMode === 'change') {
+ if (cobj._type === 'event') editor_blockly.import(guid, { type: cobj._event });
+ if (cobj._type === 'textarea') editor_multi.import(guid, { lint: cobj._lint, string: cobj._string });
+ } else if (editor_mode.doubleClickMode === 'add') {
+ editor_mode.doubleClickMode = 'change';
+ editor.table.addfunc(guid, thisTr, input, field, cobj, modeNode)
+ } else if (editor_mode.doubleClickMode === 'delete') {
+ editor_mode.doubleClickMode = 'change';
+ editor.table.deletefunc(guid, thisTr, input, field, cobj, modeNode)
+ }
+ }
+
+ /**
+ * 删除表格项
+ */
+ editor_table.prototype.deletefunc = function (guid, thisTr, input, field, cobj, modeNode) {
+ editor_mode.onmode(editor_mode._ids[modeNode.getAttribute('id')]);
+ if (editor.table.checkRange(cobj, null)) {
+ editor_mode.addAction(['delete', field, undefined]);
+ editor_mode.onmode('save');//自动保存 删掉此行的话点保存按钮才会保存
+ } else {
+ printe(field + ' : 该值不允许为null,无法删除');
+ }
+ }
+
+ /**
+ * 添加表格项
+ */
+ editor_table.prototype.addfunc = function (guid, thisTr, input, field, cobj, modeNode) {
+ editor_mode.onmode(editor_mode._ids[modeNode.getAttribute('id')]);
+
+ var mode = document.getElementById('editModeSelect').value;
+
+ // 1.输入id
+ var newid = prompt('请输入新项的ID(仅公共事件支持中文ID)');
+ if (newid == null || newid.length == 0) {
+ return;
+ }
+
+ // 检查commentEvents
+ if (mode !== 'commonevent') {
+ // 2.检查id是否符合规范或与已有id重复
+ if (!/^[a-zA-Z0-9_]+$/.test(newid)) {
+ printe('id不符合规范, 请使用大小写字母数字下划线来构成');
+ return;
+ }
+ }
+
+ var conflict = true;
+ var basefield = field.replace(/\[[^\[]*\]$/, '');
+ if (basefield === "['main']") {
+ printe("全塔属性 ~ ['main'] 不允许添加新值");
+ return;
+ }
+ try {
+ var baseobj = eval('obj' + basefield);
+ conflict = newid in baseobj;
+ } catch (ee) {
+ // 理论上这里不会发生错误
+ printe(ee);
+ throw ee;
+ }
+ if (conflict) {
+ printe('id已存在, 请直接修改该项的值');
+ return;
+ }
+ // 3.添加
+ editor_mode.addAction(['add', basefield + "['" + newid + "']", null]);
+ editor_mode.onmode('save');//自动保存 删掉此行的话点保存按钮才会保存
+ }
+
+ /////////////////////////////////////////////////////////////////////////////
+ editor.constructor.prototype.table = new editor_table();
+}
+//editor_table_wrapper(editor);
\ No newline at end of file
diff --git a/_server/editor_util.js b/_server/editor_util.js
new file mode 100644
index 00000000..bab29837
--- /dev/null
+++ b/_server/editor_util.js
@@ -0,0 +1,150 @@
+editor_util_wrapper = function (editor) {
+
+ editor_util = function () {
+
+ }
+
+ editor_util.prototype.guid = function () {
+ return 'id_' + 'xxxxxxxx_xxxx_4xxx_yxxx_xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
+ var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
+ return v.toString(16);
+ });
+ }
+
+ editor_util.prototype.HTMLescape = function (str_) {
+ return String(str_).split('').map(function (v) {
+ return '' + v.charCodeAt(0) + ';'
+ }).join('');
+ }
+
+ editor_util.prototype.getPixel = function (imgData, x, y) {
+ var offset = (x + y * imgData.width) * 4;
+ var r = imgData.data[offset + 0];
+ var g = imgData.data[offset + 1];
+ var b = imgData.data[offset + 2];
+ var a = imgData.data[offset + 3];
+ return [r, g, b, a];
+ }
+
+ editor_util.prototype.setPixel = function (imgData, x, y, rgba) {
+ var offset = (x + y * imgData.width) * 4;
+ imgData.data[offset + 0] = rgba[0];
+ imgData.data[offset + 1] = rgba[1];
+ imgData.data[offset + 2] = rgba[2];
+ imgData.data[offset + 3] = rgba[3];
+ }
+
+ // rgbToHsl hue2rgb hslToRgb from https://github.com/carloscabo/colz.git
+ //--------------------------------------------
+ // The MIT License (MIT)
+ //
+ // Copyright (c) 2014 Carlos Cabo
+ //
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
+ // of this software and associated documentation files (the "Software"), to deal
+ // in the Software without restriction, including without limitation the rights
+ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ // copies of the Software, and to permit persons to whom the Software is
+ // furnished to do so, subject to the following conditions:
+ //
+ // The above copyright notice and this permission notice shall be included in all
+ // copies or substantial portions of the Software.
+ //
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ // SOFTWARE.
+ //--------------------------------------------
+ // https://github.com/carloscabo/colz/blob/master/public/js/colz.class.js
+ var round=Math.round;
+ var rgbToHsl = function (rgba) {
+ var arg, r, g, b, h, s, l, d, max, min;
+
+ arg = rgba;
+
+ if (typeof arg[0] === 'number') {
+ r = arg[0];
+ g = arg[1];
+ b = arg[2];
+ } else {
+ r = arg[0][0];
+ g = arg[0][1];
+ b = arg[0][2];
+ }
+
+ r /= 255;
+ g /= 255;
+ b /= 255;
+
+ max = Math.max(r, g, b);
+ min = Math.min(r, g, b);
+ l = (max + min) / 2;
+
+ if (max === min) {
+ h = s = 0; // achromatic
+ } else {
+ d = max - min;
+ s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
+
+ switch (max) {
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+
+ h /= 6;
+ }
+
+ //CARLOS
+ h = round(h * 360);
+ s = round(s * 100);
+ l = round(l * 100);
+
+ return [h, s, l];
+ }
+ //
+ var hue2rgb = function (p, q, t) {
+ if (t < 0) { t += 1; }
+ if (t > 1) { t -= 1; }
+ if (t < 1 / 6) { return p + (q - p) * 6 * t; }
+ if (t < 1 / 2) { return q; }
+ if (t < 2 / 3) { return p + (q - p) * (2 / 3 - t) * 6; }
+ return p;
+ }
+ var hslToRgb = function (hsl) {
+ var arg, r, g, b, h, s, l, q, p;
+
+ arg = hsl;
+
+ if (typeof arg[0] === 'number') {
+ h = arg[0] / 360;
+ s = arg[1] / 100;
+ l = arg[2] / 100;
+ } else {
+ h = arg[0][0] / 360;
+ s = arg[0][1] / 100;
+ l = arg[0][2] / 100;
+ }
+
+ if (s === 0) {
+ r = g = b = l; // achromatic
+ } else {
+
+ q = l < 0.5 ? l * (1 + s) : l + s - l * s;
+ p = 2 * l - q;
+ r = hue2rgb(p, q, h + 1 / 3);
+ g = hue2rgb(p, q, h);
+ b = hue2rgb(p, q, h - 1 / 3);
+ }
+ return [round(r * 255), round(g * 255), round(b * 255)];
+ }
+ editor_util.prototype.rgbToHsl=rgbToHsl
+ editor_util.prototype.hue2rgb=hue2rgb
+ editor_util.prototype.hslToRgb=hslToRgb
+
+ editor.constructor.prototype.util = new editor_util();
+}
+//editor_util_wrapper(editor);
\ No newline at end of file
diff --git a/_server/refactoring.md b/_server/refactoring.md
new file mode 100644
index 00000000..5d92d0f4
--- /dev/null
+++ b/_server/refactoring.md
@@ -0,0 +1,89 @@
+# 重构
+
++ [ ] 按功能拆分文件
++ [ ] 左侧页面模块化, 方便添加
++ [ ] 不同的模式的文件操作尽可能模块化
+
+---
+
+文件结构
+
++ [x] editor_blockly 图块化事件编辑器, 基本不改动
++ [x] editor_multi 多行文本编辑器, 基本不改动
++ [ ] editor_table 处理表格的生成, 及其响应的事件, 从原editor\_mode中分离
++ [ ] editor_file 调用fs.js编辑文件, 把原editor\_file模块化
++ [ ] editor_game 处理来自core的数据, 导入为editor的数据, 从原editor中分离
++ [ ] editor_util 生成guid等函数, 从editor分离
++ [ ] editor 执行初始化流程加组合各组件
+
++ [ ] 原editor_mode 移除
++ [ ] 原vm 移除
+
+---
+
+对象结构
+
+```
+editor: {
+ __proto__: {
+ blockly: 组件
+ multi: 组件
+ file: 组件
+ table: 组件
+ util: 组件
+ }
+ game: 来自游戏的数据
+ config: 编辑器配置
+ mode: 当前的模式(左侧的选择)
+ map: 当前编辑层的地图
+ ...
+}
+```
+
+---
+
+某些注意到的点
+
++ 地图的编辑与其他(如全塔属性和楼层属性), 现在的文件操作的模式是完全不同的
+ 楼层文件的储存与其他不同
+
++ functions和plugins的借助JSON.stringify的replacer特殊处理
+
++ 目前editor.map中储存的是info\