Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Z
zeroing-editor
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
劳工
zeroing-editor
Commits
aa70b179
Commit
aa70b179
authored
Nov 29, 2019
by
任建锋
Browse files
Options
Browse Files
Download
Plain Diff
--
parents
e21945d8
4be75099
Changes
24
Hide whitespace changes
Inline
Side-by-side
Showing
24 changed files
with
537 additions
and
215 deletions
+537
-215
config_20191129114418.js
.history/src/config_20191129114418.js
+40
-0
config_20191129114434.js
.history/src/config_20191129114434.js
+37
-0
psd瘦身.jsx
jsx/psd瘦身.jsx
+0
-0
自动拆分.jsx
jsx/自动拆分.jsx
+62
-0
自动整理.jsx
jsx/自动整理.jsx
+80
-0
common.js
src/api/common.js
+25
-7
project.js
src/api/project.js
+26
-0
config.js
src/config.js
+1
-3
en.json
src/locales/en.json
+8
-1
zh-CN.json
src/locales/zh-CN.json
+8
-1
env.js
src/store/modules/env.js
+1
-1
project.js
src/store/modules/project.js
+47
-4
editor.scss
src/themes/light/editor.scss
+4
-0
playground.scss
src/themes/light/playground.scss
+4
-0
index.js
src/utils/index.js
+15
-0
Assets.vue
src/views/Editor/Assets.vue
+16
-31
ToolBar.vue
src/views/Editor/ToolBar.vue
+6
-3
UploadIndicator.vue
src/views/Editor/ToolBar/UploadIndicator.vue
+34
-0
Views.vue
src/views/Editor/Views.vue
+115
-110
DynamicInput.vue
src/views/Editor/behavior-editor/inputs/DynamicInput.vue
+1
-1
BehaviorEditorDialog.vue
src/views/Editor/dialogs/BehaviorEditorDialog.vue
+2
-2
Home.vue
src/views/Home.vue
+2
-2
DuplicateProjectDialog.vue
src/views/Home/DuplicateProjectDialog.vue
+3
-1
自动合并.jsx
自动合并.jsx
+0
-48
No files found.
.history/src/config_20191129114418.js
0 → 100644
View file @
aa70b179
/**
* Created by rockyl on 2019-09-19.
*/
export
let
API_HOST
;
if
(
process
.
env
.
NODE_ENV
===
'development'
)
{
//API_HOST = 'http://10.10.95.74:7777';
//API_HOST = 'http://10.10.94.134:7777';
//API_HOST = 'http://localhost:3002';
API_HOST
=
window
.
__data
.
apiHost
;
<<<<<<<
HEAD
=======
//API_HOST = '';
>>>>>>>
4
be75099e23b6946a0ba4a754861b69a32bad830
}
else
{
API_HOST
=
window
.
__data
.
apiHost
;
}
if
(
API_HOST
[
API_HOST
.
length
-
1
]
===
'/'
)
{
API_HOST
=
API_HOST
.
substr
(
0
,
API_HOST
.
length
-
1
);
}
export
const
SSO_VERIFY_PAGE_URL
=
'/sso/logout'
;
export
const
DOCK_POINT_OFFSET
=
4
;
//文件类型图标 t表示展示缩略图
export
const
fileTypeIcon
=
{
''
:
'file-empty'
,
'.txt'
:
'file-text'
,
'.json'
:
'file-text'
,
'.zip'
:
'file-zip'
,
'.fnt'
:
'file-font'
,
'.jpg'
:
't'
,
'.jpeg'
:
't'
,
'.png'
:
't'
,
'.gif'
:
't'
,
'.svg'
:
't'
,
};
.history/src/config_20191129114434.js
0 → 100644
View file @
aa70b179
/**
* Created by rockyl on 2019-09-19.
*/
export
let
API_HOST
;
if
(
process
.
env
.
NODE_ENV
===
'development'
)
{
//API_HOST = 'http://10.10.95.74:7777';
//API_HOST = 'http://10.10.94.134:7777';
//API_HOST = 'http://localhost:3002';
API_HOST
=
window
.
__data
.
apiHost
;
//API_HOST = '';
}
else
{
API_HOST
=
window
.
__data
.
apiHost
;
}
if
(
API_HOST
[
API_HOST
.
length
-
1
]
===
'/'
)
{
API_HOST
=
API_HOST
.
substr
(
0
,
API_HOST
.
length
-
1
);
}
export
const
SSO_VERIFY_PAGE_URL
=
'/sso/logout'
;
export
const
DOCK_POINT_OFFSET
=
4
;
//文件类型图标 t表示展示缩略图
export
const
fileTypeIcon
=
{
''
:
'file-empty'
,
'.txt'
:
'file-text'
,
'.json'
:
'file-text'
,
'.zip'
:
'file-zip'
,
'.fnt'
:
'file-font'
,
'.jpg'
:
't'
,
'.jpeg'
:
't'
,
'.png'
:
't'
,
'.gif'
:
't'
,
'.svg'
:
't'
,
};
psd瘦身.jsx
→
jsx/
psd瘦身.jsx
View file @
aa70b179
File moved
jsx/自动拆分.jsx
0 → 100644
View file @
aa70b179
/**
* Created by rockyl on 2019-11-25.
*/
var
curDocument
=
app
.
activeDocument
;
//alert(ShowObjProperty2(curDocument.activeLayer).attributes);
//alert(ShowObjProperty2(oldDocument.activeLayer).methods);
for
(
var
i
=
0
;
i
<
curDocument
.
layers
.
length
;
i
++
)
{
var
layer
=
curDocument
.
layers
[
i
];
if
(
!
layer
.
name
.
match
(
/__e$/
))
{
duplicateToNewDocument
(
layer
);
}
}
function
createDocument
(
width
,
height
,
docName
)
{
//定义一个变量[resolution],表示新文档的分辨率。
var
resolution
=
72
;
//定义一个变量[mode],表示新文档的颜色模式。
var
mode
=
NewDocumentMode
.
RGB
;
//定义一个变量[initialFill],表示新文档的默认背景填充颜色。
var
initialFill
=
DocumentFill
.
TRANSPARENT
;
//定义一个变量[pixelAspectRatio],用来设置新文档的像素比率。
var
pixelAspectRatio
=
1
;
//使用[Documents.add]命令创建一个新文档,将设置好的参数放在[add]方法里面。
var
document
=
app
.
documents
.
add
(
width
,
height
,
resolution
,
docName
,
mode
,
initialFill
,
pixelAspectRatio
);
return
document
;
}
function
duplicateToNewDocument
(
layer
)
{
var
document
=
createDocument
(
curDocument
.
width
,
curDocument
.
height
,
layer
.
name
);
app
.
activeDocument
=
curDocument
;
layer
.
duplicate
(
document
,
ElementPlacement
.
PLACEATBEGINNING
);
}
function
ShowObjProperty2
(
obj
)
{
// 用来保存所有的属性名称和值
var
attributes
=
''
;
var
methods
=
''
;
// 开始遍历
for
(
var
p
in
obj
)
{
// 方法
if
(
typeof
(
obj
[
p
])
===
"function"
)
{
methods
+=
'属性:'
+
p
+
'
\
r
\
n'
// obj[p]();
}
else
{
// p 为属性名称,obj[p]为对应属性的值
attributes
+=
'方法:'
+
p
+
" = "
+
obj
[
p
]
+
"
\
r
\n
"
;
}
}
// 最后显示所有的属性
return
{
attributes
:
attributes
,
methods
:
methods
}
}
jsx/自动整理.jsx
0 → 100644
View file @
aa70b179
/**
* Created by rockyl on 2019-11-25.
*/
var
mergeFlagReg
=
/__m$/
;
var
excludeFlagReg
=
/__e$/
;
var
extName
=
'.psd'
;
var
oldDocument
=
app
.
activeDocument
;
var
mergeLayers
=
[];
var
document
=
oldDocument
.
duplicate
(
oldDocument
.
name
.
replace
(
extName
,
''
)
+
'-合并'
+
extName
,
0
);
function
traverse
(
layer
,
callback
)
{
if
(
layer
.
layers
)
{
for
(
var
i
=
0
,
li
=
layer
.
layers
.
length
;
i
<
li
;
i
++
)
{
var
childLayer
=
layer
.
layers
[
i
];
var
action
=
callback
(
childLayer
);
switch
(
action
)
{
case
0
:
traverse
(
childLayer
,
callback
);
break
;
case
2
:
i
--
;
li
--
;
break
;
}
}
}
}
function
deleteDocumentAncestorsMetadata
()
{
whatApp
=
String
(
app
.
name
);
//String version of the app name
if
(
whatApp
.
search
(
"Photoshop"
)
>
0
)
{
//Check for photoshop specifically, or this will cause errors
//Function Scrubs Document Ancestors from Files
if
(
!
documents
.
length
)
{
alert
(
"There are no open documents. Please open a file to run this script."
)
return
;
}
if
(
ExternalObject
.
AdobeXMPScript
==
undefined
)
ExternalObject
.
AdobeXMPScript
=
new
ExternalObject
(
"lib:AdobeXMPScript"
);
var
xmp
=
new
XMPMeta
(
activeDocument
.
xmpMetadata
.
rawData
);
// Begone foul Document Ancestors!
xmp
.
deleteProperty
(
XMPConst
.
NS_PHOTOSHOP
,
"DocumentAncestors"
);
app
.
activeDocument
.
xmpMetadata
.
rawData
=
xmp
.
serialize
();
}
}
function
execute
(
document
)
{
traverse
(
document
,
function
(
layer
)
{
if
(
layer
.
name
.
match
(
mergeFlagReg
))
{
document
.
activeLayer
=
layer
;
var
newName
=
layer
.
name
.
replace
(
mergeFlagReg
,
''
);
layer
.
name
=
newName
;
mergeLayers
.
push
(
newName
);
layer
.
merge
();
return
1
;
}
else
if
(
layer
.
name
.
match
(
excludeFlagReg
))
{
layer
.
remove
();
return
2
;
}
return
0
;
});
deleteDocumentAncestorsMetadata
();
document
.
crop
([
0
,
0
,
oldDocument
.
width
,
oldDocument
.
height
],
0
);
/*if (mergeLayers.length > 0) {
alert('合并的图层有: ' + mergeLayers.join(','));
} else {
alert('没有图层被合并');
}*/
alert
(
'整理完成'
);
}
execute
(
document
);
src/api/common.js
View file @
aa70b179
...
@@ -36,12 +36,27 @@ export async function fetchApi(uri, {params, method = 'get', contentType = 'json
...
@@ -36,12 +36,27 @@ export async function fetchApi(uri, {params, method = 'get', contentType = 'json
};
};
if
(
params
)
{
if
(
params
)
{
if
(
method
.
toLowerCase
()
===
'post'
)
{
if
(
method
.
toLowerCase
()
===
'post'
)
{
if
(
contentType
===
'form'
)
{
switch
(
contentType
){
options
.
headers
[
'Content-Type'
]
=
'application/x-www-form-urlencoded'
;
case
'form-data'
:
options
.
body
=
stringify
(
params
);
let
formData
=
new
FormData
();
}
else
if
(
contentType
===
'json'
)
{
for
(
let
key
in
params
)
{
options
.
headers
[
'Content-Type'
]
=
'application/json'
;
let
value
=
params
[
key
];
options
.
body
=
JSON
.
stringify
(
params
);
if
(
value
instanceof
File
){
formData
.
append
(
key
,
value
,
value
.
name
);
}
else
{
formData
.
append
(
key
,
value
);
}
}
options
.
body
=
formData
;
break
;
case
'form'
:
options
.
headers
[
'Content-Type'
]
=
'application/x-www-form-urlencoded'
;
options
.
body
=
stringify
(
params
);
break
;
case
'json'
:
options
.
headers
[
'Content-Type'
]
=
'application/json'
;
options
.
body
=
JSON
.
stringify
(
params
);
break
;
}
}
}
else
{
}
else
{
url
+=
(
url
.
indexOf
(
'?'
)
<
0
?
'?'
:
''
)
+
(
url
.
endsWith
(
'&'
)
?
''
:
'&'
)
+
stringify
(
params
);
url
+=
(
url
.
indexOf
(
'?'
)
<
0
?
'?'
:
''
)
+
(
url
.
endsWith
(
'&'
)
?
''
:
'&'
)
+
stringify
(
params
);
...
@@ -49,6 +64,9 @@ export async function fetchApi(uri, {params, method = 'get', contentType = 'json
...
@@ -49,6 +64,9 @@ export async function fetchApi(uri, {params, method = 'get', contentType = 'json
}
}
const
response
=
await
fetch
(
url
,
options
);
const
response
=
await
fetch
(
url
,
options
);
if
(
response
.
status
===
401
)
{
location
.
href
=
'/admin/permission'
;
}
const
jsonObj
=
await
response
.
json
();
const
jsonObj
=
await
response
.
json
();
//console.log(jsonObj);
//console.log(jsonObj);
...
@@ -57,4 +75,4 @@ export async function fetchApi(uri, {params, method = 'get', contentType = 'json
...
@@ -57,4 +75,4 @@ export async function fetchApi(uri, {params, method = 'get', contentType = 'json
}
}
throw
new
ApiError
(
'call api failed'
,
jsonObj
.
code
,
errMessage
);
throw
new
ApiError
(
'call api failed'
,
jsonObj
.
code
,
errMessage
);
}
}
\ No newline at end of file
src/api/project.js
View file @
aa70b179
...
@@ -59,3 +59,29 @@ export async function pack(id) {
...
@@ -59,3 +59,29 @@ export async function pack(id) {
errMessage
:
'Failed to pack project'
,
errMessage
:
'Failed to pack project'
,
})
})
}
}
export
async
function
importView
(
file
)
{
const
response
=
await
fetchApi
(
'/api/parsePSD'
,
{
params
:
{
file
,
},
method
:
'post'
,
contentType
:
'form-data'
,
errMessage
:
'Failed to import view'
,
});
response
.
__originFile
=
file
;
return
response
;
}
export
async
function
uploadFile
(
file
)
{
const
response
=
await
fetchApi
(
'/api/uploadFile'
,
{
params
:
{
file
,
},
method
:
'post'
,
contentType
:
'form-data'
,
errMessage
:
'Failed to upload file'
,
});
response
.
__originFile
=
file
;
return
response
;
}
src/config.js
View file @
aa70b179
...
@@ -8,6 +8,7 @@ if (process.env.NODE_ENV === 'development') {
...
@@ -8,6 +8,7 @@ if (process.env.NODE_ENV === 'development') {
//API_HOST = 'http://10.10.94.134:7777';
//API_HOST = 'http://10.10.94.134:7777';
//API_HOST = 'http://localhost:3002';
//API_HOST = 'http://localhost:3002';
API_HOST
=
window
.
__data
.
apiHost
;
API_HOST
=
window
.
__data
.
apiHost
;
//API_HOST = '';
}
else
{
}
else
{
API_HOST
=
window
.
__data
.
apiHost
;
API_HOST
=
window
.
__data
.
apiHost
;
}
}
...
@@ -16,9 +17,6 @@ if (API_HOST[API_HOST.length - 1] === '/') {
...
@@ -16,9 +17,6 @@ if (API_HOST[API_HOST.length - 1] === '/') {
API_HOST
=
API_HOST
.
substr
(
0
,
API_HOST
.
length
-
1
);
API_HOST
=
API_HOST
.
substr
(
0
,
API_HOST
.
length
-
1
);
}
}
export
const
UPLOAD_FILE_URL
=
API_HOST
+
'/api/uploadFile'
;
export
const
PARSE_BUNDLE_URL
=
API_HOST
+
'/api/parsePSD'
;
export
const
SSO_VERIFY_PAGE_URL
=
'/sso/logout'
;
export
const
SSO_VERIFY_PAGE_URL
=
'/sso/logout'
;
export
const
DOCK_POINT_OFFSET
=
4
;
export
const
DOCK_POINT_OFFSET
=
4
;
...
...
src/locales/en.json
View file @
aa70b179
...
@@ -16,6 +16,7 @@
...
@@ -16,6 +16,7 @@
"Import"
:
"Import"
,
"Import"
:
"Import"
,
"Export"
:
"Export"
,
"Export"
:
"Export"
,
"Upload"
:
"Upload"
,
"Upload"
:
"Upload"
,
"Uploading"
:
"Uploading"
,
"Edit"
:
"Edit"
,
"Edit"
:
"Edit"
,
"EditEnv"
:
"EditEnv"
,
"EditEnv"
:
"EditEnv"
,
"EditCustomModule"
:
"EditCustomModule"
,
"EditCustomModule"
:
"EditCustomModule"
,
...
@@ -118,7 +119,13 @@
...
@@ -118,7 +119,13 @@
"Custom node desc"
:
"Custom node"
,
"Custom node desc"
:
"Custom node"
,
"Divider node desc"
:
"Divider node, exit will be executed in sequence"
,
"Divider node desc"
:
"Divider node, exit will be executed in sequence"
,
"Save this behavior before"
:
"Save this behavior before?"
,
"Save this behavior before"
:
"Save this behavior before?"
,
"Upload view failed"
:
"Upload view failed"
,
"Failed to import view"
:
"Failed to import view"
,
"Failed to upload file"
:
"Failed to upload file"
,
"Single view"
:
"Single view"
,
"Multi views"
:
"Multi views"
,
"Import single"
:
"Import single"
,
"Import multi"
:
"Import multi"
,
"Import view success"
:
"Import view success"
,
"menu"
:
{
"menu"
:
{
"save"
:
"Save"
,
"save"
:
"Save"
,
"details"
:
"Details"
,
"details"
:
"Details"
,
...
...
src/locales/zh-CN.json
View file @
aa70b179
...
@@ -16,6 +16,7 @@
...
@@ -16,6 +16,7 @@
"Import"
:
"导入"
,
"Import"
:
"导入"
,
"Export"
:
"导出"
,
"Export"
:
"导出"
,
"Upload"
:
"上传"
,
"Upload"
:
"上传"
,
"Uploading"
:
"上传中"
,
"Edit"
:
"编辑"
,
"Edit"
:
"编辑"
,
"EditEnv"
:
"编辑环境"
,
"EditEnv"
:
"编辑环境"
,
"EditCustomModule"
:
"编辑自定义模块"
,
"EditCustomModule"
:
"编辑自定义模块"
,
...
@@ -118,7 +119,13 @@
...
@@ -118,7 +119,13 @@
"Custom node desc"
:
"自定义节点"
,
"Custom node desc"
:
"自定义节点"
,
"Divider node desc"
:
"分流节点,出口会按顺序一次执行"
,
"Divider node desc"
:
"分流节点,出口会按顺序一次执行"
,
"Save this behavior before"
:
"是否先保存这个行为?"
,
"Save this behavior before"
:
"是否先保存这个行为?"
,
"Upload view failed"
:
"上传视图失败"
,
"Failed to import view"
:
"导入视图失败"
,
"Failed to upload file"
:
"上传文件失败"
,
"Single view"
:
"单视图"
,
"Multi views"
:
"多视图"
,
"Import single"
:
"导入单"
,
"Import multi"
:
"导入多"
,
"Import view success"
:
"视图导入成功"
,
"menu"
:
{
"menu"
:
{
"save"
:
"保存"
,
"save"
:
"保存"
,
"details"
:
"详情"
,
"details"
:
"详情"
,
...
...
src/store/modules/env.js
View file @
aa70b179
...
@@ -11,7 +11,7 @@ export const envStore = {
...
@@ -11,7 +11,7 @@ export const envStore = {
state
:
{
state
:
{
initialized
:
false
,
initialized
:
false
,
name
:
'Zeroing Editor'
,
name
:
'Zeroing Editor'
,
version
:
'1.0.
0
'
,
version
:
'1.0.
1
'
,
templates
:
{
templates
:
{
builtin
:
[
'blank'
],
builtin
:
[
'blank'
],
custom
:
[],
custom
:
[],
...
...
src/store/modules/project.js
View file @
aa70b179
...
@@ -9,6 +9,8 @@ import generateUUID from "uuid/v4";
...
@@ -9,6 +9,8 @@ import generateUUID from "uuid/v4";
import
{
getCmpProps
,
flattenViews
,
getCmpByUUID
}
from
'../../utils/common'
;
import
{
getCmpProps
,
flattenViews
,
getCmpByUUID
}
from
'../../utils/common'
;
import
{
clonePureObj
,
saveAs
}
from
"../../utils"
;
import
{
clonePureObj
,
saveAs
}
from
"../../utils"
;
import
{
template
}
from
"../../template"
;
import
{
template
}
from
"../../template"
;
import
{
importView
,
uploadFile
}
from
"../../api/project"
;
import
events
from
"@/global-events"
;
const
defaultOptions
=
{
const
defaultOptions
=
{
pageTitle
:
'no title'
,
pageTitle
:
'no title'
,
...
@@ -300,7 +302,7 @@ export const projectStore = {
...
@@ -300,7 +302,7 @@ export const projectStore = {
}
}
}
}
},
},
deleteAllAssets
(
state
){
deleteAllAssets
(
state
)
{
const
{
assets
}
=
state
.
data
;
const
{
assets
}
=
state
.
data
;
assets
.
splice
(
0
);
assets
.
splice
(
0
);
},
},
...
@@ -546,7 +548,21 @@ export const projectStore = {
...
@@ -546,7 +548,21 @@ export const projectStore = {
scripts
:
_scripts
scripts
:
_scripts
})
})
},
},
async
importView
({
commit
},
{
file
,
action
})
{
const
{
view
,
assets
}
=
await
importView
(
file
);
switch
(
action
)
{
case
0
:
//单视图
view
.
name
=
file
.
name
.
substring
(
0
,
file
.
name
.
lastIndexOf
(
'.'
));
commit
(
'importView'
,
view
);
break
;
case
1
:
//多视图
for
(
let
subView
of
view
.
children
)
{
commit
(
'importView'
,
subView
);
}
break
;
}
commit
(
'importAssets'
,
assets
);
},
exportView
({
state
},
view
)
{
exportView
({
state
},
view
)
{
let
zip
=
new
JSZip
();
let
zip
=
new
JSZip
();
zip
.
file
(
'view.json'
,
JSON
.
stringify
(
view
));
zip
.
file
(
'view.json'
,
JSON
.
stringify
(
view
));
...
@@ -554,10 +570,37 @@ export const projectStore = {
...
@@ -554,10 +570,37 @@ export const projectStore = {
saveAs
(
content
,
`view-
${
view
.
name
}
.zrv`
);
saveAs
(
content
,
`view-
${
view
.
name
}
.zrv`
);
});
});
},
},
async
uploadFiles
({
commit
},
files
)
{
const
failedList
=
[];
let
ps
=
[];
for
(
let
file
of
files
)
{
events
.
$emit
(
'upload-indicator'
,
true
);
ps
.
push
(
uploadFile
(
file
).
catch
(
e
=>
{
}).
finally
(()
=>
{
events
.
$emit
(
'upload-indicator'
,
false
);
})
);
}
const
result
=
await
Promise
.
all
(
ps
);
for
(
let
item
of
result
)
{
const
{
url
,
__originFile
}
=
item
;
commit
(
'addAsset'
,
{
url
,
file
:
__originFile
});
}
/*for (let file of files) {
try {
const {url} = await uploadFile(file);
commit('addAsset', {url, file});
}catch (e) {
failedList.push(file);
}
events.$emit('upload-indicator', false);
}*/
return
failedList
;
},
async
packProject
({
state
})
{
async
packProject
({
state
})
{
const
result
=
await
projectApi
.
pack
(
state
.
id
);
const
result
=
await
projectApi
.
pack
(
state
.
id
);
console
.
log
(
result
)
console
.
log
(
result
)
;
return
result
;
return
result
;
}
}
},
},
...
...
src/themes/light/editor.scss
View file @
aa70b179
...
@@ -25,6 +25,10 @@
...
@@ -25,6 +25,10 @@
}
}
}
}
.file-upload-indicator
{
color
:
$--color-text-secondary
;
}
.right-part
{
.right-part
{
color
:
$--color-text-regular
;
color
:
$--color-text-regular
;
line-height
:
15px
;
line-height
:
15px
;
...
...
src/themes/light/playground.scss
View file @
aa70b179
...
@@ -13,6 +13,10 @@
...
@@ -13,6 +13,10 @@
zoom
:
0
.5
;
zoom
:
0
.5
;
background
:
url(data:image/jpeg;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAiUlEQVQ4jZ1TSxLFIAhLOp7C+19NjyFvlQ7lUUvLRgXzgVGOMQyb6L3/5cwMJAEAxw6sy3FP8tw/EkhJqp7klQMBtKpWcpC1oVp7IoiqviXg4xBFRPL7EM/6WsviYDxwzrkVaBHsz5U4MlWfKxHEySpXIdk6qLRzcXBHVnKQfZRKCy1Ty979XfwApOBe0rB0KiIAAAAASUVORK5CYII=)
;
background
:
url(data:image/jpeg;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAiUlEQVQ4jZ1TSxLFIAhLOp7C+19NjyFvlQ7lUUvLRgXzgVGOMQyb6L3/5cwMJAEAxw6sy3FP8tw/EkhJqp7klQMBtKpWcpC1oVp7IoiqviXg4xBFRPL7EM/6WsviYDxwzrkVaBHsz5U4MlWfKxHEySpXIdk6qLRzcXBHVnKQfZRKCy1Ty979XfwApOBe0rB0KiIAAAAASUVORK5CYII=)
;
background-repeat
:
repeat
;
background-repeat
:
repeat
;
&
:
:-
webkit-scrollbar
{
display
:
none
;
}
}
}
// .zero-playground-draw-panel{
// .zero-playground-draw-panel{
// min-height: 1200px;
// min-height: 1200px;
...
...
src/utils/index.js
View file @
aa70b179
...
@@ -108,3 +108,18 @@ export function readTextFile(file) {
...
@@ -108,3 +108,18 @@ export function readTextFile(file) {
},
false
);
},
false
);
})
})
}
}
export
function
selectFile
(
callback
,
{
accept
,
multiple
}
=
{})
{
let
input
=
document
.
createElement
(
'input'
);
input
.
type
=
'file'
;
input
.
onchange
=
function
(
e
)
{
callback
(
input
.
files
);
};
if
(
accept
)
{
input
.
accept
=
accept
;
}
if
(
multiple
)
{
input
.
multiple
=
true
;
}
input
.
click
();
}
src/views/Editor/Assets.vue
View file @
aa70b179
...
@@ -23,17 +23,9 @@
...
@@ -23,17 +23,9 @@
<el-scrollbar
class=
"assets-scrollbar"
wrap-class=
"wrap-x-hidden"
<el-scrollbar
class=
"assets-scrollbar"
wrap-class=
"wrap-x-hidden"
view-class=
"scrollbar-view"
>
view-class=
"scrollbar-view"
>
<div
class=
"file-list"
>
<div
class=
"file-list"
>
<el-upload
<div
class=
"file-uploader"
@
click=
"toUploadFile"
>
class=
"file-uploader"
:action=
"uploadFileUrl"
name=
"file"
multiple
:show-file-list=
"false"
:on-success=
"uploadFileSuccess"
:on-error=
"uploadFileError"
>
<i
class=
"el-icon-plus file-uploader-icon"
></i>
<i
class=
"el-icon-plus file-uploader-icon"
></i>
</
el-upload
>
</
div
>
<file-item
v-for=
"(asset, index) in assets"
:data=
"asset"
:key=
"index"
@
show-file-details=
"showFileDetails"
<file-item
v-for=
"(asset, index) in assets"
:data=
"asset"
:key=
"index"
@
show-file-details=
"showFileDetails"
@
click=
"onItemClick(asset)"
/>
@
click=
"onItemClick(asset)"
/>
</div>
</div>
...
@@ -45,12 +37,12 @@
...
@@ -45,12 +37,12 @@
</template>
</template>
<
script
>
<
script
>
import
{
mapState
,
mapMutations
}
from
'vuex'
import
{
mapState
,
mapMutations
,
mapActions
}
from
'vuex'
import
Pane
from
"../../components/Pane"
;
import
Pane
from
"../../components/Pane"
;
import
FileItem
from
"./Assets/FileItem"
;
import
FileItem
from
"./Assets/FileItem"
;
import
AssetsShow
from
"./Assets/AssetsShow"
;
import
AssetsShow
from
"./Assets/AssetsShow"
;
import
{
UPLOAD_FILE_URL
}
from
"../../config"
;
import
SplitPanes
from
'splitpanes'
import
SplitPanes
from
'splitpanes'
import
{
selectFile
}
from
"../../utils"
;
export
default
{
export
default
{
name
:
"Assets"
,
name
:
"Assets"
,
...
@@ -59,12 +51,12 @@
...
@@ -59,12 +51,12 @@
return
{
return
{
showFields
:
[
'url'
,
'uuid'
],
showFields
:
[
'url'
,
'uuid'
],
currentItem
:
null
,
currentItem
:
null
,
uploadHeaders
:
{
authorization
:
'Bearer '
+
window
[
'zeroing_token'
],
},
}
}
},
},
computed
:
{
computed
:
{
uploadFileUrl
()
{
return
UPLOAD_FILE_URL
;
},
...
mapState
({
...
mapState
({
assets
:
state
=>
state
.
project
.
data
.
assets
assets
:
state
=>
state
.
project
.
data
.
assets
}),
}),
...
@@ -73,27 +65,18 @@
...
@@ -73,27 +65,18 @@
this
.
currentItem
=
null
;
this
.
currentItem
=
null
;
},
},
methods
:
{
methods
:
{
toUploadFile
()
{
selectFile
((
files
)
=>
{
this
.
uploadFiles
(
files
);
},
{
multiple
:
true
})
},
showFileDetails
(
file
)
{
showFileDetails
(
file
)
{
this
.
$refs
.
assetsShow
.
show
(
file
);
this
.
$refs
.
assetsShow
.
show
(
file
);
},
},
onItemClick
(
asset
)
{
onItemClick
(
asset
)
{
this
.
currentItem
=
asset
;
this
.
currentItem
=
asset
;
},
},
uploadFileSuccess
(
response
,
file
)
{
deleteAll
()
{
if
(
response
.
success
)
{
//console.log('upload success', response, file);
this
.
addAsset
({
url
:
response
.
url
,
file
,
})
}
else
{
this
.
uploadFileError
();
}
},
uploadFileError
()
{
console
.
log
(
'upload error'
)
},
deleteAll
(){
this
.
$confirm
(
this
.
$t
(
'Are you sure to delete all assets'
),
this
.
$t
(
'Alert'
),
{
this
.
$confirm
(
this
.
$t
(
'Are you sure to delete all assets'
),
this
.
$t
(
'Alert'
),
{
confirmButtonText
:
this
.
$t
(
'Confirm'
),
confirmButtonText
:
this
.
$t
(
'Confirm'
),
cancelButtonText
:
this
.
$t
(
'Cancel'
),
cancelButtonText
:
this
.
$t
(
'Cancel'
),
...
@@ -104,9 +87,11 @@
...
@@ -104,9 +87,11 @@
});
});
},
},
...
mapMutations
([
...
mapMutations
([
'addAsset'
,
'deleteAllAssets'
,
'deleteAllAssets'
,
]),
]),
...
mapActions
([
'uploadFiles'
,
]),
}
}
}
}
</
script
>
</
script
>
...
...
src/views/Editor/ToolBar.vue
View file @
aa70b179
<
template
>
<
template
>
<div
class=
"tool-bar"
>
<div
class=
"tool-bar"
>
<sample-menu
:data=
"menu"
@
click-menu=
"clickMenu"
/>
<sample-menu
:data=
"menu"
@
click-menu=
"clickMenu"
/>
<upload-indicator/>
<div
style=
"flex: 1"
></div>
<div
class=
"right-part"
>
<div
class=
"right-part"
>
<span>
<span>
[
{{
project
.
name
}}
]
[
{{
project
.
name
}}
]
...
@@ -13,10 +15,11 @@
...
@@ -13,10 +15,11 @@
<
script
>
<
script
>
import
{
mapState
,
mapActions
,
mapMutations
}
from
'vuex'
import
{
mapState
,
mapActions
,
mapMutations
}
from
'vuex'
import
SampleMenu
from
"../../components/SampleMenu"
;
import
SampleMenu
from
"../../components/SampleMenu"
;
import
UploadIndicator
from
"./ToolBar/UploadIndicator"
;
export
default
{
export
default
{
name
:
"ToolBar"
,
name
:
"ToolBar"
,
components
:
{
SampleMenu
},
components
:
{
UploadIndicator
,
SampleMenu
},
data
()
{
data
()
{
return
{}
return
{}
},
},
...
@@ -24,7 +27,7 @@
...
@@ -24,7 +27,7 @@
...
mapState
([
...
mapState
([
'project'
'project'
]),
]),
menu
:
function
()
{
menu
:
function
()
{
const
menuConfig
=
this
.
$t
(
'menu'
);
const
menuConfig
=
this
.
$t
(
'menu'
);
let
menu
=
{};
let
menu
=
{};
for
(
let
item
of
Object
.
keys
(
menuConfig
))
{
for
(
let
item
of
Object
.
keys
(
menuConfig
))
{
...
@@ -43,7 +46,7 @@
...
@@ -43,7 +46,7 @@
clickMenu
(
menuItem
)
{
clickMenu
(
menuItem
)
{
this
.
$emit
(
'click-menu'
,
menuItem
);
this
.
$emit
(
'click-menu'
,
menuItem
);
},
},
editProjectName
(){
editProjectName
()
{
this
.
$prompt
(
this
.
$t
(
'Input project name'
),
this
.
$t
(
'Rename project'
),
{
this
.
$prompt
(
this
.
$t
(
'Input project name'
),
this
.
$t
(
'Rename project'
),
{
inputValue
:
this
.
project
.
name
,
inputValue
:
this
.
project
.
name
,
confirmButtonText
:
this
.
$t
(
'Confirm'
),
confirmButtonText
:
this
.
$t
(
'Confirm'
),
...
...
src/views/Editor/ToolBar/UploadIndicator.vue
0 → 100644
View file @
aa70b179
<
template
>
<div
v-if=
"counting > 0"
class=
"file-upload-indicator"
>
{{
$t
(
'Uploading'
)
}}
(
{{
counting
}}
)
<i
class=
"el-icon-loading"
></i>
</div>
</
template
>
<
script
>
import
events
from
"../../../global-events"
;
export
default
{
name
:
"UploadIndicator"
,
data
()
{
return
{
counting
:
0
,
}
},
mounted
()
{
events
.
$on
(
'upload-indicator'
,
this
.
onUploadIndicator
);
},
destroyed
()
{
events
.
$off
(
'upload-indicator'
,
this
.
onUploadIndicator
);
},
methods
:
{
onUploadIndicator
(
show
)
{
this
.
counting
+=
show
?
1
:
-
1
;
},
}
}
</
script
>
<
style
scoped
>
</
style
>
\ No newline at end of file
src/views/Editor/Views.vue
View file @
aa70b179
...
@@ -3,17 +3,14 @@
...
@@ -3,17 +3,14 @@
<div
class=
"container"
>
<div
class=
"container"
>
<div
class=
"header-bar"
>
<div
class=
"header-bar"
>
<el-link
class=
"menu-item"
@
click=
"toAddView"
>
{{
$t
(
'Add'
)
}}
</el-link>
<el-link
class=
"menu-item"
@
click=
"toAddView"
>
{{
$t
(
'Add'
)
}}
</el-link>
<el-upload
<el-link
@
click=
"toImport(0)"
>
{{
$t
(
'Import'
)
}}
</el-link>
class=
"menu-item import-file"
<el-dropdown
trigger=
"hover"
placement=
"top"
size=
"mini"
@
command=
"onImportCommand"
>
:action=
"importFileUrl"
<i
class=
"el-icon-arrow-down el-icon--right"
></i>
name=
"file"
<el-dropdown-menu
slot=
"dropdown"
>
:headers=
"uploadHeaders"
<el-dropdown-item
command=
"single"
>
{{
$t
(
'Single view'
)
}}
</el-dropdown-item>
:show-file-list=
"false"
<el-dropdown-item
command=
"multi"
>
{{
$t
(
'Multi views'
)
}}
</el-dropdown-item>
:on-success=
"uploadFileSuccess"
</el-dropdown-menu>
:on-error=
"uploadFileError"
</el-dropdown>
>
<el-link
@
click=
"toImportView"
>
{{
$t
(
'Import'
)
}}
</el-link>
</el-upload>
</div>
</div>
<el-scrollbar
class=
"tree-scrollbar"
wrap-class=
"wrap-x-hidden"
>
<el-scrollbar
class=
"tree-scrollbar"
wrap-class=
"wrap-x-hidden"
>
<el-tree
<el-tree
...
@@ -22,10 +19,11 @@
...
@@ -22,10 +19,11 @@
:expand-on-click-node=
"false"
:expand-on-click-node=
"false"
draggable
draggable
highlight-current
highlight-current
:default-expand-all=
"
tru
e"
:default-expand-all=
"
fals
e"
@
node-click=
"handleNodeClick"
@
node-click=
"handleNodeClick"
empty-text=
""
empty-text=
""
:allow-drag=
"allowDrag"
:allow-drag=
"allowDrag"
:allow-drop=
"allowDrop"
>
>
<div
slot-scope=
"
{ node, data }" class="tree-node">
<div
slot-scope=
"
{ node, data }" class="tree-node">
<div
class=
"node-name"
>
<div
class=
"node-name"
>
...
@@ -55,105 +53,112 @@
...
@@ -55,105 +53,112 @@
</
template
>
</
template
>
<
script
>
<
script
>
import
{
mapState
,
mapMutations
,
mapActions
}
from
'vuex'
;
import
{
mapState
,
mapMutations
,
mapActions
}
from
'vuex'
;
import
Pane
from
'../../components/Pane'
;
import
Pane
from
'../../components/Pane'
;
import
{
PARSE_BUNDLE_URL
}
from
'../../config'
;
import
{
selectFile
}
from
"../../utils"
;
import
events
from
"../../global-events"
;
export
default
{
name
:
'Views'
,
components
:
{
Pane
},
data
()
{
return
{
defaultProps
:
{
children
:
'children'
,
label
:
'name'
},
uploadHeaders
:
{
authorization
:
'Bearer '
+
window
[
'zeroing_token'
],
},
};
},
computed
:
{
importFileUrl
()
{
return
PARSE_BUNDLE_URL
;
},
...
mapState
({
views
:
state
=>
state
.
project
.
data
.
views
})
},
methods
:
{
allowDrag
(
draggingNode
)
{
return
draggingNode
.
parent
.
parent
;
},
/**
* 点击左侧视图列表
*/
handleNodeClick
(
data
,
node
)
{
this
.
$store
.
dispatch
(
'activeComponent'
,
{
data
,
node
});
},
toAddView
()
{
this
.
$prompt
(
this
.
$t
(
'Input view name'
),
this
.
$t
(
'Alert'
),
{
confirmButtonText
:
this
.
$t
(
'Confirm'
),
cancelButtonText
:
this
.
$t
(
'Cancel'
),
inputPattern
:
/^.
{1,64}
$/
,
inputErrorMessage
:
this
.
$t
(
'Invalid view name'
)
})
.
then
(({
value
})
=>
{
this
.
addNode
({
name
:
value
,
type
:
'node'
});
})
.
catch
(()
=>
{});
},
toImportView
()
{},
selectNode
(
data
,
node
,
target
)
{},
onMoreMenu
(
command
,
data
,
node
)
{
switch
(
command
)
{
case
'delete'
:
this
.
deleteNode
({
node
:
data
,
parentNode
:
node
.
parent
.
data
});
break
;
case
'export'
:
this
.
exportView
(
data
);
break
;
default
:
if
(
command
.
startsWith
(
'add_node_'
))
{
const
type
=
command
.
substr
(
'add_node_'
.
length
);
this
.
addNode
({
node
:
data
,
type
,
name
:
type
,
});
}
break
;
}
},
uploadFileSuccess
(
response
,
file
)
{
if
(
response
.
success
)
{
console
.
log
(
'upload success'
,
response
);
const
{
view
,
assets
}
=
response
.
data
;
this
.
importView
(
view
);
export
default
{
this
.
importAssets
(
assets
);
name
:
'Views'
,
}
else
{
components
:
{
Pane
},
this
.
uploadFileError
();
data
()
{
}
return
{
},
defaultProps
:
{
uploadFileError
()
{
children
:
'children'
,
console
.
log
(
'upload error'
);
label
:
'name'
this
.
$message
({
},
message
:
this
.
$t
(
'Upload view failed'
),
uploadHeaders
:
{
type
:
'error'
,
authorization
:
'Bearer '
+
window
[
'zeroing_token'
],
duration
:
1000
,
},
});
};
},
},
...
mapMutations
([
'importView'
,
'importAssets'
,
'deleteNode'
,
'addNode'
]),
computed
:
{
...
mapActions
([
'exportView'
])
...
mapState
({
}
views
:
state
=>
state
.
project
.
data
.
views
};
})
},
methods
:
{
allowDrag
(
draggingNode
)
{
return
draggingNode
.
parent
.
parent
;
},
allowDrop
(
draggingNode
,
dropNode
,
type
)
{
//console.log(dropNode.parent.parent, type);
return
dropNode
.
parent
.
parent
||
type
===
'inner'
;
},
/**
* 点击左侧视图列表
*/
handleNodeClick
(
data
,
node
)
{
this
.
$store
.
dispatch
(
'activeComponent'
,
{
data
,
node
});
},
toAddView
()
{
this
.
$prompt
(
this
.
$t
(
'Input view name'
),
this
.
$t
(
'Alert'
),
{
confirmButtonText
:
this
.
$t
(
'Confirm'
),
cancelButtonText
:
this
.
$t
(
'Cancel'
),
inputPattern
:
/^.
{1,64}
$/
,
inputErrorMessage
:
this
.
$t
(
'Invalid view name'
)
})
.
then
(({
value
})
=>
{
this
.
addNode
({
name
:
value
,
type
:
'node'
});
})
.
catch
(()
=>
{
});
},
toImport
(
action
)
{
selectFile
(
async
files
=>
{
events
.
$emit
(
'upload-indicator'
,
true
);
try
{
await
this
.
importView
({
file
:
files
[
0
],
action
,
});
}
catch
(
e
)
{
}
events
.
$emit
(
'upload-indicator'
,
false
);
})
},
onImportCommand
(
command
)
{
let
action
;
switch
(
command
)
{
case
'single'
:
action
=
0
;
break
;
case
'multi'
:
action
=
1
;
break
;
}
this
.
toImport
(
action
);
},
onMoreMenu
(
command
,
data
,
node
)
{
switch
(
command
)
{
case
'delete'
:
this
.
deleteNode
({
node
:
data
,
parentNode
:
node
.
parent
.
data
});
break
;
case
'export'
:
this
.
exportView
(
data
);
break
;
default
:
if
(
command
.
startsWith
(
'add_node_'
))
{
const
type
=
command
.
substr
(
'add_node_'
.
length
);
this
.
addNode
({
node
:
data
,
type
,
name
:
type
,
});
}
break
;
}
},
...
mapMutations
([
'deleteNode'
,
'addNode'
]),
...
mapActions
([
'exportView'
,
'importView'
])
}
};
</
script
>
</
script
>
<
style
scoped
>
<
style
scoped
>
...
...
src/views/Editor/behavior-editor/inputs/DynamicInput.vue
View file @
aa70b179
<
template
>
<
template
>
<input-wrapper
:editable=
"editable"
:value=
"value"
:container=
"container"
:property=
"property"
<input-wrapper
:editable=
"editable"
:value=
"value"
:container=
"container"
:property=
"property"
:propertyName=
"propertyName"
>
:propertyName=
"propertyName"
>
<dynamic-selector
style=
"flex: 1;"
:
input
=
"value"
@
input=
"onChange"
<dynamic-selector
style=
"flex: 1;"
:
value
=
"value"
@
input=
"onChange"
:editable=
"editable"
:editable=
"editable"
:container=
"container"
:container=
"container"
:property=
"property"
:property=
"property"
...
...
src/views/Editor/dialogs/BehaviorEditorDialog.vue
View file @
aa70b179
<
template
>
<
template
>
<el-dialog
:title=
"$t('Behavior Editor')"
:visible
.
sync=
"visible"
:before-close=
"beforeClose"
@
opened=
"onOpened"
<el-dialog
:title=
"$t('Behavior Editor')"
:visible
.
sync=
"visible"
:before-close=
"beforeClose"
@
opened=
"onOpened"
:fullscreen=
"true"
:fullscreen=
"true"
:close-on-click-modal=
"false"
:close-on-press-escape=
"false"
:append-to-body=
"true"
:close-on-click-modal=
"false"
custom-class=
"behavior-editor-dialog"
>
:append-to-body=
"true"
custom-class=
"behavior-editor-dialog"
>
<behavior-editor
v-if=
"editorReady"
ref=
"behaviorEditor"
class=
"full-size"
></behavior-editor>
<behavior-editor
v-if=
"editorReady"
ref=
"behaviorEditor"
class=
"full-size"
></behavior-editor>
<div
slot=
"footer"
class=
"dialog-footer"
>
<div
slot=
"footer"
class=
"dialog-footer"
>
<el-button
size=
"mini"
type=
"primary"
@
click=
"onSave"
>
{{
$t
(
'Save'
)
}}
</el-button>
<el-button
size=
"mini"
type=
"primary"
@
click=
"onSave"
>
{{
$t
(
'Save'
)
}}
</el-button>
...
...
src/views/Home.vue
View file @
aa70b179
...
@@ -33,11 +33,11 @@
...
@@ -33,11 +33,11 @@
type=
"success"
icon=
"el-icon-document-copy"
type=
"success"
icon=
"el-icon-document-copy"
size=
"small"
circle
plain
>
size=
"small"
circle
plain
>
</el-button>
</el-button>
<el-button
<
!--
<
el-button
@
click
.
native
.
prevent=
"onDeleteProject(scope.row)"
@
click
.
native
.
prevent=
"onDeleteProject(scope.row)"
type=
"danger"
icon=
"el-icon-delete"
type=
"danger"
icon=
"el-icon-delete"
size=
"small"
circle
plain
>
size=
"small"
circle
plain
>
</el-button>
</el-button>
-->
</
template
>
</
template
>
</el-table-column>
</el-table-column>
</el-table>
</el-table>
...
...
src/views/Home/DuplicateProjectDialog.vue
View file @
aa70b179
...
@@ -22,7 +22,8 @@
...
@@ -22,7 +22,8 @@
return
{
return
{
visible
:
false
,
visible
:
false
,
project
:
{
project
:
{
name
:
''
id
:
''
,
name
:
''
,
},
},
template
:
'blank'
,
template
:
'blank'
,
templates
:
{
templates
:
{
...
@@ -39,6 +40,7 @@
...
@@ -39,6 +40,7 @@
methods
:
{
methods
:
{
async
show
(
project
)
{
async
show
(
project
)
{
this
.
project
.
name
=
project
.
name
+
'-'
+
this
.
$t
(
'copy'
)
+
'-'
+
Math
.
floor
(
Math
.
random
()
*
10000
);
this
.
project
.
name
=
project
.
name
+
'-'
+
this
.
$t
(
'copy'
)
+
'-'
+
Math
.
floor
(
Math
.
random
()
*
10000
);
this
.
project
.
id
=
project
.
id
;
this
.
visible
=
true
;
this
.
visible
=
true
;
},
},
doCreateProject
()
{
doCreateProject
()
{
...
...
自动合并.jsx
deleted
100644 → 0
View file @
e21945d8
/**
* Created by rockyl on 2019-11-25.
*/
var
mergeFlagReg
=
/__m$/
;
var
oldDocument
=
app
.
activeDocument
;
var
mergeLayers
=
[];
var
document
=
oldDocument
.
duplicate
(
oldDocument
.
name
+
'-合并'
,
0
);
app
.
activeDocument
=
document
;
merge
(
document
);
function
merge
(
document
){
traverse
(
document
,
function
(
layer
){
return
layer
.
name
.
match
(
mergeFlagReg
);
},
function
(
layer
){
document
.
activeLayer
=
layer
;
var
newName
=
layer
.
name
.
replace
(
mergeFlagReg
,
''
);
layer
.
name
=
newName
;
mergeLayers
.
push
(
newName
);
layer
.
merge
();
});
if
(
mergeLayers
.
length
>
0
){
alert
(
'合并的图层有: '
+
mergeLayers
.
join
(
','
));
}
else
{
alert
(
'没有图层被合并'
);
}
}
function
traverse
(
layer
,
filter
,
callback
)
{
if
(
layer
.
layers
){
for
(
var
i
=
0
;
i
<
layer
.
layers
.
length
;
i
++
)
{
var
childLayer
=
layer
.
layers
[
i
];
if
(
filter
(
childLayer
))
{
callback
(
childLayer
);
}
else
{
traverse
(
childLayer
,
filter
,
callback
);
}
}
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment