├── .eslintignore
├── docs
├── .nojekyll
├── index.html
├── en
│ ├── LOGS.md
│ ├── README.md
│ └── TUTORIAL.md
├── LOGS.md
├── README.md
└── TUTORIAL.md
├── .babelrc
├── screenshot
├── 1.PNG
├── 1.gif
├── 2.gif
└── 1_en.PNG
├── .gitignore
├── src
├── index.js
├── mvvm
│ ├── observer.js
│ └── index.js
├── https
│ ├── checkVersion.js
│ └── index.js
├── ui
│ ├── moveGroupWindow.js
│ ├── moveItemWindow.js
│ ├── previewProgress.js
│ ├── presetWindow.js
│ ├── outputGroupWindow.js
│ ├── moduleWindow.js
│ ├── rightClickMenu.js
│ └── settingWindow.js
├── layer
│ └── progressFactory.js
├── polyfill.js
├── startup.js
├── preset.js
└── i18n
│ └── index.js
├── lib
├── AutoSave.js
├── OperatorOverload.js
├── ReloadPic.js
├── UIParser.js
├── GridView.js
└── Translate.js
├── package.json
├── README.md
├── .eslintrc.js
├── index.js
└── LICENSE
/.eslintignore:
--------------------------------------------------------------------------------
1 | dist
--------------------------------------------------------------------------------
/docs/.nojekyll:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["es2015", "stage-2"],
3 | "comments": false
4 | }
--------------------------------------------------------------------------------
/screenshot/1.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smallpath/memory/HEAD/screenshot/1.PNG
--------------------------------------------------------------------------------
/screenshot/1.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smallpath/memory/HEAD/screenshot/1.gif
--------------------------------------------------------------------------------
/screenshot/2.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smallpath/memory/HEAD/screenshot/2.gif
--------------------------------------------------------------------------------
/screenshot/1_en.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smallpath/memory/HEAD/screenshot/1_en.PNG
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
3 | Sp_memory
4 |
5 | dist/*
6 |
7 | !dist/Sp_memory.jsx
8 |
9 | *.log
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | progressFactory: require('./layer/progressFactory'),
3 | previewProgress: require('./ui/previewProgress'),
4 | settingWindow: require('./ui/settingWindow'),
5 | fns: require('./ui/function')
6 | }
7 |
--------------------------------------------------------------------------------
/src/mvvm/observer.js:
--------------------------------------------------------------------------------
1 | exports.observer = observer
2 | exports.isObj = isObj
3 |
4 | function isObj(obj) {
5 | return Object.prototype.toString.call(obj).slice(8, -1) === 'Object'
6 | }
7 |
8 | function isInBlackList(name, list) {
9 | for (var i = 0; i < list.length; i++) {
10 | if (list[i] === name) return true
11 | }
12 | return false
13 | }
14 |
15 | function observer(obj, callback, nameBlackList, index) {
16 | index = index || 0
17 | if (!isObj(obj)) return
18 | for (var i in obj) {
19 | if (index === 0 && isInBlackList(i, nameBlackList)) continue
20 | obj.watch(i, callback)
21 | if (isObj(obj[i])) observer(obj[i], callback, nameBlackList, index + 1)
22 | }
23 | return obj
24 | }
25 |
--------------------------------------------------------------------------------
/lib/AutoSave.js:
--------------------------------------------------------------------------------
1 | // 批量自动保存每一层为新Item
2 | $.global.autoSave = autoSave
3 | function autoSave() {
4 | if (confirm(loc(sp.auto)) === false) return
5 | if (!(app.project.activeItem instanceof CompItem)) return alert(loc(sp.needComp))
6 | if (!sp.droplist.selection) return
7 |
8 | try {
9 | var preRenameValue = sp.autoNameValue
10 | sp.autoNameValue = true
11 | for (var i = 0; i < app.project.activeItem.numLayers; i++) {
12 | for (var j = 1; j <= app.project.activeItem.numLayers; j++) {
13 | app.project.activeItem.layer(j).selected = false
14 | }
15 | app.project.activeItem.layer(i + 1).selected = true
16 | sp.fns.newItem()
17 | app.project.activeItem.layer(i + 1).selected = false
18 | }
19 | sp.autoNameValue = preRenameValue
20 | } catch (err) { }
21 | sp.droplist.notify('onChange')
22 | sp.gv.refresh()
23 | }
24 |
--------------------------------------------------------------------------------
/lib/OperatorOverload.js:
--------------------------------------------------------------------------------
1 | function OperatorOverload(call, operator) {
2 | var meta = [
3 | // Unary operator
4 | '+', '-', '~',
5 | // Binary operator
6 | '*', '/', '%', '^', '<', '<=', '==', '<<', '>>', '>>>', '&', '|', '==='
7 | ]
8 | var toObject = function() {
9 | for (var i = 0; i < arguments.length; i++) { this[arguments[i]] = true }
10 | return this
11 | }
12 | var metaObj = toObject.apply({}, meta)
13 | if (!metaObj.hasOwnProperty(operator)) { return alert('Operator not supported.') }
14 |
15 | this.call = call
16 | this[operator] = function(operand, rev) {
17 | this.call(operand, rev)
18 | return this
19 | }
20 | return this
21 | }
22 |
23 | var cout = $.global.cout = new OperatorOverload(function(operand, rev) {
24 | if (!rev) { $.writeln(operand) } else { alert(operand) }
25 | }, '<<')
26 | $.global.cout = cout
27 |
--------------------------------------------------------------------------------
/src/mvvm/index.js:
--------------------------------------------------------------------------------
1 | var mvvm = require('./observer')
2 |
3 | var nameBlackList = [
4 | 'win', // the parent window of grid view instance
5 | 'gv', // the grid view instance
6 | 'isOutside', // ensure mouse cursor is in image rect or not
7 | 'previewHelper', // helper object for preview feature
8 | 'isLoopPreview', // preview loop boolean value
9 | 'droplist',
10 | 'parentDroplist',
11 | 'menu'
12 | ]
13 |
14 | function watch(name, oldValue, newValue) {
15 | // $.writeln('name: ', name, ' oldValue: ', oldValue, ' newValue: ', newValue)
16 | if (typeof oldValue === 'function') {
17 | return oldValue
18 | } else if (typeof newValue === 'boolean') {
19 | var settingName = name.replace('Value', '')
20 | // $.writeln('write to ', settingName, ' has?: ', $.global.sp.haveSetting(name.replace('Value', '')))
21 | if ($.global.sp.haveSetting(settingName)) {
22 | $.global.sp.saveSetting(settingName, newValue)
23 | return newValue
24 | } else {
25 | return oldValue
26 | }
27 | } else {
28 | return newValue
29 | }
30 | }
31 |
32 | module.exports = function(obj) {
33 | return mvvm.observer(obj, watch, nameBlackList)
34 | }
35 |
--------------------------------------------------------------------------------
/docs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Sp_memory - a script for adobe after effects to save any layers
6 |
7 |
8 |
9 |
10 |
11 |
15 |
16 |
17 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/src/https/checkVersion.js:
--------------------------------------------------------------------------------
1 | module.exports = function(win, isStarting) {
2 | clearOutput && clearOutput()
3 | var targetAlert = isStarting ? writeLn : alert
4 | return function() {
5 | var latestVersion = sp.getVersion()
6 | var nowVersion = sp.version
7 | var compare = sp.compareSemver(latestVersion, nowVersion)
8 | if (compare > 0) {
9 | targetAlert(loc(sp.newVersionFind) + latestVersion.toString())
10 | var scriptLink = sp.downloadLinkPrefix + latestVersion + sp.downloadLinkSuffix
11 | if (confirm(loc(sp.shouldUpdateScript))) {
12 | try {
13 | var scriptString = sp.request(
14 | 'GET',
15 | scriptLink,
16 | ''
17 | )
18 | var file = new File($.fileName)
19 | file.writee(scriptString)
20 | targetAlert(loc(sp.downloaded))
21 | win.close()
22 | sp.win.close()
23 | } catch (err) { err.printa() }
24 | } else if (confirm(loc(sp.shouldDownloadScript))) {
25 | try {
26 | sp.openLink(scriptLink)
27 | } catch (err) { err.printa() }
28 | }
29 | } else if (compare === 0) {
30 | targetAlert(loc(sp.newVersionNotFind) + nowVersion.toString())
31 | } else if (compare < 0) {
32 | targetAlert(loc(sp.tryVersionFind) + nowVersion.toString())
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/docs/en/LOGS.md:
--------------------------------------------------------------------------------
1 | ### 3.0 Date:2016-04-07
2 | - Add preview feature
3 | - Add module
4 | - New checkbox->Save preview
5 | - Fix CC2015 save preview error
6 |
7 | ### 2.2 Date:2016-03-20
8 | - Refactoring
9 | - Fixing expression error automatically
10 | - Add a new type of thumbnail
11 | - Fix memory leaks
12 | - Fix script freezing
13 |
14 | ### 2.1 Date:2015-11-05
15 | - Add shortcut for Palette-type open
16 | - Add checkbox of limiting text
17 | - Speed up 10% for saving layers
18 |
19 | ### 2.0 Date:2015-10-07
20 | - Add new UI
21 | - Add some options in Setting window
22 | - Support keyframe interpolation and roving
23 | - Support MaskIndex and LayerIndex property
24 | - Support ray-traced layer
25 | - Support check update
26 | - Support remember size and position of script open in Palette type
27 | - Fix some bugs
28 |
29 | ### 1.3 Date:2015-07-02
30 | - Support CC2015
31 | - Add auto-save feature
32 | - Add export groups feature
33 | - Fix some bugs
34 |
35 | ### 1.2 Date:2015-05-16
36 | - Support CS3,CS4,CS5 and CS5.5
37 | - New checkbox->Empty property
38 | - New checkbox->Offset keyframe
39 | - Fix some bugs
40 |
41 | ### 1.1 Date:2015-04-19
42 | - New checkbox->Save material
43 | - Add option for empty temp folder
44 | - Add option for rename group
45 | - Add button for rename item
46 | - Add option for change script language
47 | - Fix some bugs
48 |
49 | ### 1.0 Date:2015-04-13
50 | - Support Composition layer
51 | - Support CS6,CC and CC2014
52 |
--------------------------------------------------------------------------------
/src/https/index.js:
--------------------------------------------------------------------------------
1 | var vbsString = `set namedArgs = WScript.Arguments.Named
2 |
3 | sMethod = namedArgs.Item("Method")
4 | sUrl = namedArgs.Item("URL")
5 | sRequest = namedArgs.Item("Query")
6 |
7 | HTTPPost sMethod, sUrl, sRequest
8 |
9 | Function HTTPPost(sMethod, sUrl, sRequest)
10 |
11 | set oHTTP = CreateObject("Microsoft.XMLHTTP")
12 |
13 | If sMethod = "POST" Then
14 | oHTTP.open "POST", sUrl,false
15 | ElseIf sMethod = "GET" Then
16 | oHTTP.open "GET", sUrl,false
17 | End If
18 |
19 | oHTTP.setRequestHeader "Content-Type", "application/x-www-form-urlencoded"
20 | oHTTP.setRequestHeader "Content-Length", Len(sRequest)
21 | oHTTP.send sRequest
22 |
23 | HTTPPost = oHTTP.responseText
24 |
25 | WScript.Echo HTTPPost
26 |
27 | End Function
28 | `
29 |
30 | module.exports = function(method, endpoint, query) {
31 | var response = null
32 |
33 | var tempVbsFile = new File($.layer.tempFolder.toString() + $.layer.slash.toString() + 'curl.vbs')
34 |
35 | if (!tempVbsFile.exists) {
36 | tempVbsFile.writee(vbsString)
37 | }
38 | var wincurl = tempVbsFile.fsName
39 | var curlCmd = ''
40 |
41 | try {
42 | if (sp.os === 'win') {
43 | curlCmd = `cscript "${wincurl}" /Method:${method} /URL:${endpoint} /Query:${query} //nologo`
44 | } else {
45 | curlCmd = `curl -s -G -d "${query}" ${endpoint}`
46 | }
47 | response = system.callSystem(curlCmd)
48 | } catch (err) {}
49 |
50 | return response
51 | }
52 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "memory",
3 | "version": "3.1.0",
4 | "description": "a script for adobe after effects to save any layers",
5 | "main": "index.js",
6 | "scripts": {
7 | "dev": "webpack --config ./build/webpack.config.js --watch --progress --hide-modules",
8 | "test": "echo \"Error: no test specified\" && exit 1",
9 | "build": "cross-env NODE_ENV=production webpack --config ./build/webpack.config.js --progress --hide-modules",
10 | "lint": "eslint . --quiet",
11 | "fix": "eslint . --fix --quiet"
12 | },
13 | "repository": {
14 | "type": "git",
15 | "url": "git+https://smallpath@github.com/smallpath/memory.git"
16 | },
17 | "keywords": [
18 | "ae",
19 | "layer",
20 | "sp_memory"
21 | ],
22 | "author": "smallpath",
23 | "license": "Apache-2.0",
24 | "bugs": {
25 | "url": "https://github.com/smallpath/memory/issues"
26 | },
27 | "homepage": "https://github.com/smallpath/memory#readme",
28 | "devDependencies": {
29 | "after-effects": "^0.4.11",
30 | "babel-core": "^6.24.0",
31 | "babel-eslint": "^7.2.1",
32 | "babel-loader": "^6.4.1",
33 | "babel-polyfill": "^6.23.0",
34 | "babel-preset-es2015": "^6.24.0",
35 | "babel-preset-stage-2": "^6.22.0",
36 | "cross-env": "^4.0.0",
37 | "eslint": "^3.19.0",
38 | "eslint-config-standard": "^10.2.0",
39 | "eslint-plugin-import": "^2.2.0",
40 | "eslint-plugin-node": "^4.2.2",
41 | "eslint-plugin-promise": "^3.5.0",
42 | "eslint-plugin-standard": "^3.0.1",
43 | "osascript": "^1.2.0",
44 | "webpack": "^2.3.3"
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## memory
2 | 这是后期合成软件Adobe After Effects的层存储脚本,你可以将AE中任何层(包括合成层)保存下来,以便在其他工程中,在其他版本的AE中,甚至在其他电脑中生成新的层
3 |
4 | ## 文档
5 | - [中文文档](https://smallpath.github.io/memory)
6 | - [安装](https://smallpath.github.io/memory/#/?id=安装)
7 | - [English Document](https://smallpath.github.io/memory/#/en/)
8 |
9 | ## 脚本功能
10 | 1. 支持动态预览元素内容, 支持窗口大小自适应,同时拥有方便的右键菜单来节省界面空间
11 | 2. 支持一切层的存储与生成,包括形状层,文字层,图片音频层,甚至`合成层`
12 | 3. 支持几乎所有属性的存储与生成,包括层本身属性以及层内部属性组,例如插件,遮罩,文字动画器,形状效果器,图层样式等等
13 | 4. 支持任何素材层,例如图片,音频甚至是视频,即使他们被移动或删除,脚本也可以正确生成
14 | 5. 由语言版本不同造成的表达式报错将被自动修复,默认支持英文,中文,日文三种语言
15 | 6. 支持自定义预设,脚本提供插件,遮罩,动画器等9种属性组的自由搭配选项
16 | 7. 存储得到的数据兼容于AE任何版本,例如,用本脚本在CC2017上存储的一个工程,可以在CC上正确地生成
17 |
18 | ## 开发
19 | - [x] Node.js > v4.0
20 | - [x] Yarn.js
21 |
22 | ```
23 | # 安装依赖
24 | yarn
25 |
26 | # 开发
27 | yarn run dev
28 |
29 | # 构建
30 | yarn run build
31 | ```
32 |
33 | ## 感谢
34 | - 阿木亮([GridView.js](https://github.com/smallpath/memory/blob/master/lib/GridView.js),[UIParser.js](https://github.com/smallpath/memory/blob/master/lib/UIParser.js))
35 | - 水果硬糖([UIParser.js](https://github.com/smallpath/memory/blob/master/lib/UIParser.js))
36 |
37 | ## License
38 | ```
39 | Copyright (C) 2015 smallpath
40 |
41 | Licensed under the Apache License, Version 2.0 (the "License");
42 | you may not use this file except in compliance with the License.
43 | You may obtain a copy of the License at
44 |
45 | http://www.apache.org/licenses/LICENSE-2.0
46 |
47 | Unless required by applicable law or agreed to in writing, software
48 | distributed under the License is distributed on an "AS IS" BASIS,
49 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
50 | See the License for the specific language governing permissions and
51 | limitations under the License.
52 | ```
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | parser: 'babel-eslint',
4 | parserOptions: {
5 | sourceType: 'module'
6 | },
7 | // https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style
8 | extends: 'standard',
9 | globals: {
10 | "sp": true,
11 | "$": true,
12 | "Panel": true,
13 | "Folder": true,
14 | "GridView": true,
15 | "Window": true,
16 | "app": true,
17 | "File": true,
18 | "prompt": true,
19 | "alert": true,
20 | "XML": true,
21 | "confirm": true,
22 | "loc": true,
23 | "CompItem": true,
24 | "ScriptUI": true,
25 | "Socket": true,
26 | "ImportOptions": true,
27 | "ImportAsType": true,
28 | "cout": true,
29 | "clearOutput": true,
30 | "writeLn": true,
31 | "PropertyType": true,
32 | "Language": true,
33 | "system": true,
34 | "TextLayer": true,
35 | "LightLayer": true,
36 | "ShapeLayer": true,
37 | "AVLayer": true,
38 | "SolidSource": true,
39 | "FileSource": true,
40 | "CameraLayer": true,
41 | "Shape": true,
42 | "KeyframeEase": true,
43 | "PropertyValueType": true,
44 | "MarkerValue": true,
45 | "PurgeTarget": true,
46 | "memoryGlobal": true
47 | },
48 | // add your custom rules here
49 | 'rules': {
50 | // allow paren-less arrow functions
51 | 'arrow-parens': 0,
52 | // allow async-await
53 | 'generator-star-spacing': 0,
54 | 'space-before-function-paren': ['error', 'never'],
55 | 'no-return-assign': 0,
56 | 'no-extend-native': 'off',
57 | 'no-unused-expressions': 'off',
58 | 'no-caller': 'off',
59 | 'no-mixed-operators': 'off',
60 | 'no-template-curly-in-string': 'off',
61 | 'new-cap': 'off',
62 | 'no-multi-str': 'off',
63 | 'no-useless-escape': 'off',
64 | // allow debugger during development
65 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/lib/ReloadPic.js:
--------------------------------------------------------------------------------
1 | /** ***********************************自动重载图片**************************************/
2 | $.global.reloadPic = reloadPic
3 | function reloadPic() {
4 | var thisComp = app.project.activeItem
5 | if (!(thisComp instanceof CompItem)) return alert(loc(sp.needComp))
6 | if (!sp.droplist.selection) return
7 |
8 | if (confirm(loc(sp.refresh)) === false) return
9 |
10 | var frames = prompt(loc(sp.reloadNeedFrames), '')
11 | var shouldLimit = true
12 | if (!frames || isNaN(frames)) shouldLimit = false
13 | if (frames === '') shouldLimit = false
14 |
15 | try {
16 | frames = parseInt(frames)
17 | var SpeciallimitTime = frames / thisComp.frameRate
18 | } catch (err) { }
19 |
20 | var preRenameValue = sp.autoNameValue
21 | sp.autoNameValue = true
22 | var preCompValue = sp.preComposeValue
23 | sp.preComposeValue = false
24 |
25 | for (var i = 0; i < sp.gv.children.length; i++) {
26 | try {
27 | sp.gv.children[i].selected = true
28 |
29 | try {
30 | sp.gv.children[i - 1].selected = false
31 | } catch (err) { }
32 |
33 | sp.gv.lastSelectedItem = sp.gv.children[i]
34 |
35 | var layerArr = sp.fns.newLayer()
36 | var j
37 | for (j = 0; j < thisComp.selectedLayers.length; j++) {
38 | thisComp.selectedLayers[j].selected = false
39 | }
40 |
41 | if (!layerArr) continue
42 |
43 | if (!(layerArr instanceof Array)) layerArr = [layerArr]
44 |
45 | for (j = 0; j < layerArr.length; j++) {
46 | layerArr[j].selected = true
47 |
48 | if (shouldLimit === false) continue
49 |
50 | if (layerArr[j].outPoint > SpeciallimitTime) {
51 | layerArr[j].outPoint = SpeciallimitTime
52 | }
53 | }
54 |
55 | sp.fns.cover()
56 |
57 | for (j = layerArr.length - 1; j >= 0; j--) {
58 | layerArr[j].remove()
59 | }
60 |
61 | sp.gv.children[i].selected = false
62 | } catch (err) { alert(err.line.toString() + '\r' + err.toString()) }
63 | }
64 |
65 | sp.autoNameValue = preRenameValue
66 | sp.preComposeValue = preCompValue
67 | sp.gv.refresh()
68 | }
69 |
--------------------------------------------------------------------------------
/docs/LOGS.md:
--------------------------------------------------------------------------------
1 | ### 3.1 Date:soon
2 | ## 优化
3 | - 更换打包工具以提供直观的报错定位
4 | - 支持存储视频, 去除素材的大小限制
5 | - 生成层进度条
6 | - 存储层进度条
7 | - 进度条显示脚本耗时
8 | - 存储预览进度条
9 | - 优化预览CPU占用
10 | - 生成单个预合成时直接拉伸至当前合成大小
11 | - 增加允许截取工作区预览的检测框
12 | - 修复检查更新功能
13 | - 增加自动更新功能
14 | - 增加windows缩放比例参数
15 |
16 | ## 漏洞修复
17 | - 修复音频层关键帧未生成的问题
18 | - 修复windows缩放比例不为1时的界面越界问题
19 | - 修复界面中一些特殊文字的错位问题
20 | - 修复windows禁止字符导致预览存储失败的问题
21 | - 修复最小化时关掉脚本导致的脚本大小归零的问题
22 | - 修复windows特殊字符串导致的模块,组以及元素生成失败的问题
23 | - 修复mac CC2017中表达式翻译无法使用的问题
24 | - 修复setInterpolationTypeAtKey的关键帧生成报错
25 | - 修复非1080p的右键菜单越界的问题
26 |
27 | ### 3.0 Date:2016-04-07
28 |
29 | [发布地址](http://tieba.baidu.com/p/4462854806)
30 |
31 | - 添加预览动画
32 | - 界面支持预览动画的播放
33 | - 添加组的分类-模块
34 | - 修正CC2015无法裁剪缩略图的问题
35 |
36 | ### 2.2 Date:2016-03-20
37 | - 重构代码
38 | - 生成时将默认翻译表达式
39 | - 添加一种新类型的缩略图,支持CS6-CC2014
40 | - 生成加速5%
41 | - 解决内存泄漏的问题
42 | - 解决脚本停止运行的问题
43 | - 修正win10下右侧滑块不能下拉到最下面的问题
44 | - 修正检测框状态保存失败的问题
45 | - 修正老界面删除组失败的相关问题
46 | - 修正存储时相同名字导致的图片更新不及时的问题
47 |
48 | ### 2.1 Date:2015-11-05
49 | - 添加组级别的出错处理
50 | - 非Panel模式打开脚本时添加快捷键
51 | - 添加裁剪新界面上文字的长度的选项
52 | - 存储过程加速10%
53 |
54 | ### 2.0 Date:2015-10-07
55 |
56 | [发布地址](http://tieba.baidu.com/p/4087269643)
57 |
58 | - 添加新界面(支持CC,CC2014,CC2015),支持图片自动排列,支持多选
59 | - 添加一些设置选项
60 | - 添加关键帧插值与roving的支持
61 | - 添加LayerIndex与MaskIndex类型的属性的支持
62 | - 添加光线追踪层的支持
63 | - 添加检查更新的功能
64 | - 添加记忆脚本窗口位置与大小的功能
65 | - 修正一些BUG
66 |
67 | ### 1.3 Date:2015-07-02
68 |
69 | [发布地址](http://tieba.baidu.com/p/3866311869)
70 |
71 | - 添加AE CC2015的支持
72 | - 添加快速存储辅助脚本
73 | - 添加批量导出功能
74 | - 修正一些BUG
75 |
76 | ### 1.2 Date:2015-05-16
77 |
78 | [发布地址](http://tieba.baidu.com/p/3766894868)
79 |
80 | - 添加AE CS3,CS4,CS5,CS5.5的支持
81 | - 新增第五检测框,关键帧偏移检测框,并在右键菜单中新增其选项
82 | - 新增第六检测框,清空层内容检测框
83 | - 新增预设功能
84 | - 修正一些BUG
85 |
86 | ### 1.1 Date:2015-04-19
87 |
88 | [发布地址](http://tieba.baidu.com/p/3711493077)
89 |
90 | - 启用第四检测框,存储素材
91 | - 在设置菜单中添加清空临时文件夹的快捷按钮
92 | - 在设置菜单中增加重命名选中组的按钮
93 | - 在右键菜单中增加重命名选中元素的按钮
94 | - 在设置菜单中增加中英文界面切换的按钮
95 | - 修正一些BUG
96 |
97 | ### 1.0 Date:2015-04-13
98 |
99 | [发布地址](http://tieba.baidu.com/p/3699068264)
100 |
101 | - 新增合成层支持
102 | - 添加AE CS6,CC,CC2014的支持
103 |
--------------------------------------------------------------------------------
/src/ui/moveGroupWindow.js:
--------------------------------------------------------------------------------
1 | var settingsButtonFunc = require('./settingWindow')
2 |
3 | module.exports = function(xmlItem, groupItem, win) {
4 | var moveWin = new Window('dialog', 'Move', undefined, {
5 | resizeable: 0,
6 | maximizeButton: 0
7 | })
8 | var outRes = `Group{
9 | orientation: 'column', alignment:['fill', 'fill'], alignChildren:['fill', 'fill'],\
10 | wlist:ListBox{properties:{multiselect:0}},
11 | oc:Group{
12 | alignment:['fill', 'fill'], alignChildren:['fill', 'fill'],
13 | ok:Button{text:'` + loc(sp.ok) + `'},
14 | cancel:Button{text:'` + loc(sp.cancel) + `'}
15 | }
16 | }`
17 | try {
18 | outRes = moveWin.add(outRes)
19 | } catch (err) {
20 | alert(err)
21 | }
22 | sp.xmlGroupNames.forEach(function(item, index) {
23 | this.add('item', item)
24 | }, outRes.wlist)
25 |
26 | outRes.oc.cancel.onClick = function() {
27 | moveWin.close()
28 | win.close()
29 | settingsButtonFunc()
30 | }
31 |
32 | outRes.oc.ok.onClick = function() {
33 | if (!outRes.wlist.selection) return
34 | if (outRes.wlist.selection.text === groupItem.text) return
35 | var xml = new XML(sp.settingsFile.readd())
36 | var parentGroup = xml.ParentGroup
37 | var xmlIndex = xmlItem.index
38 | var groupIndex = groupItem.index
39 |
40 | var editXml = parentGroup.child(groupIndex).child(xmlIndex)
41 | var targetXml = parentGroup.child(outRes.wlist.selection.index)
42 | targetXml.appendChild(new XML(editXml))
43 |
44 | parentGroup.child(groupIndex).child(xmlIndex).setLocalName('waitToDelete')
45 | delete parentGroup.child(groupIndex).waitToDelete
46 | sp.settingsFile.writee(xml)
47 |
48 | sp.reloadParentDroplist()
49 | var selection = parseInt(sp.getSetting('parentSelection'))
50 | sp.parentDroplist.selection = (selection <= sp.parentDroplist.items.length - 1 && selection >= 0) ? selection : 0
51 | selection = parseInt(sp.getSetting('thisSelection'))
52 | sp.droplist.selection = (selection <= sp.droplist.items.length - 1 && selection >= 0) ? selection : 0
53 |
54 | moveWin.close()
55 | win.close()
56 | settingsButtonFunc()
57 | } // last
58 |
59 | outRes.wlist.size = [200, 300]
60 | moveWin.show()
61 | }
62 |
--------------------------------------------------------------------------------
/src/layer/progressFactory.js:
--------------------------------------------------------------------------------
1 | var global = $.global
2 |
3 | var parentProgress = require('../ui/previewProgress')
4 |
5 | var progressFactory = {
6 | createWindow: function(len, title, prefixString, suffixString) {
7 | if (global.progressWin) {
8 | global.progressBar.maxvalue = len
9 | return
10 | }
11 | parentProgress.createWindow(len, title, prefixString, suffixString)
12 | },
13 | update: function(len, prefixString, suffixString, timePrefix, timeSuffix) {
14 | parentProgress.update(len, prefixString, suffixString, timePrefix, timeSuffix)
15 | },
16 | complete: function(timePrefix, timeSuffix) {
17 | parentProgress.complete(timePrefix, timeSuffix)
18 | global.progressWin = null
19 | global.progressTimeText = null
20 | global.progressText = null
21 | global.progressBar = null
22 | }
23 | }
24 |
25 | var timeSuffix = loc(sp.second)
26 | // saving process window
27 | var savingReport = loc(sp.savingReport)
28 | var savingPrefixString = loc(sp.savingProcessingPrefix)
29 | var savingSuffixString = loc(sp.savingProcessAfter)
30 | var savingTitle = loc(sp.savingProcessTitle)
31 | $.layer.willSaveLayers = function(layers) {
32 | var len = $.layer.countLayers(layers, true)
33 | progressFactory.createWindow(
34 | len,
35 | savingTitle,
36 | savingPrefixString,
37 | savingSuffixString
38 | )
39 | }
40 | $.layer.didSaveLayer = function(count) {
41 | progressFactory.update(
42 | count,
43 | savingPrefixString,
44 | savingSuffixString,
45 | savingReport,
46 | timeSuffix
47 | )
48 | }
49 | $.layer.didSaveLayers = function() {
50 | $.layer.didSaveLayer(0)
51 | progressFactory.complete(savingReport, timeSuffix)
52 | }
53 |
54 | // generating process window
55 | var creatingReport = loc(sp.creatingReport)
56 | var creatingPrefixString = loc(sp.creatingProcessingPrefix)
57 | var creatingSuffixString = loc(sp.creatingProcessAfter)
58 | var creatingTitle = loc(sp.creatingProcessTitle)
59 |
60 | $.layer.willCreateLayers = function(len) {
61 | progressFactory.createWindow(
62 | len,
63 | creatingTitle,
64 | creatingPrefixString,
65 | creatingSuffixString
66 | )
67 | }
68 | $.layer.didCreateLayer = function(count) {
69 | progressFactory.update(
70 | count,
71 | creatingPrefixString,
72 | creatingSuffixString,
73 | creatingReport,
74 | timeSuffix
75 | )
76 | }
77 | $.layer.didCreateLayers = function() {
78 | $.layer.didCreateLayer(0)
79 | progressFactory.complete(creatingReport, timeSuffix)
80 | }
81 |
82 | module.exports = progressFactory
83 |
--------------------------------------------------------------------------------
/src/polyfill.js:
--------------------------------------------------------------------------------
1 | module.exports = (function() {
2 | require('lib/OperatorOverload')
3 |
4 | sp.extend(sp, {
5 | forEach: function(xml, callback, context) {
6 | if (!(xml instanceof XML)) return
7 | var i,
8 | len
9 | for (i = 0, len = xml.children().length(); i < len; i++) {
10 | if (callback.call(context, xml.child(i), i, xml) === false) {
11 | break
12 | }
13 | }
14 | }
15 | })
16 |
17 | String.prototype.trim = String.prototype.trim || function() {
18 | return this.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '')
19 | }
20 |
21 | Array.prototype.includes = function(value) {
22 | for (var i = 0, len = this.length; i < len; i++) {
23 | if (this[i] === value) {
24 | return true
25 | }
26 | }
27 | return false
28 | }
29 |
30 | Array.prototype.forEach = function(callback, context) {
31 | if (Object.prototype.toString.call(this) === '[object Array]') {
32 | var i, len
33 | for (i = 0, len = this.length; i < len; i++) {
34 | if (typeof callback === 'function' && Object.prototype.hasOwnProperty.call(this, i)) {
35 | if (callback.call(context, this[i], i, this) === false) {
36 | break
37 | }
38 | }
39 | }
40 | }
41 | }
42 |
43 | Error.prototype.print = Error.prototype.print || function() {
44 | return 'Line #' + this.line.toString() + '\r\n' + this.toString()
45 | }
46 |
47 | Error.prototype.printc = Error.prototype.printc || function() {
48 | cout << '\n---------'
49 | cout << this.print()
50 | cout << '---------\n'
51 | }
52 |
53 | Error.prototype.printa = Error.prototype.printa || function() {
54 | this.print() << cout
55 | }
56 |
57 | File.prototype.writee = function(str) { // method to write file
58 | this.open('w')
59 | this.write(str)
60 | this.close()
61 | }
62 |
63 | File.prototype.readd = function() { // method to read from file
64 | this.open('r')
65 | var temp = this.read()
66 | this.close()
67 | return temp
68 | }
69 |
70 | Array.prototype.pushh = function(str) { // chains call for Array.push()
71 | this.push(str)
72 | return this
73 | }
74 |
75 | sp.deleteThisFolder = function(folder) {
76 | var waitClFile = folder.getFiles()
77 | for (var i = 0; i < waitClFile.length; i++) {
78 | if (waitClFile[i] instanceof Folder) {
79 | sp.deleteThisFolder(waitClFile[i])
80 | waitClFile[i].remove()
81 | } else {
82 | waitClFile[i].remove()
83 | }
84 | }
85 | }
86 | })()
87 |
--------------------------------------------------------------------------------
/src/startup.js:
--------------------------------------------------------------------------------
1 | module.exports = (function() {
2 | if (!(sp.settingsFile.exists) || sp.settingsFile.length === 0) {
3 | if (sp.settingsFile.exists) sp.settingsFile.remove()
4 | var settingsText =
5 | '\
6 | \
7 | \
8 | '
9 | var newsettingsxml = new XML(settingsText)
10 | var allFiles = sp.scriptFolder.getFiles()
11 | newsettingsxml.ParentGroup.appendChild(new XML(" "))
12 | var i = 0
13 | allFiles.forEach(function(item, index) {
14 | if (item.toString().indexOf('.xml') !== -1 && item.name.indexOf('settings.xml') === -1) {
15 | newsettingsxml.ListItems.appendChild(new XML('' + item.displayName.replace('.xml', '') + ''))
16 | newsettingsxml.ParentGroup.child(0).appendChild(new XML('' + i + ''))
17 | i++
18 | }
19 | })
20 | sp.settingsFile.writee(newsettingsxml)
21 | }
22 |
23 | // If the file do not have the ParentGroup,add parentGroup to it
24 | var content = new XML(sp.settingsFile.readd())
25 | if (!content.hasOwnProperty('ParentGroup')) { content.appendChild(new XML('')) }
26 | if (content.ParentGroup.children().length() === 0) {
27 | content.ParentGroup.appendChild(new XML(" "))
28 | sp.forEach(content.ListItems, function(item, index) {
29 | content.ParentGroup.child(0).appendChild(new XML('' + index.toString() + ''))
30 | })
31 | sp.settingsFile.writee(content)
32 | }
33 |
34 | // If the file do not have a group,give it
35 | content = new XML(sp.settingsFile.readd())
36 | if (!content.hasOwnProperty('ListItems')) { content.appendChild(new XML('')) }
37 | if (content.ListItems.children().length() === 0) {
38 | allFiles = sp.scriptFolder.getFiles()
39 | allFiles.forEach(function(item, index) {
40 | if (item.toString().indexOf('.xml') !== -1 && item.name.indexOf('settings.xml') === -1) {
41 | content.ListItems.appendChild(new XML('' + item.displayName.replace('.xml', '') + ''))
42 | content.ParentGroup.child(0).appendChild(new XML('' + index.toString() + ''))
43 | }
44 | })
45 | }
46 | if (content.ListItems.children().length() === 0) {
47 | content.ListItems.appendChild(new XML('Default'))
48 | content.ParentGroup.child(0).appendChild(new XML('' + 0 + ''))
49 | var file = sp.getFileByName('Default')
50 | sp.getImageFolderByName('Default')
51 | var str = ''
52 | file.writee(str)
53 | }
54 |
55 | sp.settingsFile.writee(content)
56 | })()
57 |
--------------------------------------------------------------------------------
/docs/en/README.md:
--------------------------------------------------------------------------------
1 | ## memory
2 | This is a script for Adobe After Effects.It can save any layer even `composition layer` in AE ,so you can create these layers in another project,another version of ae and even another computer
3 |
4 | ## Support
5 | AE CC,CC2014,CC2015 and CC2017 on Windows system
6 |
7 | ## User Interface
8 | memory supports preview animation,what you have watched is what it will be after generating layers
9 | 
10 | 
11 | 
12 | Script layouts automatically according to window size.Moreover,it has right-click menu to reduce space for you
13 |
14 | ## Script Feature
15 | 1. Supporting preview element, you can set the frame numbers and frame rate of preview animation.
16 | 2. Supporting any layer, such as Shape layer,Text layer,Image layer,Music layer and even `Composition layer`
17 | 3. Supporting any property,including Plugin,Mask,Text Animator,Shape Effector,Layer Style and so on.
18 | 4. Supporting storing image and music.Even if the material has been removed, it can be generated correctly by memory
19 | 5. Supporting fixing the expression error caused by using different launguage of AE.Lauguage supported includes English,Chinese,Japanese and ADBE.
20 | 6. Supporting preset which has 9 types of PropertyGroup such as Plugin,Mask,Text Animator and Transform.
21 | 7. Supporting cross-version.For example, if you save a composition layer in AE CC2015,memory can generate that layer perfectly in AE CS4
22 |
23 | ## Installation
24 | Go to [release page](https://github.com/smallpath/memory/releases).Download the latest version by clicking `Sp_memory.zip`
25 | Extract the `Sp_memory.jsxbin` to your AE script folder,something like `Support Files\Scripts\ScriptUI Panels`
26 | If your windows is win8 or win10, make sure AE is running under the administrator access
27 | In AE, go to `Edit->Preferences->General`,make sure `Allow scripts to write File and access Network` is checked
28 | Open script from `Window->Sp_memory.jsxbin`
29 |
30 | !> The default language is not English. To force English, just add a `force_en.txt` file in `Sp_memory` folder and restart script.
31 |
32 | ## Usage
33 | >[Usage](en/TUTORIAL.md)
34 |
35 |
36 | ## ChangeLog
37 | >[Change Log](en/LOGS.md)
38 |
39 |
40 | ## Development
41 | - [x] Node.js > v4.0
42 | - [x] Yarn.js
43 |
44 | ```
45 | # install
46 | yarn
47 |
48 | # development
49 | yarn run dev
50 |
51 | # build
52 | yarn run build
53 | ```
54 |
55 | ## Feedback
56 | If you encounter any problems or have any feedback, please open an issue.
57 |
--------------------------------------------------------------------------------
/src/ui/moveItemWindow.js:
--------------------------------------------------------------------------------
1 |
2 | var upAndDown = function(isUp, isW) {
3 | var file = sp.getFileByName(sp.droplist.selection.text)
4 | var xml = new XML(file.readd())
5 | if (isUp === true && sp.gv.lastSelectedItem !== null && sp.gv.lastSelectedItem.index > 0) {
6 | var upxml = new XML(xml.child(sp.gv.lastSelectedItem.index))
7 | xml.insertChildBefore(xml.child(sp.gv.lastSelectedItem.index - 1), upxml)
8 | xml.child(sp.gv.lastSelectedItem.index + 1).setLocalName('waitToDelete')
9 | delete xml.waitToDelete
10 | file.writee(xml)
11 | sp.gv.lastSelectedItem.moveUp()
12 | } else if (isUp === false && sp.gv.lastSelectedItem !== null && sp.gv.lastSelectedItem.index < xml.children().length() - 1) {
13 | var downxml = new XML(xml.child(sp.gv.lastSelectedItem.index))
14 | xml.insertChildAfter(xml.child(sp.gv.lastSelectedItem.index + 1), downxml)
15 | xml.child(sp.gv.lastSelectedItem.index).setLocalName('waitToDelete')
16 | delete xml.waitToDelete
17 | file.writee(xml)
18 | sp.gv.lastSelectedItem.moveDown()
19 | }
20 | }
21 |
22 | module.exports = function(cu) {
23 | var udWin = new Window('palette', loc(sp.ud))
24 | var udWins = udWin.add('Group{}')
25 | var a = udWins.add("Button{text:'" + loc(sp.up) + "'}")
26 | var b = udWins.add("Button{text:'" + loc(sp.down) + "'}")
27 | var c = udWins.add("Group{et:EditText{text:'0',characters:3,justify:'center'},j:Button{text:'" + loc(sp.jmp) + "'}}")
28 | udWin.frameLocation = cu
29 | udWin.show()
30 | a.onClick = function() {
31 | upAndDown(true, true)
32 | }
33 | b.onClick = function() {
34 | upAndDown(false, true)
35 | }
36 | c.j.onClick = function() {
37 | var d = parseInt(c.et.text)
38 | var file = sp.getFileByName(sp.droplist.selection.text)
39 | var xml = new XML(file.readd())
40 | if (sp.gv.children.length === 0) return
41 | if (sp.gv.lastSelectedItem === null) return
42 | if (d >= 0 && d < sp.gv.children.length - 1 && sp.gv.lastSelectedItem.index !== d) {
43 | var upxml = new XML(xml.child(sp.gv.lastSelectedItem.index))
44 | xml.insertChildBefore(xml.child(d), upxml)
45 | xml.child(sp.gv.lastSelectedItem.index + 1).setLocalName('waitToDelete')
46 | delete xml.waitToDelete
47 | file.writee(xml)
48 | sp.gv.lastSelectedItem.moveBefore(sp.gv.children[d])
49 | } else if (d === sp.gv.children.length - 1 && sp.gv.lastSelectedItem.index !== d) {
50 | upxml = new XML(xml.child(sp.gv.lastSelectedItem.index))
51 | xml.insertChildAfter(xml.child(d), upxml)
52 | xml.child(sp.gv.lastSelectedItem.index + 1).setLocalName('waitToDelete')
53 | delete xml.waitToDelete
54 | file.writee(xml)
55 | sp.gv.lastSelectedItem.moveAfter(sp.gv.children[d])
56 | } else {
57 | try {
58 | alert(loc(sp.from) + '~' + (sp.gv.children.length - 1).toString())
59 | } catch (er) { }
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 | ## memory
2 | 这是后期合成软件Adobe After Effects的层存储脚本,你可以将AE中任何层(包括合成层)保存下来,以便在其他工程中,在其他版本的AE中,甚至在其他电脑中生成新的层
3 |
4 | ## 环境要求
5 | Windows系统, AE版本为CC,CC2014,CC2015,CC2017
6 |
7 | ## 界面演示
8 | 支持动态预览元素内容, 支持窗口大小自适应, 同时拥有方便的**右键菜单**来节省界面空间
9 | 
10 | 
11 | 
12 |
13 | ## 功能
14 | 1. 脚本界面支持预览动画,可以设置预览动画的帧率和帧数
15 | 2. 支持一切层,包括形状层,文字层,图片音频层,甚至`合成层`
16 | 3. 支持一切属性,包括层本身属性以及层内部属性组,例如插件,遮罩,文字动画器,形状效果器,图层样式等等
17 | 4. 支持图片和音频,即使他们被移动或删除,脚本也可以正确生成
18 | 5. 由语言版本不同造成的表达式报错将被自动修复,支持英文,中文,日文三种语言
19 | 6. 支持自定义预设,脚本提供插件,遮罩,动画器等9种属性组的自由搭配选项
20 | 7. 存储得到的数据兼容于AE任何版本,例如,用本脚本在CC2015上存储的一个工程,可以在CC上正确地生成
21 |
22 | ## 安装
23 | 进入 [版本页面](https://github.com/smallpath/memory/releases), 下载最新版本的`Sp_memory.zip`
24 | 请将`Sp_memory.jsx`脚本放置在你的AE脚本文件夹中, 通常在`path\to\ae\Support Files\Scripts\ScriptUI Panels`
25 | 在AE中打开`窗口`菜单中的`Sp_memory.jsx`即可
26 |
27 | !> 下载下来的压缩包中包含三个拥有预览动画的素材包用于演示, 请在解压后, 在脚本界面上`右键->导入组`并全选素材文件
28 |
29 | ## 常见使用问题
30 |
31 | ### 版本相关
32 | - memory推荐的AE版本是?
33 | - AE CC2017, 它存储预览的速度是之前的十倍以上, 很适合经常存储素材的用户
34 | - CC2015无法使用表达式翻译,怎样解决?
35 | - AE CC2015砍掉了脚本权限, 所有依赖表达式的脚本均无法工作, 建议使用其他版本
36 | - v3.1版本的进度条在windows上几秒钟就停止响应了,如何解决?
37 | - 这与脚本以及AE无关, 而是由windows自行控制, 提高windows注册表中的hungAppTimeout的值即可
38 | - 脚本可以成功运行在mac平台的AE上, 为什么文档中却说不支持mac平台?
39 | - mac版AE的性能非常弱, 会在文件大于50M时出现磁盘I/O断崖式下跌的现象, 导致脚本停止响应
40 | - 详细的数据是, 7M文件只需7秒, 70M文件则需要7分钟, 100M的文件半个小时也无法写完.
41 | - 因此, 不建议在mac上使用本脚本
42 | - 脚本如何升级?
43 | - 右键v3.1脚本, 设置中**检查更新**即可, 建议经常使用脚本的用户将**启动时检查更新**也勾选上
44 | - 如果没有找到设置中的**启动时检查更新**, 那么说明你使用的并不是最新的脚本
45 |
46 | ### 错误相关
47 | - 弹窗中错误提示数字看不懂, 代表什么意思?
48 | - 首先, v3.1将错误暴露给了用户, 打开源脚本查看对应行数的代码即可, 非最新版本的报错将不会被处理
49 | - 另外, `Sp_memory/tempFile/error.txt`包含脚本的运行时错误, 请在上报错误时一并提交文件内容
50 | - 脚本无法新建组与保存层,错误代码提示1251
51 | - win8-win10用户请使用管理员权限运行AE
52 | - 如果是首次使用脚本,请在AE中打开`编辑->预选项->一般`,勾选`允许脚本访问文件与网络`
53 | - AE CC2015.3 使用Memory无法存储, 错误代码提示1321
54 | - memory v3.0不向上兼容, 只有经过测试的版本才会加上支持. 开发版本已经添加了CC2015.3, 请查看脚本安装部分进行安装
55 |
56 | ### 使用相关
57 | - 手动存储每一个合成非常麻烦, 有更好的办法吗?
58 | - 可以通过`右键->自动存储每一层`功能来批量存储`Motion Graphics`合成层
59 | - 我存储的素材如何备份?
60 | - 直接备份脚本同目录的`Sp_memory`文件夹即可
61 | - v3版本无法预览之前存储的元素,应该怎样解决?
62 | - `右键->重载组内预览动画`,即可进行预览动画的生成
63 | - v2支持CS3至CC2017,为什么v3只支持CC至CC2017?
64 | - 因为预览特性对AE环境非常苛刻,目前只有CC及以上版本能够通过测试
65 | - 但是,v3存储的元素,一样能够正确导出到v2中并进行层的生成
66 | - 是否有更多的`Motion Graphics`素材包以供下载?
67 | - 因为版权原因, 只提供三个素材包作为示范, memory只作为一个存储生成层的平台, 不提供原始素材包
68 |
69 | ## 脚本使用教程
70 | >[文字教程](TUTORIAL.md)
71 |
72 | ## 版本更新记录
73 | >[更新历史](LOGS.md)
74 |
75 | ## 开发
76 | - [x] Node.js > v4.0
77 | - [x] Yarn.js
78 |
79 | ```
80 | # 安装依赖
81 | yarn
82 |
83 | # 开发
84 | yarn run dev
85 |
86 | # 构建
87 | yarn run build
88 | ```
89 | windows上开发时, 建议对AE窗口使用`ctrl + \`快捷键, 否则自动刷新每次都会缩放AE窗口
90 |
91 | ## 反馈
92 | 脚本使用中遇到任何问题, 请[新开issue](https://github.com/smallpath/memory/issues/new), 或联系smallpath2013@gmail.com
93 |
--------------------------------------------------------------------------------
/docs/TUTORIAL.md:
--------------------------------------------------------------------------------
1 | ## 打开脚本
2 |
3 | #### Panel模式
4 | 将脚本复制至AE的ScriptUI Panels文件夹,重启AE后,在AE的窗口栏中打开Sp_memory.jsxbin
5 |
6 | #### 非Panel模式
7 | 点击`AE->文件->脚本->打开脚本`,打开Sp_memory.jsxbin即可.
8 | 非Panel模式打开时,脚本支持快捷键,具体快捷键信息在设置窗口中.
9 |
10 | ## 元素
11 | 脚本面板中,可以被选中的之后统称为元素
12 |
13 | ## 保存层
14 |
15 | `右键->新建元素`,即可保存AE中已被选中的层.
16 | 如果右键菜单中的'存储预览被打开',则脚本将存储选中层的预览动画,范围为选中层的最小入点到最大出点
17 | 快捷键为:脚本面板中进行`Ctrl+右键` 或者 `Alt+右键`
18 |
19 | ## 生成层
20 | `右键->生成层`,即可在当前合成中生成新层
21 | 快捷键为:双击元素
22 |
23 | ## 覆盖元素
24 | 选中元素后,在选中了层的情况下,`右键->覆盖元素`,即可用选中层的信息覆盖选中元素的内容
25 |
26 | ## 移动元素
27 | `Shift+右键`,即可弹出元素移动的窗口
28 |
29 | ## 批量存储
30 | `右键->辅助脚本->自动存储每一层`,可将当前合成的每一层都单独存储为一个元素
31 | 十分适合存储MG合成层
32 |
33 | ## 右键菜单的检测框
34 | ```
35 | 一般:
36 | 显示文字: 是否显示元素的名称
37 |
38 | 保存层:
39 | 自动取名: 保存层为元素时,是否自动给元素取名
40 | 存储预览: 保存层时,是否存储层的预览动画
41 | 存储素材: 保存层时,是否存储图片和音频.存储素材之后,如果原图片和音频被删除,脚本将会自动生成图片和音频
42 |
43 | 生成层:
44 | 预合成: 生成层时,是否将生成的所有层进行预合成
45 | 仅生成效果: 生成层时,是否不生成层,而是只在选中的层上生成当前元素里的属性组(即插件,遮罩,文字动画器等等)
46 | 清空属性组: 如果仅生成效果被打开,则决定是否在生成属性组前将原层里的原属性组清空
47 | 关键帧偏移: 如果仅生成效果被打开,则决定是否将关键帧按被选中层的进入时间进行偏移
48 | ```
49 |
50 | ## 重载预览动画
51 | `右键->辅助脚本->重载组内预览动画`,即可为v3.0前保存的组进行预览动画的生成操作
52 | 可选项为是否限定最大帧数,如输入最大帧数,则脚本将限定预览动画范围为(0-最大帧数)
53 |
54 | ## 修复表达式报错
55 | `右键->辅助脚本->表达式翻译`,按需求选择需翻译的合成和目标语言,可修正语言版本不同导致的表达式报错
56 | 目前支持语言为中文,英文,日文和ADBE(Adobe通用标志名称)
57 | 生成时,如侦测到错误表达式,脚本将会自动进行表达式翻译.
58 |
59 | ## 预览全部/预览选中
60 | 没有元素被选中时,右键菜单中的预览按钮变为`预览全部`,点击后所有元素将会播放预览动画.
61 | 有元素被选中时,右键菜单中的预览按钮变为`预览部分`,点击后被选中的元素将会播放预览动画.
62 | 可使用Ctrl和Shift对元素进行多选和反选
63 |
64 | ## 导入图片
65 | `右键->导入图片`,可为选中的元素导入图片.
66 | 图片将会被脚本自动裁剪至缩略图大小
67 |
68 | ## 导入组
69 | `右键->导入组`,可进行导入组的操作,支持多选
70 |
71 | ## 新建组
72 | `右键->新建组`,可新建一个组.
73 | 保存层时必须有当前组存在.
74 |
75 | ## 新建模块
76 | `右键->新建模块`,可新建一个模块
77 | 新建组和导入组时,会将新组建立在当前模块中
78 | 在设置窗口中,可将组剪贴到其他模块,或对模块进行移动和改名操作
79 |
80 | ## 设置
81 | `右键->设置`,可打开设置窗口
82 |
83 | #### 移动组
84 | 在右上角选中一个组,按小键盘的"↑"和"↓"键,即可上下移动元素
85 |
86 | #### 剪切选中组到其他模块
87 | 在右上角选中一个组后,可将此组剪贴到其他模块中
88 |
89 | #### 批量导出组
90 | 弹出所有组的窗口,可在多选后,批量导出组
91 |
92 | #### 清空素材文件夹
93 | 存储素材功能开启后,所有脚本生成的图片和音频都被生成在一个固定的文件夹中,点击此按钮即可清空此文件夹
94 |
95 | #### 限制新界面的文字
96 | 是否剪贴主界面上元素的文字长度,避免文字位置溢出,默认开启
97 |
98 | #### 覆盖时更新缩略图
99 | 是否在覆盖时更新缩略图.此指主缩略图,是否更新预览动画由`右键->存储预览`决定,默认关闭
100 |
101 | #### 启用另一种缩略图
102 | CC和CC2014中,可启用另一种缩略图.此缩略图为AE合成栏的当前视图,包含层边缘和3D轮廓等像素.默认关闭
103 |
104 | #### 删除时警告
105 | 是否在删除元素时警告.默认开启
106 |
107 | #### 生成供预览的图片序列时图片的数量
108 | CC和CC2014中最大值为50,CC2015最大值为300.
109 | 原因是CC2015存储预览动画的速度至少为其他版本的10倍.
110 |
111 | #### 收集生成层时的文件夹名
112 | 生成层时,所有生成的层将会被自动收集到一个与元素名同名的工程栏文件夹中.
113 | 脚本还会将这个文件夹放置在总文件夹中,以达到清爽的工程栏效果
114 | 此选项即决定了总文件夹的名称
115 |
116 | #### 默认开启仅生成效果的组名
117 | 以逗号分隔,如果当前组的名称被包含在这里,则默认勾选`右键->仅生成效果`
118 |
119 | #### 中文/English
120 | 切换中英文.切换完毕后请重启脚本
121 |
122 | #### 检查更新
123 | 手动检查脚本更新.
124 | 目前用作更新的服务器作者另有其他项目需要使用,因此更新功能暂时关闭
125 |
126 | ## 预设设置
127 | `右键->预设设置`,即可打开预设窗口
128 | 按左右分为两部分,'仅生成效果'和'清空属性组'
129 | 勾选和取消勾选都将会被动态存储,配置完毕后按OK即可退出
130 | 搭配两者的选项,将会实现十分强大的预设功能
131 |
132 | #### 仅生成效果
133 | 决定在`右键->仅生成效果`被勾选且时,将会被脚本生成的属性组.
134 | 默认为
135 | ```
136 | 遮罩
137 | 效果
138 | 图层样式
139 | 形状层形状组
140 | 文字层动画器
141 | ```
142 |
143 | #### 清空属性组
144 | 决定在`右键->清空属性组`和`右键->仅生成效果`都被勾选时,在生成前将会被清空的属性组
145 |
146 | 默认为
147 | ```
148 | 图层样式
149 | 文字层动画器
150 | ```
151 |
152 |
153 |
154 |
155 |
156 |
157 |
--------------------------------------------------------------------------------
/src/ui/previewProgress.js:
--------------------------------------------------------------------------------
1 | var global = $.global
2 |
3 | var width = 300
4 | var height = 80
5 | var progressHeight = 20
6 |
7 | var progressFactory = {
8 | createWindow: function(len, title, prefixString, suffixString) {
9 | global.progressWin = new Window('palette', title)
10 |
11 | var group = global.progressWin.add(`Group{
12 | orientation:'column',alignment: ['fill','fill'],
13 | preferredSize: [-1, ${height}],
14 | progressBar: Progressbar{
15 | value:0, minvalue:0, maxvalue:${len},
16 | preferredSize: [${width}, ${progressHeight}]
17 | },
18 | progressText: StaticText {
19 | alignment:['fill','fill'],text:"", justify:'center',properties:{multiline:0}
20 | },
21 | progressTimeText: StaticText {
22 | alignment:['fill','fill'],text:"", justify:'center',properties:{multiline:0}
23 | }
24 | }`)
25 | global.progressWin.addEventListener('keydown', function() {
26 | global.progressWin.close()
27 | })
28 | global.progressTimeText = group.progressTimeText
29 | global.progressText = group.progressText
30 | global.progressBar = group.progressBar
31 | var divide = '0' + '/' + global.progressBar.maxvalue
32 | global.progressText.text = prefixString + divide + suffixString
33 | global.progressTimeText
34 | global.progressWin.show()
35 | global.progressWin.center()
36 | var preY = global.progressText.location[1] + 10
37 | global.progressText.originY = preY
38 | global.progressText.location[1] = preY + (global.progressText.location[1] >> 1)
39 | global.progressWin.startTime = Date.now()
40 | global.progressWin.update && global.progressWin.update()
41 | },
42 | update: function(len, prefixString, suffixString, timePrefix, timeSuffix) {
43 | global.progressBar.value = global.progressBar.value + len
44 | var divide = global.progressBar.value + '/' + global.progressBar.maxvalue
45 | var time = (Date.now() - global.progressWin.startTime) / 1000
46 | global.progressText.text = prefixString + divide + suffixString
47 | global.progressTimeText.text = timePrefix + time.toString() + timeSuffix
48 | var preY = global.progressText.location[1]
49 | var shouldRelocation = global.progressTimeText.text.length === 0
50 | if (shouldRelocation) {
51 | global.progressText.location[1] = preY + (global.progressText.location[1] >> 1)
52 | } else {
53 | global.progressText.location[1] = global.progressText.originY
54 | }
55 | global.progressWin.update && global.progressWin.update()
56 | },
57 | complete: function(timePrefix, timeSuffix) {
58 | var time = (Date.now() - global.progressWin.startTime) / 1000
59 | var report = timePrefix + time.toString() + timeSuffix
60 | writeLn(report)
61 | return time
62 | }
63 | }
64 |
65 | var title = loc(sp.previewTitle)
66 | var previewPrefix = loc(sp.previewPrefix)
67 | var timePrefix = loc(sp.previewTime)
68 | var timeSuffix = loc(sp.second)
69 | sp.willSavePreviews = function(len) {
70 | progressFactory.createWindow(
71 | len,
72 | title,
73 | previewPrefix,
74 | timeSuffix
75 | )
76 | }
77 | sp.didSavePreview = function() {
78 | progressFactory.update(
79 | 1,
80 | previewPrefix,
81 | '',
82 | timePrefix,
83 | timeSuffix
84 | )
85 | }
86 | sp.didSavePreviews = function() {
87 | progressFactory.complete(timePrefix, timeSuffix)
88 | }
89 |
90 | module.exports = progressFactory
91 |
--------------------------------------------------------------------------------
/src/ui/presetWindow.js:
--------------------------------------------------------------------------------
1 | module.exports = function() {
2 | var jinWin = new Window('dialog', loc(sp.settingPre))
3 | var jinRes = `group{
4 | orientation:'column',alignment:['fill','fill'],alignChildren:['fill','fill'],
5 | guluG:Group{
6 | orientation:'row',alignment:['fill','fill'],alignChildren:['fill','fill'],
7 | jinGroup:Group{
8 | orientation:'column',alignment:['fill','fill'],alignChildren:['fill','fill'],
9 | isJin:StaticText{text:'${loc(sp.isEffect)}'}
10 | isJinSt:StaticText{text:'${loc(sp.jinOne)}',properties:{multiline:1}}
11 | jin:Panel{
12 | orientation:'column',alignment:['fill','fill'],alignChildren:['fill','fill'],
13 | _1:Checkbox{text:'${loc(sp._1)}'},
14 | _2:Checkbox{text:'${loc(sp._2)}'},
15 | _3:Checkbox{text:'${loc(sp._3)}'},
16 | _4:Checkbox{text:'${loc(sp._4)}'},
17 | _5:Checkbox{text:'${loc(sp._5)}'},
18 | _6:Checkbox{text:'${loc(sp._6)}'},
19 | _7:Checkbox{text:'${loc(sp._7)}'},
20 | _8:Checkbox{text:'${loc(sp._8)}'},
21 | _9:Checkbox{text:'${loc(sp._9)}'},
22 | }
23 | },
24 | delGroup:Group{
25 | orientation:'column',alignment:['fill','fill'],alignChildren:['fill','fill'],
26 | isJin:StaticText{text:'${loc(sp.cleanProperty)}'},
27 | isJinSt:StaticText{text:'${loc(sp.jinTwo)}',properties:{multiline:1}},
28 | del:Panel{
29 | orientation:'column',alignment:['fill','fill'],alignChildren:['fill','fill'],
30 | _1:Checkbox{text:'${loc(sp._1)}'},
31 | _2:Checkbox{text:'${loc(sp._2)}'},
32 | _3:Checkbox{text:'${loc(sp._3)}',enabled:0},
33 | _4:Checkbox{text:'${loc(sp._4)}',enabled:0},
34 | _5:Checkbox{text:'${loc(sp._5)}'},
35 | _6:Checkbox{text:'${loc(sp._6)}'},
36 | _7:Checkbox{text:'${loc(sp._7)}'},
37 | _8:Checkbox{text:'${loc(sp._8)}',enabled:0},
38 | _9:Checkbox{text:'${loc(sp._9)}',enabled:0},
39 | }
40 | },
41 | },
42 | oc:Group{
43 | orientation:'row',alignment:['fill','center'],alignChildren:['center','fill'],
44 | ok:Button{text:'Ok',preferredSize:[160,30]},
45 | }
46 | }`
47 | var jinGulu = jinWin.add(jinRes)
48 | for (let i = 1; i <= 9; i++) {
49 | if (sp.haveSetting('_1_' + i) === false) {
50 | if (i === 1 || i === 2 || i === 5) {
51 | sp.saveSetting('_1_' + i, '1')
52 | } else {
53 | sp.saveSetting('_1_' + i, '0')
54 | }
55 | }
56 | try {
57 | jinGulu.guluG.jinGroup.jin['_' + i].value = sp.getSetting('_1_' + i) === '1'
58 | jinGulu.guluG.jinGroup.jin['_' + i].onClick = function() {
59 | sp.getSetting('_1_' + i)
60 | sp.saveSetting('_1_' + i, (jinGulu.guluG.jinGroup.jin['_' + i].value === true) ? '1' : '0')
61 | }
62 | } catch (err) { }
63 | }
64 | for (let i = 1; i <= 9; i++) {
65 | if (sp.haveSetting('_2_' + i) === false) {
66 | sp.saveSetting('_2_' + i, '0')
67 | }
68 |
69 | try {
70 | jinGulu.guluG.delGroup.del['_' + i].value = sp.getSetting('_2_' + i) === '1'
71 | jinGulu.guluG.delGroup.del['_' + i].onClick = function() {
72 | sp.getSetting('_2_' + i)
73 | sp.saveSetting('_2_' + i, (jinGulu.guluG.delGroup.del['_' + i].value === true) ? '1' : '0')
74 | }
75 | } catch (err) { }
76 | }
77 | jinGulu.oc.ok.onClick = function() {
78 | jinWin.close()
79 | }
80 | jinWin.center()
81 | jinWin.show()
82 | }
83 |
--------------------------------------------------------------------------------
/src/ui/outputGroupWindow.js:
--------------------------------------------------------------------------------
1 |
2 | module.exports = function() {
3 | var outWin = new Window('window', 'Export', undefined, {
4 | resizeable: 0,
5 | maximizeButton: 0
6 | })
7 | var outRes = `Group{
8 | orientation: 'column', alignment:['fill', 'fill'], alignChildren:['fill', 'fill'],\
9 | wlist:ListBox{properties:{multiselect:1}},
10 | oc:Group{
11 | alignment:['fill', 'fill'], alignChildren:['fill', 'fill'],
12 | ok:Button{text:'` + loc(sp.ok) + `'},
13 | cancel:Button{text:'` + loc(sp.cancel) + `'}
14 | }
15 | }`
16 | try {
17 | outRes = outWin.add(outRes)
18 | } catch (err) {
19 | alert(err)
20 | }
21 | for (var i = 0; i < sp.xmlFileNames.length; i++) {
22 | outRes.wlist.add('item', sp.xmlFileNames[i])
23 | }
24 | outRes.wlist.size = [200, 400]
25 | outWin.show()
26 |
27 | outRes.oc.cancel.onClick = function() {
28 | outWin.close()
29 | }
30 |
31 | outRes.oc.ok.onClick = function() {
32 | if (outRes.wlist.selection !== null) {
33 | var exportFolder = Folder.selectDialog('Please select folder')
34 | if (exportFolder !== null && exportFolder instanceof Folder) {
35 | for (var i = 0; i < outRes.wlist.selection.length; i++) {
36 | var sourceFile = sp.getFileByName(outRes.wlist.selection[i].text)
37 | var targetFile = File(exportFolder.toString() + sp.slash + outRes.wlist.selection[i].text + '.xml')
38 | if (targetFile.exists) {
39 | continue
40 | }
41 |
42 | var images = sp.getImageFolderByName(outRes.wlist.selection[i].text).getFiles()
43 | var picXml = new XML('')
44 | var seqXml = new XML('')
45 | images.forEach(function(item, index) {
46 | if (item.name.indexOf('.png') !== -1) {
47 | item.open('r')
48 | item.encoding = 'binary'
49 | var str = encodeURIComponent(item.read())
50 | item.close()
51 | var tempXmlBigHere = new XML('' + encodeURIComponent(item.name) + '')
52 | var tempXmlHeres = new XML('
' + str + '')
53 | var guluTempA = new XML('')
54 | guluTempA.appendChild(tempXmlBigHere)
55 | guluTempA.appendChild(tempXmlHeres)
56 | picXml.appendChild(guluTempA)
57 | } else if (item instanceof Folder && item.name.indexOf('_seq') !== -1) {
58 | var thisFolder = item
59 | var folderXml = new XML("")
60 | var seqFiles = thisFolder.getFiles()
61 | seqFiles.forEach(function(imageFile, imageIndex) {
62 | imageFile.open('r')
63 | imageFile.encoding = 'binary'
64 | var str = encodeURIComponent(imageFile.read())
65 | imageFile.close()
66 | var tempXmlBigHere = new XML('' + encodeURIComponent(imageFile.name) + '')
67 | var tempXmlHeres = new XML('
' + str + '')
68 | var guluTempA = new XML('')
69 | guluTempA.appendChild(tempXmlBigHere)
70 | guluTempA.appendChild(tempXmlHeres)
71 | folderXml.appendChild(guluTempA)
72 | })
73 | seqXml.appendChild(folderXml)
74 | }
75 | })
76 | var xml = new XML(sourceFile.readd())
77 | if (picXml.children().length() > 0) {
78 | xml.appendChild(picXml)
79 | }
80 | if (seqXml.children().length() > 0) {
81 | xml.appendChild(seqXml)
82 | }
83 | if (xml.children().length() === 0) {
84 | xml = ''
85 | }
86 | targetFile.writee(xml)
87 | } // for loop
88 | clearOutput()
89 | writeLn('Complete!')
90 | } // not null
91 | } // last
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | try {
2 | (function(global) {
3 | require('src/singleton')
4 | require('src/i18n')
5 | require('src/polyfill')
6 | require('src/preset')
7 | require('src/startup')
8 | require('lib/AfterEffectsLayer')
9 | require('lib/Translate')
10 | require('lib/ReloadPic')
11 | require('lib/AutoSave')
12 | require('lib/GridView')
13 | require('lib/UIParser')
14 | var helpers = require('src/index')
15 |
16 | $.layer.slash = sp.slash
17 | $.layer.tempFolder = new Folder(sp.scriptFolder.toString() + $.layer.slash + 'tempFile')
18 | $.layer.translate = $.global.translate
19 |
20 | sp.fns = new helpers.fns()
21 |
22 | // Create UI
23 | $.global.callbackBeforeWebpackBuild && $.global.callbackBeforeWebpackBuild()
24 | if (!(global instanceof Panel)) {
25 | $.global.callbackBeforeWebpackBuild = function() {
26 | win.close()
27 | }
28 | }
29 | var win = sp.win = global instanceof Panel ? global : new Window('window', sp.scriptName, undefined, { resizeable: true })
30 | var outterGroup = sp.win.outterGroup = win.add("Group{orientation: 'column', alignment: ['fill','fill'],spacing:0,margins:0}")
31 | var innerGroup = sp.win.innerGroup = outterGroup.add("Group{orientation: 'row', alignment: ['fill','fill'],spacing:0,margins:0}")
32 | var parentDroplist = sp.parentDroplist = innerGroup.add('Dropdownlist{}')
33 | var droplist = sp.droplist = innerGroup.add('Dropdownlist{}')
34 | var gv = sp.gv = new GridView(outterGroup)
35 | var screen = $.screens[0].toString().split('-').pop().split(':')
36 | outterGroup.maximumSize = innerGroup.maximumSize = [parseInt(screen[0]), parseInt(screen[1])]
37 |
38 | // Set GridView's attributes
39 | gv.scale = sp.gridViewScale
40 | gv.limitText = sp.getSettingAsBool('limitText')
41 | gv.showText = sp.showThumbValue
42 | gv.version = (parseInt(app.version.split('.')[0]) === 12 || parseInt(app.version.split('.')[0]) === 14) ? 'CC' : 'CC2014'
43 |
44 | // Binding eventHandlers to mouse click and Window
45 | gv.leftClick = sp.fns.leftClick
46 | gv.rightClick = sp.fns.rightClick
47 | gv.leftDoubleClick = sp.fns.newLayer
48 | gv.mouseMove = sp.fns.moveOver
49 | parentDroplist.onChange = sp.fns.parentDroplistChange
50 | droplist.onChange = sp.fns.droplistChange
51 |
52 | sp.reloadParentDroplist()
53 | var selection = parseInt(sp.getSetting('parentSelection'))
54 | parentDroplist.selection = (selection <= parentDroplist.items.length - 1 && selection >= 0) ? selection : 0
55 | selection = parseInt(sp.getSetting('thisSelection'))
56 | droplist.selection = (selection <= droplist.items.length - 1 && selection >= 0) ? selection : 0
57 |
58 | sp.renderTaskArray.forEach(function(item, index) {
59 | app.cancelTask(item)
60 | })
61 | sp.renderTaskArray.length = 0
62 | sp.previewHelper = {}
63 |
64 | win.onResize = win.onResizing = sp.fns.winResize
65 |
66 | if (win instanceof Panel) {
67 | win.layout.layout(1)
68 | } else {
69 | var ratio = sp.gv.scale
70 | var location = sp.getSetting('winLocation').split(',')
71 | win.location = [parseInt(location[0]), parseInt(location[1])]
72 | if (win.location[0] <= 0 || win.location[1] <= 0) { win.location = [100, 200] }
73 | win.show()
74 | var size = sp.getSetting('winSize').split(',')
75 | win.size = [parseInt(size[0]) * ratio, parseInt(size[1]) * ratio]
76 | if (win.size[0] <= 0 || win.size[1] <= 0) { win.size = [240, 500] }
77 | win.onClose = sp.fns.winClose
78 | }
79 |
80 | win.onResize()
81 |
82 | if (sp.checkVersionOnStartupValue) {
83 | var checkVersionFunc = require('src/https/checkVersion')(
84 | win,
85 | /* true for starting */
86 | true
87 | )
88 | checkVersionFunc()
89 | }
90 |
91 | var observeSingleton = require('src/mvvm/index')
92 | observeSingleton(sp)
93 |
94 | app.onError && app.onError(function(err) {
95 | alert(`警告, Sp_memory检测到AE报错, 内容如下:
96 | ${err.toString()}
97 |
98 | 请尽量将层分散存储在不同组内`)
99 | })
100 | })(memoryGlobal)
101 | } catch (err) { alert('Line #' + err.line.toString() + '\r\n' + err.toString()) }
102 |
--------------------------------------------------------------------------------
/src/ui/moduleWindow.js:
--------------------------------------------------------------------------------
1 | module.exports = function(groupItem, win, callback) {
2 | var moveWin = new Window('dialog', 'Module', undefined, {
3 | resizeable: 0,
4 | maximizeButton: 0
5 | })
6 | var outRes = `Group{
7 | orientation: 'column', alignment:['fill', 'fill'], alignChildren:['fill', 'fill'],\
8 | helpTip:StaticText{text:'` + loc(sp.moduleHelpTip) + `'},
9 | wlist:ListBox{properties:{multiselect:0}},
10 | oc:Group{
11 | alignment:['fill', 'fill'], alignChildren:['fill', 'fill'],
12 | ok:Button{text:'` + loc(sp.changeModuleName) + `'},
13 | cancel:Button{text:'` + loc(sp.quit) + `'}
14 | }
15 | }`
16 | try {
17 | outRes = moveWin.add(outRes)
18 | } catch (err) {
19 | alert(err)
20 | }
21 | sp.xmlGroupNames.forEach(function(item, index) {
22 | this.add('item', item)
23 | }, outRes.wlist)
24 |
25 | outRes.wlist.addEventListener('keydown', function(k) {
26 | switch (k.keyName) {
27 | case 'Up':
28 |
29 | if (this.selection !== null && this.selection.index > 0) {
30 | var xml = new XML(sp.settingsFile.readd())
31 | var groupIndex = this.selection.index
32 | var targetXml = xml.ParentGroup.child(groupIndex)
33 |
34 | xml.ParentGroup.insertChildBefore(xml.ParentGroup.child(groupIndex - 1), new XML(targetXml))
35 | xml.ParentGroup.child(groupIndex + 1).setLocalName('waitToDelete')
36 | delete xml.ParentGroup.waitToDelete
37 |
38 | sp.settingsFile.writee(xml)
39 |
40 | sp.reloadParentDroplist()
41 | var selection = parseInt(sp.getSetting('parentSelection'))
42 | sp.parentDroplist.selection = (selection <= sp.parentDroplist.items.length - 1 && selection >= 0) ? selection : 0
43 | selection = parseInt(sp.getSetting('thisSelection'))
44 | sp.droplist.selection = (selection <= sp.droplist.items.length - 1 && selection >= 0) ? selection : 0
45 |
46 | sp.swap(outRes.wlist.items[this.selection.index - 1], outRes.wlist.items[this.selection.index])
47 | };
48 | break
49 | case 'Down':
50 | if (this.selection !== null && this.selection.index < this.items.length - 1) {
51 | xml = new XML(sp.settingsFile.readd())
52 | groupIndex = this.selection.index
53 | targetXml = xml.ParentGroup.child(groupIndex)
54 |
55 | xml.ParentGroup.insertChildAfter(xml.ParentGroup.child(groupIndex + 1), new XML(targetXml))
56 | xml.ParentGroup.child(groupIndex).setLocalName('waitToDelete')
57 | delete xml.ParentGroup.waitToDelete
58 |
59 | sp.settingsFile.writee(xml)
60 |
61 | sp.reloadParentDroplist()
62 | selection = parseInt(sp.getSetting('parentSelection'))
63 | sp.parentDroplist.selection = (selection <= sp.parentDroplist.items.length - 1 && selection >= 0) ? selection : 0
64 | selection = parseInt(sp.getSetting('thisSelection'))
65 | sp.droplist.selection = (selection <= sp.droplist.items.length - 1 && selection >= 0) ? selection : 0
66 |
67 | sp.swap(outRes.wlist.items[this.selection.index], outRes.wlist.items[this.selection.index + 1])
68 | };
69 | break
70 | }
71 | })
72 |
73 | outRes.oc.cancel.onClick = function() {
74 | moveWin.close()
75 | win.close()
76 | callback && callback()
77 | }
78 |
79 | outRes.oc.ok.onClick = function() {
80 | var wlist = outRes.wlist
81 | if (!wlist.selection) return
82 | var newGroupName = prompt(loc(sp.setName), wlist.selection.text)
83 | if (!newGroupName) return
84 | if (sp.xmlGroupNames.includes(newGroupName)) {
85 | alert(loc(sp.existName))
86 | return
87 | }
88 |
89 | var xml = new XML(sp.settingsFile.readd())
90 | var parentGroup = xml.ParentGroup
91 | var groupIndex = wlist.selection.index
92 |
93 | var editXml = parentGroup.child(groupIndex)
94 | editXml['@groupName'] = newGroupName
95 |
96 | sp.settingsFile.writee(xml)
97 |
98 | sp.reloadParentDroplist()
99 | var selection = parseInt(sp.getSetting('parentSelection'))
100 | sp.parentDroplist.selection = (selection <= sp.parentDroplist.items.length - 1 && selection >= 0) ? selection : 0
101 | selection = parseInt(sp.getSetting('thisSelection'))
102 | sp.droplist.selection = (selection <= sp.droplist.items.length - 1 && selection >= 0) ? selection : 0
103 |
104 | moveWin.close()
105 | win.close()
106 | } // last
107 |
108 | outRes.wlist.size = [200, 300]
109 | moveWin.show()
110 | }
111 |
--------------------------------------------------------------------------------
/src/preset.js:
--------------------------------------------------------------------------------
1 | module.exports = (function() {
2 | var keyNameArr = []
3 | var valueArr = []
4 |
5 | for (var i = 1; i <= 9; i++) {
6 | keyNameArr.push('_1_' + i)
7 | if (i === 1 || i === 2 || i === 5) {
8 | valueArr.push('1')
9 | } else {
10 | valueArr.push('0')
11 | }
12 | }
13 |
14 | for (i = 1; i <= 9; i++) {
15 | keyNameArr.push('_2_' + i)
16 | valueArr.push('0')
17 | }
18 |
19 | keyNameArr.pushh('thisSelection')
20 | .pushh('limitText')
21 | .pushh('thumbType')
22 | .pushh('winLocation')
23 | .pushh('winSize')
24 | .pushh('coverChange')
25 | .pushh('folderName')
26 | .pushh('effectName')
27 | .pushh('deleteAlert')
28 | .pushh('preCompose')
29 | .pushh('saveMaterial')
30 | .pushh('autoName')
31 | .pushh('onlyEffect')
32 | .pushh('cleanGroup')
33 | .pushh('offsetKeyframe')
34 | .pushh('language')
35 | .pushh('showThumb')
36 | .pushh('parentSelection')
37 | .pushh('frameSecond')
38 | .pushh('frameNum')
39 | .pushh('savePreview')
40 | .pushh('gridViewScale')
41 | .pushh('saveWorkarea')
42 | .pushh('checkVersionOnStartup')
43 |
44 | valueArr.pushh('1')
45 | .pushh('true')
46 | .pushh('false')
47 | .pushh('200,500')
48 | .pushh('300,500')
49 | .pushh('false')
50 | .pushh('Sp_memory Folder')
51 | .pushh('Effects,Effect,effect,effects,特效,效果')
52 | .pushh('true')
53 | .pushh('false')
54 | .pushh('true')
55 | .pushh('true')
56 | .pushh('false')
57 | .pushh('false')
58 | .pushh('false')
59 | .pushh('ch')
60 | .pushh('true')
61 | .pushh('0')
62 | .pushh('33')
63 | .pushh('30')
64 | .pushh('true')
65 | .pushh('1')
66 | .pushh('false')
67 | .pushh('false')
68 |
69 | keyNameArr.forEach(function(item, index) {
70 | var value = valueArr[index]
71 | if (sp.haveSetting(item) === false) sp.saveSetting(item, value)
72 | })
73 |
74 | // ensure delete alert
75 | sp.deleteAlertValue = true
76 |
77 | sp.showThumbValue = sp.getSettingAsBool('showThumb')
78 | sp.preComposeValue = sp.getSettingAsBool('preCompose')
79 | sp.saveMaterialValue = sp.getSettingAsBool('saveMaterial')
80 | sp.autoNameValue = sp.getSettingAsBool('autoName')
81 | sp.onlyEffectValue = sp.getSettingAsBool('onlyEffect')
82 | sp.cleanGroupValue = sp.getSettingAsBool('cleanGroup')
83 | sp.offsetKeyframeValue = sp.getSettingAsBool('offsetKeyframe')
84 | sp.savePreviewValue = sp.getSettingAsBool('savePreview')
85 | sp.saveWorkareaValue = sp.getSettingAsBool('saveWorkarea')
86 |
87 | sp.thumbTypeValue = sp.getSettingAsBool('thumbType')
88 | sp.coverChangeValue = sp.getSettingAsBool('coverChange')
89 |
90 | sp.frameSecond = parseInt(sp.getSetting('frameSecond'))
91 | sp.frameNum = parseInt(sp.getSetting('frameNum'))
92 | sp.gridViewScale = parseFloat(sp.getSetting('gridViewScale'))
93 | sp.checkVersionOnStartupValue = sp.getSettingAsBool('checkVersionOnStartup')
94 |
95 | !sp.scriptFolder.exists && sp.scriptFolder.create()
96 | !sp.roamingFolder.exists && sp.roamingFolder.create()
97 | !sp.materialFolder.exists && sp.materialFolder.create()
98 |
99 | var loc = function(string) {
100 | if (sp.lang === 0) {
101 | sp.lang = sp.getSetting('language')
102 |
103 | if (sp.isForceEnglish()) {
104 | sp.lang = 'en'
105 | }
106 | }
107 | return string[sp.lang]
108 | }
109 |
110 | $.global.loc = loc
111 |
112 | sp.extend(sp, {
113 | beyondCS6: true,
114 | versionUpdateInfo: {
115 | ch:
116 | `层存储脚本Sp_Memory ${process.env.VERSION} @秋风_小径
117 |
118 | >> 优化
119 | - 更换打包工具以提供直观的报错定位
120 | - 支持存储视频, 去除素材的大小限制
121 | - 生成层进度条
122 | - 存储层进度条
123 | - 进度条显示脚本耗时
124 | - 存储预览进度条
125 | - 优化预览CPU占用
126 | - 生成单个预合成时直接拉伸至当前合成大小
127 | - 增加允许截取工作区预览的检测框
128 | - 修复检查更新功能
129 | - 增加自动更新功能
130 | - 增加windows缩放比例参数
131 |
132 | >> 漏洞修复
133 | - 修复音频层关键帧未生成的问题
134 | - 修复windows缩放比例不为1时的界面越界问题
135 | - 修复界面中一些特殊文字的错位问题
136 | - 修复windows禁止字符导致预览存储失败的问题
137 | - 修复最小化时关掉脚本导致的脚本大小归零的问题
138 | - 修复windows特殊字符串导致的模块,组以及元素生成失败的问题
139 | - 修复mac CC2017中表达式翻译无法使用的问题
140 | - 修复setInterpolationTypeAtKey的关键帧生成报错
141 | - 修复非1080p的右键菜单越界的问题
142 | `,
143 | en: `Sp_memory ${process.env.VERSION} @smallpath
144 |
145 | New Feature:
146 | 1. Move to new pack tool to provide useful error stack trace
147 | 2. Add support to media material layer and remove the size limit of any material
148 | 3. Add progress bar to creating and saving process, together with saving previews
149 | 4. Add check box to support saving previews in workarea
150 | 5. Add support for windows font scale ratio to solve problem on AE CC2015
151 | 6. Fit to comp when only one comp layer is generated
152 | 7. Add auto updating feature and checkbox for starting checking
153 | 8. Optimize cpu rank while previewing
154 | `
155 | }
156 | })
157 |
158 | if (sp.haveSetting('version') === false || sp.getSetting('version') < sp.version) {
159 | alert(loc(sp.versionUpdateInfo))
160 | }
161 | sp.saveSetting('version', sp.version)
162 | })()
163 |
--------------------------------------------------------------------------------
/docs/en/TUTORIAL.md:
--------------------------------------------------------------------------------
1 | ## Open script
2 |
3 | #### Panel type
4 | Open `Sp_memory.jsxbin` from `AE->Window->Sp_memory.jsxbin`
5 |
6 | #### Palette type
7 | `AE->File->Scripts->Run script file` to open `Sp_memory.jsxbin`.
8 | In this type, memory supports shortcut keys.More infomation in the memory setting window
9 |
10 | ## Item
11 | The element in memory panel is called `Item`
12 |
13 | ## Save layer
14 | `Right Click->New item` to save selected layers into a new item
15 | Shortcut:`Ctrl+Right Click` Or `Alt+Right Click`
16 |
17 | ## Create layer
18 | `Right Click->New layer` to generating new layers using the selected item
19 | Shortcut:Double click at selected item.
20 |
21 | ## Cover item
22 | `Right Click->Cover item` to cover selected item by selected layers
23 |
24 | ## Move item
25 | `Shift+Right Click` to show item-moving window
26 |
27 | ## Save all layers in current comp, each as a new item.
28 | `Right Click->Help scripts->save every layer in active comp` to save each layer as each item in current comp
29 | Very useful to save motion graphics compositions
30 |
31 | ## 8 checkboxs of Right-click menu
32 | ```
33 | General:
34 | Show text: whether the text of item shows
35 |
36 | Save layer:
37 | Auto rename: whether auto name for the item when save layer.
38 | Save preview: whether save preview for the item when save layer.
39 | Save material: whether save images and musics for the item when save layer.
40 | If true,script can create images and musics even if the source has been removed.
41 |
42 | Create layer:
43 | Pre-compose: Whether pre-compose layers which are created.
44 | Only property: Whether only create new property groups on selected layer rather than create new layers.
45 | Empty property: If Only property is checked,decide whether clean property group before Only property
46 | Offset keyframe: If Only property is checked,decide whether keyframes created should offset related to the inPoint of layer.
47 | ```
48 |
49 | ## Reload previews of group
50 | `Right Click->Help scripts->Reload previews of group` to reload previews of group if there is no previews
51 | Option is the max number of frames.memory will cut the layers from 0 to the max number if you input it.
52 |
53 | ## Fix expression errors
54 | `Right Click->Help scripts->Fix expression errors` to fix expression errors caused by using different language of AE
55 | Language supported includes Chinese,English,Japanese and ADBE(Adobe general identifier)
56 | If there are wrong expressions when create layer,memory will call this script to fix them.
57 |
58 | ## Preview all/selected
59 | If there is items being selected , the preview button in Right-click menu will be `Preview selected`
60 | If there is no,the preview button will be `Preview all`
61 | You can select items by using `Ctrl` and `Shift`
62 |
63 | ## Import picture
64 | `Right Click->Import picture` to import image to selected item
65 | memory will scale the picture to the size of thumbnail
66 |
67 | ## Import group
68 | `Right Click->Import group` to import groups to memory
69 |
70 | ## Add group
71 | `Right Click->New group` to add a new group
72 | Group is the container of item,so make sure there is a group before saving layer
73 |
74 | ## Add module
75 | `Right Click->New module` to add a new module
76 | When add group and import group,the group will be added into current module
77 | You can edit the module by open the `Move module or rename module` from the Setting window
78 |
79 | ## Setting
80 | `Right Click->Setting` to open Setting window
81 |
82 | #### Move group
83 | Press "↑" and "↓" to move group in the Setting window which is near top-right
84 |
85 | #### Cut group to other module
86 | Cut selected group to other module
87 |
88 | #### Export groups
89 | Export groups.Support multi-select
90 |
91 | #### Empty temp folder
92 | Empty the material folder which is created by memory using 'Save material' feature
93 |
94 | #### Limit the text
95 | Decide whether limit the text of item to avoid overflow.Default: true
96 |
97 | #### Update thumbs when cover item
98 | Whether update thumbnail when cover item.This is just thunmnail.To avoid updating preview, make sure `Right Click-Save preview` is not checked
99 |
100 | #### Enable new type of thumb
101 | In CC and CC,memory can save another type of thumb.This thumbnail is exactly the screenshot of `Composition Window` of AE
102 |
103 | #### Deleting alert
104 | Whether alert when delete items.Default: true
105 |
106 | #### The milliseconds of a frame continues when preview
107 | The max number is 50 in CC and CC2014, and is 300 in CC2015
108 | Since the speed of saveing preview in CC2015 is 10 times faster than other AE version
109 |
110 | #### The folder name of collect feature
111 | This is the name of the main folder in `Project Window`
112 | memory will collect the Comp layers created by script to the main folder
113 |
114 | #### The group name that can enable 'Only property'
115 | If the name of group is included here, then `Right Click->Only property` will be checked when change groups
116 |
117 | #### 中文/English
118 | To change script language to 中文 or English
119 |
120 | #### Check version
121 | Check updates for memory
122 |
123 | ## Preset setting
124 | `Right Click->Preset setting` to open preset window
125 | 'Only property' and 'Empty property' will be here.
126 | You can edit them by yourself to use the powerful preset feather of memory
127 |
128 | #### Only property
129 | If `Right Click->Only property` is checked ,decide the property groups that will be created
130 | Default:
131 | ```
132 | Mask
133 | Effect
134 | Layer styles
135 | Shape content
136 | Text animators
137 | ```
138 |
139 | #### Empty property
140 | If `Right Click->Empty property` and `Right Click->Only property` are checked,decide the property groups that will be empty before Only property
141 |
142 | Default:
143 | ```
144 | Layer styles
145 | Text animators
146 | ```
147 |
148 |
149 |
150 |
151 |
152 |
153 |
--------------------------------------------------------------------------------
/src/ui/rightClickMenu.js:
--------------------------------------------------------------------------------
1 | var settingWindow = require('./settingWindow')
2 | var presetWindow = require('./presetWindow')
3 |
4 | module.exports = function() {
5 | var itemList = [
6 | { name: loc(sp.settings), type: 'button' }, { name: 'helperScripts', type: 'dropdownlist' },
7 |
8 | { name: 'preview', type: 'button' }, { name: loc(sp.yushe), type: 'button' },
9 |
10 | { name: loc(sp.changeName), type: 'button' }, { name: loc(sp.importPicture), type: 'button' },
11 | { name: loc(sp.addModule), type: 'button' }, { name: loc(sp.deleteModule), type: 'button' },
12 | { name: loc(sp.importFile), type: 'button' }, { name: loc(sp.exportFile), type: 'button' },
13 | { name: loc(sp.addGroup), type: 'button' }, { name: loc(sp.deleteGroup), type: 'button' },
14 | { name: loc(sp.addElement), type: 'button' }, { name: loc(sp.cover), type: 'button' },
15 | { name: loc(sp.create), type: 'button' }, { name: loc(sp.deleteElement), type: 'button' },
16 |
17 | // { name: loc(sp.searchText), type: 'button' }, { name: loc(sp.searchButton), type: 'button' },
18 |
19 | { name: loc(sp.isShow), type: 'checkbox' }, { name: loc(sp.isName), type: 'checkbox', id: 'autoName' },
20 | { name: loc(sp.isSavePreview), type: 'checkbox', id: 'savePreview' }, { name: loc(sp.isOffset), type: 'checkbox', id: 'saveMaterial' },
21 | { name: loc(sp.isPrecomp), type: 'checkbox', id: 'preCompose' }, { name: loc(sp.isEffect), type: 'checkbox', id: 'onlyEffect' },
22 | { name: loc(sp.cleanProperty), type: 'checkbox', id: 'cleanGroup' }, { name: loc(sp.offsetKey), type: 'checkbox', id: 'offsetKeyframe' },
23 | { name: loc(sp.saveWorkarea), type: 'checkbox', id: 'saveWorkarea' }
24 |
25 | ]
26 |
27 | var length = itemList.length
28 |
29 | var space = 102 / 5
30 | var buttonHeight = 20
31 | var checkBoxHeight = 21
32 |
33 | if (sp.lang === 'ch') { var maxWidth = 180 } else { maxWidth = 190 }
34 |
35 | var shortMenu = new Window('palette', '', [0, 0, maxWidth, Math.ceil(length / 2) * space + 2], {
36 | borderless: true
37 | })
38 |
39 | for (var i = 0; i < length; i++) {
40 | var item = itemList[i]
41 | let itemWidth, itemHeight
42 | itemWidth = maxWidth / 2 + (item.widthOffset || 0)
43 | if (item.type === 'button') {
44 | itemHeight = buttonHeight
45 | } else if (item.type === 'checkbox') {
46 | itemHeight = checkBoxHeight
47 | } else if (item.type === 'dropdownlist') {
48 | itemHeight = buttonHeight
49 | } else if (item.type === 'edittext') {
50 | itemHeight = buttonHeight
51 | }
52 | var control
53 | if (i % 2 === 0) {
54 | control = shortMenu[item.name] = shortMenu.add(
55 | item.type,
56 | [
57 | 0,
58 | (parseInt((i) / 2) * itemHeight),
59 | itemWidth,
60 | (22 + parseInt((i) / 2) * itemHeight)
61 | ],
62 | item.name
63 | )
64 | } else {
65 | control = shortMenu[item.name] = shortMenu.add(
66 | item.type,
67 | [
68 | itemWidth,
69 | (parseInt((i - 1) / 2) * itemHeight),
70 | maxWidth,
71 | (22 + parseInt((i - 1) / 2) * itemHeight)
72 | ],
73 | item.name
74 | )
75 | }
76 | if (control && item.id) control.id = item.id
77 | }
78 |
79 | var isCheckBoxClicked = false
80 |
81 | shortMenu[loc(sp.settings)].onClick = function() {
82 | isCheckBoxClicked = false
83 | shortMenu.hide()
84 | settingWindow()
85 | }
86 |
87 | shortMenu['helperScripts'].add('item', loc(sp.helperScripts))
88 | shortMenu['helperScripts'].add('item', loc(sp.expressionTranslate))
89 | shortMenu['helperScripts'].add('item', loc(sp.reloadGroup))
90 | shortMenu['helperScripts'].add('item', loc(sp.saveEachLayer))
91 | shortMenu['helperScripts'].selection = 0
92 |
93 | shortMenu['helperScripts'].onChange = shortMenu['helperScripts'].onChanging = function() {
94 | try {
95 | // run sp_translate script
96 | this.selection.index === 1 &&
97 | $.global.translate() ||
98 |
99 | // generate and then save the whole group
100 | this.selection.index === 2 &&
101 | $.global.reloadPic() ||
102 |
103 | // auto save every layer in current comp,one layer as one element
104 | this.selection.index === 3 &&
105 | $.global.autoSave()
106 | } catch (err) {
107 | err.printa()
108 | }
109 |
110 | // back list's selection
111 | this.selection = 0
112 | }
113 |
114 | shortMenu['preview'].onClick = function() {
115 | isCheckBoxClicked = false
116 | shortMenu.hide()
117 | sp.fns.previewAll()
118 | }
119 |
120 | shortMenu[loc(sp.yushe)].onClick = function() {
121 | isCheckBoxClicked = false
122 | shortMenu.hide()
123 | presetWindow()
124 | }
125 |
126 | shortMenu[loc(sp.changeName)].onClick = function() {
127 | isCheckBoxClicked = false
128 | shortMenu.hide()
129 | sp.fns.changeName()
130 | }
131 |
132 | shortMenu[loc(sp.importPicture)].onClick = function() {
133 | isCheckBoxClicked = false
134 | shortMenu.hide()
135 | sp.fns.importImage()
136 | }
137 |
138 | shortMenu[loc(sp.addModule)].onClick = function() {
139 | isCheckBoxClicked = false
140 | shortMenu.hide()
141 | sp.fns.addModule()
142 | }
143 |
144 | shortMenu[loc(sp.deleteModule)].onClick = function() {
145 | isCheckBoxClicked = false
146 | shortMenu.hide()
147 | sp.fns.deleteModule()
148 | }
149 |
150 | shortMenu[loc(sp.importFile)].onClick = function() {
151 | isCheckBoxClicked = false
152 | shortMenu.hide()
153 | sp.fns.importFiles()
154 | }
155 |
156 | shortMenu[loc(sp.exportFile)].onClick = function() {
157 | isCheckBoxClicked = false
158 | shortMenu.hide()
159 | sp.fns.exportFile()
160 | }
161 |
162 | shortMenu[loc(sp.addGroup)].onClick = function() {
163 | isCheckBoxClicked = false
164 | shortMenu.hide()
165 | sp.fns.addGroup()
166 | }
167 |
168 | shortMenu[loc(sp.deleteGroup)].onClick = function() {
169 | isCheckBoxClicked = false
170 | shortMenu.hide()
171 | sp.fns.deleteGroup()
172 | }
173 |
174 | shortMenu[loc(sp.addElement)].onClick = function() {
175 | isCheckBoxClicked = false
176 | shortMenu.hide()
177 | sp.fns.newItem()
178 | }
179 |
180 | shortMenu[loc(sp.cover)].onClick = function() {
181 | isCheckBoxClicked = false
182 | shortMenu.hide()
183 | sp.fns.cover()
184 | }
185 |
186 | shortMenu[loc(sp.create)].onClick = function() {
187 | isCheckBoxClicked = false
188 | shortMenu.hide()
189 | sp.fns.newLayer()
190 | }
191 |
192 | shortMenu[loc(sp.deleteElement)].onClick = function() {
193 | isCheckBoxClicked = false
194 | shortMenu.hide()
195 | sp.fns.deleteItem()
196 | }
197 |
198 | shortMenu[loc(sp.isShow)].value = sp.showThumbValue
199 | shortMenu[loc(sp.isName)].value = sp.autoNameValue
200 | shortMenu[loc(sp.isSavePreview)].value = sp.savePreviewValue
201 | shortMenu[loc(sp.isOffset)].value = sp.saveMaterialValue
202 | shortMenu[loc(sp.isPrecomp)].value = sp.preComposeValue
203 | shortMenu[loc(sp.isEffect)].value = sp.onlyEffectValue
204 | shortMenu[loc(sp.cleanProperty)].value = sp.cleanGroupValue
205 | shortMenu[loc(sp.offsetKey)].value = sp.offsetKeyframeValue
206 | shortMenu[loc(sp.saveWorkarea)].value = sp.saveWorkareaValue
207 |
208 | shortMenu[loc(sp.isShow)].onClick = function() {
209 | sp.showThumbValue = this.value
210 | $.global.sp.gv.showText = this.value
211 | sp.saveSetting('showThumb', this.value.toString())
212 | isCheckBoxClicked = true
213 | sp.gv.refresh()
214 | }
215 |
216 | shortMenu[loc(sp.isName)].onClick =
217 | shortMenu[loc(sp.isSavePreview)].onClick =
218 | shortMenu[loc(sp.isOffset)].onClick =
219 | shortMenu[loc(sp.isPrecomp)].onClick =
220 | shortMenu[loc(sp.isEffect)].onClick =
221 | shortMenu[loc(sp.cleanProperty)].onClick =
222 | shortMenu[loc(sp.offsetKey)].onClick =
223 | shortMenu[loc(sp.saveWorkarea)].onClick = function() {
224 | var name = this.id + 'Value'
225 | sp[name] = this.value
226 | isCheckBoxClicked = true
227 | }
228 |
229 | shortMenu.addEventListener('blur', function() {
230 | if (isCheckBoxClicked === false) {
231 | shortMenu.hide()
232 | } else {
233 | isCheckBoxClicked = true
234 | }
235 | })
236 |
237 | shortMenu.onDeactivate = function() {
238 | shortMenu.hide()
239 | }
240 |
241 | shortMenu.addEventListener('keydown', function(event) {
242 | shortMenu.hide()
243 | })
244 |
245 | return shortMenu
246 | }
247 |
--------------------------------------------------------------------------------
/src/i18n/index.js:
--------------------------------------------------------------------------------
1 |
2 | /** **********************************界面的字符串资源***************************************/
3 | sp.extend(sp, {
4 | settings: { en: 'Setting', ch: '设置' },
5 | groupName: { en: 'Group name :', ch: '组名 :' },
6 | elementName: { en: 'Element Name :', ch: '元素名 :' },
7 | changeName: { en: 'Rename item', ch: '重命名元素' },
8 | importPicture: { en: 'Import picture', ch: '导入图片' },
9 | importFile: { en: 'Import file', ch: '导入组' },
10 | exportFile: { en: 'Export file', ch: '导出组' },
11 | addGroup: { en: 'New group', ch: '新建组' },
12 | deleteGroup: { en: 'Remove group', ch: '删除组' },
13 | addElement: { en: 'New item', ch: '新建元素' },
14 | deleteElement: { en: 'Remove item', ch: '删除元素' },
15 | create: { en: 'New layer', ch: '生成层' },
16 | cover: { en: 'Cover item', ch: '覆盖元素' },
17 | isShow: { en: 'Show text', ch: '显示文字' },
18 | isAlert: { en: 'Deleting Alert', ch: '删除时警告' },
19 | isPrecomp: { en: 'Pre-compose', ch: '预合成' },
20 | isOffset: { en: 'Save material', ch: '存储素材' },
21 | isName: { en: 'Auto rename', ch: '自动取名' },
22 | isEffect: { en: 'Only property', ch: '仅生成效果' },
23 | cleanProperty: { en: 'Empty prop', ch: '清空属性组' },
24 | offsetKey: { en: 'Shift keyframe', ch: '关键帧偏移' },
25 | sureDelete: { en: 'Are you sure to delete it?', ch: '确认删除?' },
26 | helperScripts: { en: 'Help scripts', ch: '辅助脚本' },
27 | expressionTranslate: { en: 'Fix expression errors', ch: '表达式翻译' },
28 | script: { en: 'Sp_palette v1.0', ch: '形状层画板' },
29 | reloadGroup: { en: 'Reload previews of group', ch: '重载组内预览动画' },
30 | saveEachLayer: { en: 'Save every layer in active comp', ch: '自动存储每一层' },
31 | cutLength: { en: 'Cut layer length', ch: '裁剪层长度' },
32 | blankName: { en: 'Name should not be empty!', ch: '名字不应为空!' },
33 | existName: { en: 'Element with the same name exists already!', ch: '相同名字的元素已存在!' },
34 | overWritten: { en: 'File with the same name exists already!', ch: '相同名字的文件已存在!' },
35 | inputName: { en: 'Please input your name!', ch: '请输入名字!' },
36 | alertSpe: { en: 'There are special symbols in selectedLayers,please rename them first!', ch: '选中层名字有特殊符号,请首先重命名选中层!' },
37 | deleteFolder: { en: 'Empty temp folder', ch: '清空素材文件夹' },
38 | changeGroupName: { en: 'Change name of group', ch: '重命名选中组' },
39 | deleteOk: { en: 'Clean folder successfully!', ch: '清空文件夹完毕!' },
40 | yushe: { en: 'Preset Setting', ch: '预设设置' },
41 | jinOne: { en: 'Please select groups that will be created on selectedLayers', ch: '请选择在仅生成效果时要在选中层上生成的属性组' },
42 | jinTwo: { en: 'Please select groups that will be empty on selectedLayers before creating Properties', ch: '请选择在仅生成效果之前要清空的选中层的属性组' },
43 | isSureGroup: { en: 'What you are deleting is a Group.\rAre you sure?', ch: '你正在删除的是一个组.\r确定删除吗?' },
44 | isSureGroup2: { en: 'Repeat!\rWhat you are deleting is a Group.\rAre you sure?\r', ch: '重复!\r你正在删除的是一个组.\r确定删除吗?' },
45 | _1: { en: 'Mask', ch: '遮罩' },
46 | _2: { en: 'Effect', ch: '效果' },
47 | _3: { en: 'Transform', ch: '变换' },
48 | _4: { en: 'Material options', ch: '3D材质选项' },
49 | _5: { en: 'Layer styles', ch: '图层样式' },
50 | _6: { en: 'Shape content', ch: '形状层形状组' },
51 | _7: { en: 'Text animators', ch: '文字层动画器' },
52 | _8: { en: 'Light options', ch: '灯光选项' },
53 | _9: { en: 'Camera options', ch: '摄像机选项' },
54 | setName: { en: 'Please input the name.', ch: '请输入名字' },
55 | checkVersion: { en: 'Check version', ch: '检查更新' },
56 | newVersionFind: { en: 'New version found,please download the new version ', ch: '存在新版本,请下载最新版v' },
57 | newVersionNotFind: { en: 'No new version! v', ch: '已是最新版 v' },
58 | link: { en: 'Weibo', ch: '作者微博' },
59 | about: {
60 | en:
61 | `Made by:smallpath
62 | E-mail:smallpath2013@gmail.com
63 | Source Code:
64 | github.com/smallpath/memory
65 |
66 | DoubleClick:generate new layers or properties on selected layers from selected element.
67 | RightClick:call the shortcut menu.
68 | Ctrl/Alt+RightClick:save selected layers as a new element.
69 | Shift+Rightclick:call the up and down window
70 |
71 | Shortcutkey when script runs as Window:
72 | Key 'D' or 'Delete':delete selected element.
73 | Key 'F': overlap selected element.
74 | Key 'Up':drop up selected element.
75 | Key 'Down':drop down selected element.`,
76 | ch:
77 | `作者:
78 | smallpath
79 | 邮箱:
80 | smallpath2013@gmail.com
81 | 源码托管地址:
82 | github.com/smallpath/memory
83 |
84 | 右键点击:呼出右键菜单.
85 | 双击:从选中元素创建层或创建效果.
86 | Ctrl/Alt+右键点击:从选中的层读取层信息以创建新元素.
87 | Shift+右键:唤出移动元素的窗口
88 |
89 | 窗口模式运行脚本时:
90 | D键:删除选中元素.
91 | F键:覆盖选中元素.
92 | 上键:上移选中元素.
93 | 下键:下移选中元素.`
94 | },
95 | refresh: {
96 | en: `Please run this script to refresh pictures only when your group has been created with wrong thumbnails(such as all black)\rIt will spent a lot of time.\rNew thumbnails will be created at the time of active comp,so set your comp's time first.`,
97 | ch: `生成组内所有元素的预览动画:
98 | ##请用本功能对非3.x版本保存的组进行生成预览动画的操作:
99 |
100 | 此功能将生成组内所有元素的主缩略图和预览动画,其中主缩略图为当前合成的当前时间点的画面
101 |
102 | 注意:此功能将耗费大量时间,脚本会弹出图片文件夹,你可以根据其中的图片判断预览动画的生成进度
103 | `
104 | },
105 | auto: {
106 | en: `This script helps you simplify you saving proccess\rIt will save every layer in active comp as a new element.`,
107 | ch: `批量存储功能:
108 |
109 | 这会将当前合成中每一层都分别存储为一个新元素.
110 |
111 | 此功能可以帮助你快速存储新元素,十分适合存储大量的MG合成层
112 | 脚本会弹出图片文件夹,你可以根据其中的图片来判断预览动画的生成进度
113 | `},
114 | cutLengthTwo: {
115 | en: 'This script will cut every layer in current comp, related to opacity for common layer and content length for comp layer.',
116 | ch: '此功能将会裁剪当前合成中每一层的长度,根据普通层的透明度与合成层内容的长度.'
117 | },
118 | output: { en: 'Export groups', ch: '批量导出组' },
119 | ok: { en: 'Ok', ch: '确定' },
120 | cancel: { en: 'Cancel', ch: '取消' },
121 | complete: { en: 'Complete!', ch: '导出完成!' },
122 | showText: { en: 'Show text', ch: '显示文字' },
123 | ui1: { en: 'The newer UI', ch: '新界面' },
124 | ui2: { en: 'The older UI', ch: '旧界面' },
125 | sys: { en: 'Script find that Sp_memory v1.4 has been used the first time.\rPlease select the UI type,Yes for new UI and No for previous UI.', ch: '脚本检测到Sp_memory v1.4首次被使用.\r请选择脚本界面,Yes为新界面,No为旧界面.' },
126 | uiC: { en: 'Please restart script,ui will be changed.', ch: '界面已更新,请重启脚本' },
127 | from: { en: 'Range is 0.', ch: '元素下标范围为:0' },
128 | ud: { en: 'Up and down', ch: '上下移动选中元素' },
129 | up: { en: 'Up', ch: '上移' },
130 | down: { en: 'Down', ch: '下移' },
131 | jmp: { en: 'Jump', ch: '跳转' },
132 | coverChange: { en: 'Update thumb when cover', ch: '覆盖时更新缩略图' },
133 | folderName: { en: 'The folder name of collect feature:', ch: '收集生成层时的工程栏文件夹名:' },
134 | effectName: { en: 'The group name that enable Only property :', ch: '默认开启仅生成效果的组名:' },
135 | limitText: { en: 'Limit the text for UI', ch: '限制主窗口界面的文字长度' },
136 | scriptSetting: { en: 'Setting', ch: '设置' },
137 | settingPre: { en: 'Preference', ch: '预设' },
138 | thumbType: { en: 'Enable new type of thumb', ch: '缩略图包含合成栏图层轮廓' },
139 | addModule: { en: 'New module', ch: '新建模块' },
140 | deleteModule: { en: 'Remove module', ch: '删除模块' },
141 | deleteModuleAlert: {
142 | en: 'Dangerous!\r\nYou are deleting a module!\r\nAll groups in this module will be removed!\r\nDo you really want to remove this module?',
143 | ch: '警告!\r\n你正在删除一个模块!\r\n所有包含在此模块中的组都将被删除!\r\n你想要继续删除吗?'
144 | },
145 | addAlert: { en: 'Repeart:\r\n', ch: '重复:\r\n' },
146 | move: { en: 'Cut selected group to other module', ch: '剪切选中组到其他模块' },
147 | editModule: { en: 'Move module or rename module', ch: '改变模块顺序或重命名模块' },
148 | changeModuleName: { en: 'Change module name', ch: '重命名选中模块' },
149 | moduleHelpTip: { en: "press key 'Up' and 'Down can move the selected module' ", ch: '方向上下键可移动选中模块' },
150 | quit: { en: 'Quit', ch: '退出' },
151 | selectGroupFirst: { en: 'Please select a group first!', ch: '请先选中一个组!' },
152 | selectModuleFirst: { en: 'Please select a module first!', ch: '请先选中一个模块!' },
153 | frameSecondText: { en: 'The milliseconds length of frame continues when preview:', ch: '预览时一张图片持续的毫秒数:' },
154 | frameNumText: { en: 'The number of picture sequence generated for preview', ch: '生成供预览的图片序列时图片的数量:' },
155 | reloadNeedFrames: {
156 | en: "Please input the max frames which will be used to correct the duration of Preview.Keep blank if you don't what this feature",
157 | ch: '请输入最大帧数,这将被用来使预览动画的时间范围更加准确\r\n不输入则将不进行校准'
158 | },
159 | needComp: { en: 'Please select a comp first', ch: '脚本需要一个合成,当前合成不存在!' },
160 | previewAll: { en: 'Preview all', ch: '预览全部' },
161 | previewSelected: { en: 'Preview selected', ch: '预览选中' },
162 | needElement: { en: 'Please select a element in the group', ch: '组内元素未被选中,请首先选中一个元素' },
163 | needElements: { en: 'Please select at least one element in the group', ch: '组内元素未被选中,请至少选中一个元素' },
164 | needLayers: { en: 'Please select at least one layer in the current comp', ch: '请选中至少一个层' },
165 | needModule: { en: 'Please create a module first', ch: '请先新建一个模块' },
166 | isSavePreview: { en: 'Save preview', ch: '存储预览' },
167 | searchWindow: { en: 'Search', ch: '搜索' },
168 | getReport: { en: 'Get report', ch: '生成报告' },
169 | creatingReport: { en: 'Creating cost: ', ch: '生成层耗时: ' },
170 | creatingProcessTitle: { en: 'Now generating...', ch: '少女祈祷中...' },
171 | creatingProcessingPrefix: { en: 'Processing the ', ch: '正在生成第 ' },
172 | creatingProcessAfter: { en: ' layer', ch: ' 层' },
173 | savingReport: { en: 'Saving cost: ', ch: '总存储耗时: ' },
174 | savingProcessTitle: { en: 'Now saving...', ch: '少女祈祷中...' },
175 | savingProcessingPrefix: { en: 'Processing the ', ch: '正在存储第 ' },
176 | savingProcessAfter: { en: ' layer', ch: ' 层' },
177 | second: { en: ' second', ch: ' 秒' },
178 | previewTitle: { en: 'Save preview', ch: '少女祈祷中...' },
179 | previewPrefix: { en: 'Saving preview: ', ch: '正在存储预览图片: ' },
180 | previewTime: { en: 'Saving cost: ', ch: '存储预览耗时: ' },
181 | searchButton: { en: 'search', ch: '搜索' },
182 | searchText: { en: 'input name', ch: '输入元素名称' },
183 | setRatioText: { en: 'notify the scale of UI for high-DPI windows', ch: '设置主界面windows放大比例' },
184 | setRatioHelptip: {
185 | en: 'AE scriptUI may be scaled wrong in high-DPI windows from CC2013 to CC2015.0',
186 | ch: 'windows文字缩放比例大于1时, AE脚本界面会自动放大, 导致本脚本界面越界'
187 | },
188 | setRatioWarning: {
189 | en: 'Please only change it when your text ratio does not equal to 1. Restart script to make sense',
190 | ch: '请仅当你的windows文字缩放比例不为1且本脚本界面越界的情况下, 才修改此参数, 重启脚本后生效'
191 | },
192 | saveWorkarea: {
193 | en: 'Workarea',
194 | ch: '预览工作区'
195 | },
196 | tryVersionFind: {
197 | en: 'It seems that you are using the beta version which is not released yet. v',
198 | ch: '未发现新版本, 你正在使用尚未发布的试用版 v'
199 | },
200 | shouldUpdateScript: {
201 | en: 'Would you like to upgrade to new version now?\r\n it will cost some time while ae will not response\r\n',
202 | ch: '现在开始更新新版本吗?\r\n\r\n脚本大小为300KB, 下载时AE会停止响应数十秒时间.\r\n选否则可以选择通过浏览器下载'
203 | },
204 | shouldDownloadScript: {
205 | en: 'Would you like to download new version now?',
206 | ch: '是否通过浏览器自行下载最新版本?\r\n打开网页后右键另存为脚本文件即可'
207 | },
208 | downloaded: {
209 | en: 'Update success! To make it work, just restart script',
210 | ch: '升级成功, 请重启脚本'
211 | },
212 | generalOption: {
213 | en: 'General',
214 | ch: '一般选项'
215 | },
216 | otherOption: {
217 | en: 'Other',
218 | ch: '其他'
219 | },
220 | sourceCode: {
221 | en: 'Source Code',
222 | ch: '脚本源码'
223 | },
224 | addIssue: {
225 | en: 'Report bug',
226 | ch: '上报错误'
227 | },
228 | issueDesc: {
229 | en: 'Notice that error log is in Sp_memory/tempFile/error.txt',
230 | ch: '核心错误日志在Sp_memory/tempFile/error.txt当中, 这可以帮助作者定位错误\r\n\r\n你可以在Github或贴吧中报告错误, 在Github上报的错误将会被优先解决\r\n\r\n选择"Yes"前往Github, 选择"No"前往贴吧'
231 | },
232 | checkVersionOnStartupText: {
233 | en: 'Check version on startup',
234 | ch: '脚本启动时检查更新'
235 | }
236 | })
237 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | Apache License
3 | Version 2.0, January 2004
4 | http://www.apache.org/licenses/
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
176 |
177 | END OF TERMS AND CONDITIONS
178 |
179 | APPENDIX: How to apply the Apache License to your work.
180 |
181 | To apply the Apache License to your work, attach the following
182 | boilerplate notice, with the fields enclosed by brackets "[]"
183 | replaced with your own identifying information. (Don't include
184 | the brackets!) The text should be enclosed in the appropriate
185 | comment syntax for the file format. We also recommend that a
186 | file or class name and description of purpose be included on the
187 | same "printed page" as the copyright notice for easier
188 | identification within third-party archives.
189 |
190 | Copyright [yyyy] [name of copyright owner]
191 |
192 | Licensed under the Apache License, Version 2.0 (the "License");
193 | you may not use this file except in compliance with the License.
194 | You may obtain a copy of the License at
195 |
196 | http://www.apache.org/licenses/LICENSE-2.0
197 |
198 | Unless required by applicable law or agreed to in writing, software
199 | distributed under the License is distributed on an "AS IS" BASIS,
200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201 | See the License for the specific language governing permissions and
202 | limitations under the License.
203 |
--------------------------------------------------------------------------------
/lib/UIParser.js:
--------------------------------------------------------------------------------
1 | $.global.UIParser = UIParser
2 | function UIParser(global) {
3 | var _ = global._ = function(selector) {
4 | if (_.isUI(selector.type)) {
5 | return _.extend([selector], _.proto)
6 | }
7 | return _.proto.find(selector)
8 | }
9 | _.global = global
10 |
11 | _.root = {
12 | children: []
13 | }
14 | _.windows = _.root.children
15 | _.extend = function(target, source) { // give the source to target
16 | for (var i in source) target[i] = source[i]
17 | return target
18 | }
19 | _.dir = function(obj) {
20 | var str = ''
21 | for (var i in obj) str += i + ' : ' + typeof (obj[i]) + '\n'
22 | return str
23 | }
24 | _.removeWin = function(id) {
25 | for (var i = 0; i < _.windows.length; i++) {
26 | if (_.windows[i].id === id) _.windows.splice(i, 1)
27 | }
28 | }
29 | _.proto = {// 这里的函数将赋给返回的解析器对象
30 | find: function(selector, recursive) { // find函数用来返回一个递归匹配后的数组,并且将_.proto的函数也给这个数组
31 | var matchs = []
32 | var elements = ('length' in this) ? this : [_.root]
33 | if (!selector) return _.extend(elements, _.proto)
34 |
35 | // 选择器为选择器表达式
36 | if (typeof selector === 'string') {
37 | var selectors = _.formalSelector(selector)// 正规化选择器
38 | for (var i = 0; i < selectors.length; i++) {
39 | var match = elements
40 | var process = _.parserSelector(selectors[i])// 解析选择器
41 | for (var j = 0; j < process.length; j++) { // 逐步执行
42 | if (!process[j][3] && _.proto[process[j][4]]) {
43 | match = _.proto[process[j][4]].call(match, process[j][5])// 如果有:标记执行过滤操作
44 | } else {
45 | match = _.findElementsByProp(match, process[j][0], process[j][1], process[j][2])
46 | }
47 | }
48 | matchs = _.merge(match, matchs)
49 | }
50 | } else if (typeof selector === 'function') {
51 | if (!recursive) recursive = 1
52 | matchs = _.findElementsByFn(elements, selector, recursive)
53 | }
54 |
55 | return _.extend(matchs, _.proto)
56 | },
57 | filter: function(selector) {
58 | var matchs = []
59 | var elements = ('length' in this) ? this : [_.root]
60 | if (!selector) return _.extend(elements, _.proto)
61 |
62 | // 选择器为选择器表达式
63 | if (typeof selector === 'string') {
64 | var selectors = _.formalSelector(selector)// 正规化选择器
65 | for (var i = 0; i < selectors.length; i++) {
66 | var match = elements
67 | var process = _.parserSelector(selectors[i])// 解析选择器
68 | for (var j = 0; j < process.length; j++) { // 逐步执行
69 | if (!process[j][3] && _.proto[process[j][4]]) {
70 | match = _.proto[process[j][4]].call(match, process[j][5])// 如果有:标记执行过滤操作
71 | } else {
72 | match = _.findElementsByProp(match, process[j][0], process[j][1])
73 | }
74 | }
75 | matchs = _.merge(match, matchs)
76 | }
77 | } else if (typeof selector === 'function') {
78 | matchs = _.filterElementsByFn(elements, selector)
79 | }
80 |
81 | return _.extend(matchs, _.proto)
82 | },
83 | style: function(style, target) {
84 | if (!target) target = this
85 | for (var i = 0; i < target.length; i++) {
86 | for (var j in style) {
87 | if (target[i].type === j) _.proto.style(style[j], [target[i]])
88 | else target[i][j] = style[j]
89 | }
90 | }
91 | },
92 | each: function(command) { for (var i = 0; i < this.length; i++) command(this[i]) }, // command is a function
93 | setAttr: function(prop, value) { this.each(function(e) { e[prop] = value }) },
94 | getAttr: function(prop) { if (this.length) return this[0][prop] },
95 | children: function(selector) { return this.find(selector || '>*') },
96 | parent: function() { if (this.length > 0 && this[0].parent) return this[0].parent; else return _.extend([], _.proto) },
97 | on: function(event, fn, useCapture) { this.each(function(e) { e.addEventListener(event, fn, useCapture) }) },
98 | exe: function(fn, args) { this.each(function(e) { e[fn].apply(e, args) }) },
99 | addUI: function() { return _.addUI.apply(this[0], arguments) },
100 | first: function() { return _.extend([this[0]], _.proto) },
101 | last: function() { return _.extend([this[this.length - 1]], _.proto) },
102 | eq: function(index) { if (index < this.length && index >= 0) { return _.extend([this[index]], _.proto) } else { return _.extend([], _.proto) } },
103 | layout: function() { this.each(function(e) { _.layout(e) }) },
104 | remove: function() { this.each(function(e) { e.parent.remove(e) }) },
105 | empty: function() { this.children().remove() }
106 | }
107 | /** ***********************functions for createUI****************************************************/
108 | _.createUI = function(UIJson) { // 创建UI
109 | if (!UIJson) return
110 | var ISPANEL = global instanceof Panel
111 | if (ISPANEL) {
112 | var _newElement = _.addUI(UIJson, global)
113 | _.root.children.push(global)
114 | global.layout.layout(true)
115 | return _newElement
116 | } else {
117 | return _.newWindow(UIJson)
118 | }
119 | }
120 |
121 | _.newWindow = function(UIJson) { // 添加窗口
122 | if (!UIJson) return
123 | var newWindows = []
124 | for (var i in UIJson) {
125 | var json = UIJson[i]
126 | if (_.isWindow(UIJson[i].type)) {
127 | // create window
128 | var s = json.type
129 | if (json.properties) s += '{properties:' + _.JSON.stringify(json.properties) + '}'
130 | var newWindow = _.root.children[_.root.children.length] = new Window(s)
131 | newWindows.push(newWindow)
132 | if (!json.id) newWindow.id = i
133 | // add other properties for newWindow
134 | for (var j in json) {
135 | if (j === 'type' || j === 'properties' || j === 'children') continue
136 | newWindow[j] = json[j]
137 | }
138 | // create children for newWindow
139 | if (json.children) _.addUI(json.children, newWindow)
140 | }
141 | }
142 | return _.extend(newWindows, _.proto)
143 | }
144 |
145 | _.addUI = function(UIJson, parent) { // 为parent添加UI
146 | if (!UIJson) return
147 | if (!parent) parent = this
148 |
149 | var newItem = []
150 | for (var i in UIJson) {
151 | var json = UIJson[i]
152 | if (_.isElement(json.type)) {
153 | // create element
154 | var s = json.type
155 | if (json.properties) s += '{properties:' + _.JSON.stringify(json.properties) + '}'
156 | var newElement = parent.add(s)
157 | if (!json.id) newElement.id = i
158 | // add other properties for newElement
159 | for (var j in json) {
160 | if (j === 'type' || j === 'properties' || j === 'children') continue
161 | newElement[j] = json[j]
162 | }
163 | newItem.push(newElement)
164 | // create children for newElement
165 | if (_.isContainer(json.type) && json.children) arguments.callee(json.children, newElement)
166 | }
167 | }
168 | return _.extend(newItem, _.proto)
169 | }
170 |
171 | _.isWindow = function(type) { // 判断是否为window元素
172 | var winType = [
173 | 'window', 'palette', 'dialog',
174 | 'Window', 'Palette', 'Dialog'
175 | ]
176 | var len = winType.length
177 | for (var i = 0; i < len; i++) {
178 | if (type === winType[i]) return true
179 | }
180 | return false
181 | }
182 |
183 | _.isContainer = function(type) { // 判断是否为容器
184 | var winType = [
185 | 'window', 'palette', 'dialog', 'group', 'panel', 'tabbedpanel', 'treeview', 'dropdownlist', 'listbox', 'listitem', 'tab', 'node',
186 | 'Window', 'Palette', 'Dialog', 'Group', 'Panel', 'TabbedPanel', 'Treeview', 'DropDownList', 'ListBox', 'ListItem', 'Tab', 'Node'
187 | ]
188 | var len = winType.length
189 | for (var i = 0; i < len; i++) {
190 | if (type === winType[i]) return true
191 | }
192 | return false
193 | }
194 |
195 | _.isElement = function(type) { // 判断是否是window元素外的其他UI元素
196 | var winType = [
197 | 'panel', 'tabbedpanel', 'tab', 'group', 'button', 'checkbox', 'dropdownlist', 'edittext', 'flashplayer', 'iconbutton', 'image', 'item', 'listbox', 'listitem', 'progressbar', 'radiobutton', 'scrollbar', 'slider', 'statictext', 'treeview', 'tab', 'node',
198 | 'Panel', 'TabbedPanel', 'Tab', 'Group', 'Button', 'CheckBox', 'DropDownList', 'EditText', 'FlashPlayer', 'IconButton', 'Image', 'Item', 'ListBox', 'ListItem', 'ProgressBar', 'RadioButton', 'Scrollbar', 'Slider', 'StaticText', 'Treeview', 'Tab', 'Node'
199 | ]
200 | var len = winType.length
201 | for (var i = 0; i < len; i++) {
202 | if (type === winType[i]) return true
203 | }
204 | return false
205 | }
206 |
207 | _.isUI = function(type) { // 判断是否为UI元素
208 | if (_.isWindow(type) || _.isElement(type)) return true
209 | return false
210 | }
211 | /** ********************functions for find*********************************************************/
212 | _.findElementsByProp = function(elements, prop, value, recursive) {
213 | var matchs = []
214 | for (var i = 0; i < elements.length; i++) {
215 | if (elements[i].children) var atoms = elements[i].children
216 | else if (elements[i].items) atoms = elements[i].items
217 | else continue
218 | var match = []
219 | for (var j = 0; j < atoms.length; j++) {
220 | if (atoms[j][prop] && (value === '' || atoms[j][prop].toString() === value)) { match.push(atoms[j]) }
221 | if (recursive && (atoms[j].children || atoms[j].items)) {
222 | var temp = arguments.callee([atoms[j]], prop, value, 1)
223 | match = _.merge(temp, match)
224 | }
225 | }
226 | matchs = _.merge(match, matchs)
227 | }
228 | return matchs
229 | }
230 | _.findElementsByFn = function(elements, fn, recursive) {
231 | var match = []
232 | for (var i = 0; i < elements.length; i++) {
233 | if (elements[i].children) var atoms = elements[i].children
234 | else if (elements[i].items) atoms = elements[i].items
235 | else continue
236 | for (var j = 0; j < atoms.length; j++) {
237 | if (fn(atoms[j])) match.push(atoms[j])
238 | if (recursive && (atoms[j].children || atoms[j].items)) {
239 | var temp = arguments.callee(atoms[j].children, fn, 1)
240 | match = _.merge(temp, match)
241 | }
242 | }
243 | }
244 | return match
245 | }
246 | _.filterElementByProp = function(elements, prop, value) {
247 | var matchs = []
248 | for (var i = 0; i < elements.length; i++) {
249 | if (elements[i][prop] && (value === '' || elements[i][prop].toString() === value)) { matchs.push(elements[i]) }
250 | }
251 | return matchs
252 | }
253 | _.filterElementByFn = function(elements, fn) {
254 | var matchs = []
255 | for (var i = 0; i < elements.length; i++) {
256 | if (fn(elements[i])) matchs.push(elements[i])
257 | }
258 | return matchs
259 | }
260 | _.formalSelector = function(selector) { // 正规化选择器,去掉所有空格,多余字母和多余标记符,得到并列选择器,这时每个选择器中的每个标记符均有效
261 | /**
262 | 1.去掉空格])及后面的字母,如'[er t ]a:w (w)e'变为'[er:w(w'
263 | 2.去掉标记符前面的所有标记符号,遇到*>,不删除,因为标记号*>,后面不需要字母
264 | 3.将*及其后面的字母替换为*
265 | 4.将,及其后面的字母替换为,
266 | 5.将>及其后面的字母替换为>
267 | 6.将开始处的字母及逗号去掉
268 | 7.用逗号分隔选择器,得到正规化的若干个选择器
269 | 8.返回选择器数组
270 | */
271 | return selector.replace(/[\s\]\)]\w*/g, '').replace(/[\#\.\[\:\=]+(?=[\#\.\[\]\,\:\=\>\*])/g, '').replace(/\*+\w*/g, '*').replace(/\,+\w*/g, ',').replace(/\>+\w*/g, '>').replace(/^\w*\,/g, '').split(/\,/g)
272 | }
273 | _.parserSelector = function(selector) { // 解析单个的选择器,返回一个表示过程的数组
274 | var sign, content, prop, value, func, param, doFind // recursive是否递归,doFind是否查找,否则过滤操作
275 | var recursive = 1
276 | var process = []
277 | var parts = selector.replace(/(?=[\#\.\[\:\>\*])/g, '@').replace(/^\@/, '').split('@')// 将选择器根据标记分开
278 |
279 | for (var i = 0; i < parts.length; i++) {
280 | if (parts[i] === '>') { // 当出现>的时候find函数将不会递归
281 | recursive = 0
282 | i++
283 | }
284 | // 初始化
285 | sign = parts[i][0]
286 | content = parts[i].substr(1)
287 | prop = value = func = param = ''
288 | doFind = 1
289 | // 判断
290 | switch (sign) {
291 | case '*': prop = 'type'; break
292 | case '#': prop = 'id'; value = content; break
293 | case '.': prop = 'type'; value = content; break
294 | case '[':
295 | var p = content.split('=')
296 | prop = p[0]
297 | if (p.length === 2) value = p[1]
298 | break
299 | case ':':
300 | var fn = content.split('(')
301 | func = fn[0]
302 | if (fn.length === 2) param = fn[1]
303 | doFind = 0
304 | break
305 | }
306 | process.push([prop, value, recursive, doFind, func, param])
307 | recursive = 1
308 | }
309 |
310 | return process
311 | }
312 | _.merge = function(newArray, oldArray) { // 合并两个数组,并且去掉重复元素
313 | var temp = []
314 | var b = 1
315 | for (var i = 0; i < newArray.length; i++) {
316 | for (var j = 0; j < oldArray.length; j++) {
317 | if (newArray[i] === oldArray[j]) {
318 | b = 0
319 | break
320 | }
321 | }
322 | if (b) temp.push(newArray[i])
323 | }
324 | return oldArray.concat(temp)
325 | }
326 | /** ********************layout functions*********************************************************/
327 | _.layout = function(e) { // 默认布局方式
328 | e.margins = 0
329 | e.spacing = 5
330 | if (e.align) {
331 | switch (e.align) {
332 | case 'fill':
333 | case 'fill_fill': e.alignment = ['fill', 'fill']; break
334 |
335 | case 'center':
336 | case 'center_center': e.alignment = ['center', 'center']; break
337 |
338 | case 'left_fill':
339 | case 'left': e.alignment = ['left', 'fill']; break
340 | case 'center_fill': e.alignment = ['center', 'fill']; break
341 | case 'right_fill':
342 | case 'right': e.alignment = ['right', 'fill']; break
343 |
344 | case 'fill_top':
345 | case 'top': e.alignment = ['fill', 'top']; break
346 | case 'fill_center': e.alignment = ['fill', 'center']; break
347 | case 'fill_bottom':
348 | case 'bottom': e.alignment = ['fill', 'bottom']; break
349 |
350 | case 'left_center': e.alignment = ['left', 'center']; break
351 | case 'right_center': e.alignment = ['right', 'center']; break
352 | case 'center_top': e.alignment = ['center', 'top']; break
353 | case 'center_bottom': e.alignment = ['center', 'bottom']; break
354 |
355 | case 'left_top': e.alignment = ['left', 'top']; break
356 | case 'left_bottom': e.alignment = ['left', 'bottom']; break
357 | case 'right_top': e.alignment = ['right', 'top']; break
358 | case 'right_bottom': e.alignment = ['right', 'bottom']; break
359 | }
360 | }
361 | }
362 | _.extend(_.windows, _.proto)
363 | /** ********************other functions*********************************************************/
364 | _.JSON = { // 直接copy过来的代码
365 | /* eslint-disable no-eval */
366 | parse: function(strJSON) { return eval('(' + strJSON + ')') },
367 | stringify: (function() {
368 | var toString = Object.prototype.toString
369 | var isArray = Array.isArray || function(a) { return toString.call(a) === '[object Array]' }
370 | var escMap = {'"': '\\"', '\\': '\\\\', '\b': '\\b', '\f': '\\f', '\n': '\\n', '\r': '\\r', '\t': '\\t'}
371 | var escFunc = function(m) { return escMap[m] || '\\u' + (m.charCodeAt(0) + 0x10000).toString(16).substr(1) }
372 | var escRE = /[\\"\u0000-\u001F\u2028\u2029]/g
373 | return function stringify(value) {
374 | if (value == null) {
375 | return 'null'
376 | } else if (typeof value === 'number') {
377 | return isFinite(value) ? value.toString() : 'null'
378 | } else if (typeof value === 'boolean') {
379 | return value.toString()
380 | } else if (typeof value === 'object') {
381 | if (typeof value.toJSON === 'function') {
382 | return stringify(value.toJSON())
383 | } else if (isArray(value)) {
384 | var res = '['
385 | for (var i = 0; i < value.length; i++) res += (i ? ', ' : '') + stringify(value[i])
386 | return res + ']'
387 | } else if (toString.call(value) === '[object Object]') {
388 | var tmp = []
389 | for (var k in value) {
390 | if (value.hasOwnProperty(k)) tmp.push(stringify(k) + ': ' + stringify(value[k]))
391 | }
392 | return '{' + tmp.join(', ') + '}'
393 | }
394 | }
395 | return '"' + value.toString().replace(escRE, escFunc) + '"'
396 | }
397 | })()
398 | }
399 |
400 | return _
401 | };
402 |
--------------------------------------------------------------------------------
/src/ui/settingWindow.js:
--------------------------------------------------------------------------------
1 | var moduleWindow = require('./moduleWindow')
2 | var moveGroupWindow = require('./moveGroupWindow')
3 | var outputGroupWindow = require('./outputGroupWindow')
4 | var checkVersion = require('../https/checkVersion')
5 |
6 | module.exports = function() {
7 | var _ = $.global.UIParser($.global)
8 |
9 | var UIJson = {
10 | newWin: {
11 | type: 'palette',
12 | text: sp.scriptName + ' v' + sp.scriptVersion,
13 | margins: 10,
14 | orientation: 'row',
15 | children: {
16 | leftGroup: {
17 | type: 'group',
18 | orientation: 'column',
19 | alignment: ['fill', 'fill'],
20 | alignChildren: ['fill', 'fill'],
21 | children: {
22 | group1: {
23 | type: 'group',
24 | orientation: 'row',
25 | alignment: ['fill', 'fill'],
26 | alignChildren: ['fill', 'fill'],
27 | children: {
28 | helpText: {
29 | type: 'edittext',
30 | properties: {
31 | multiline: true,
32 | scrolling: false
33 | },
34 | preferredSize: [150, 280],
35 | text: '',
36 | enabled: 1
37 | },
38 | gr: {
39 | type: 'group',
40 | orientation: 'column',
41 | alignment: ['fill', 'fill'],
42 | alignChildren: ['fill', 'fill'],
43 | margins: 0,
44 | spacing: 0,
45 | children: {
46 | drop: {
47 | type: 'dropdownlist',
48 | preferredSize: [150, 20]
49 | },
50 | wlist: {
51 | type: 'listbox',
52 | preferredSize: [150, 260]
53 | }
54 | }
55 | }
56 | }
57 | },
58 | group2: {
59 | type: 'group',
60 | orientation: 'row',
61 | alignment: ['fill', 'fill'],
62 | alignChildren: ['fill', 'fill'],
63 | children: {
64 | deleteFolder: {
65 | type: 'Button',
66 | preferredSize: [165, 27],
67 | text: loc(sp.deleteFolder),
68 | enabled: 1
69 | },
70 | changeGroupName: {
71 | type: 'Button',
72 | preferredSize: [165, 27],
73 | text: loc(sp.changeGroupName),
74 | enabled: 1
75 | }
76 | }
77 | },
78 | group3: {
79 | type: 'group',
80 | alignment: ['fill', 'fill'],
81 | alignChildren: ['fill', 'fill'],
82 | children: {
83 | output: {
84 | type: 'Button',
85 | text: loc(sp.output),
86 | enabled: 1
87 | },
88 | move: {
89 | type: 'Button',
90 | text: loc(sp.move),
91 | enabled: 1
92 | }
93 | }
94 | },
95 | group35: {
96 | type: 'group',
97 | orientation: 'row',
98 | alignment: ['fill', 'fill'],
99 | alignChildren: ['fill', 'fill'],
100 | children: {
101 | editModule: {
102 | type: 'Button',
103 | preferredSize: [330, 27],
104 | text: loc(sp.editModule),
105 | enabled: 1
106 | }
107 | }
108 | }
109 | }
110 | },
111 | rightGroup: {
112 | type: 'group',
113 | orientation: 'column',
114 | alignment: ['top', 'fill'],
115 | alignChildren: ['fill', 'fill'],
116 | children: {
117 | group4: {
118 | type: 'panel',
119 | text: loc(sp.generalOption),
120 | orientation: 'column',
121 | alignment: ['fill', 'fill'],
122 | alignChildren: ['fill', 'fill'],
123 | children: {
124 | g0: {
125 | type: 'group',
126 | orientation: 'row',
127 | alignment: ['fill', 'fill'],
128 | alignChildren: ['fill', 'fill'],
129 | children: {
130 | gr1: {
131 | type: 'group',
132 | children: {
133 | limitText: {
134 | type: 'checkbox',
135 | text: loc(sp.limitText)
136 | }
137 | }
138 | },
139 | gr2: {
140 | type: 'group',
141 | children: {
142 | checkVersionOnStartup: {
143 | type: 'checkbox',
144 | text: loc(sp.checkVersionOnStartupText)
145 | }
146 | }
147 | }
148 | }
149 | },
150 | gr1: {
151 | type: 'group',
152 | orientation: 'row',
153 | alignment: ['fill', 'fill'],
154 | alignChildren: ['fill', 'fill'],
155 | children: {
156 | gr1: {
157 | type: 'group',
158 | children: {
159 | thumbType: {
160 | type: 'checkbox',
161 | text: loc(sp.thumbType)
162 | }
163 | }
164 | },
165 | gr2: {
166 | type: 'group',
167 | children: {
168 | coverChange: {
169 | type: 'checkbox',
170 | text: loc(sp.coverChange)
171 | }
172 | }
173 | }
174 | }
175 | },
176 | grRatio: {
177 | type: 'group',
178 | alignment: ['fill', 'fill'],
179 | alignChildren: ['fill', 'fill'],
180 | children: {
181 | setRatio: {
182 | type: 'statictext',
183 | text: loc(sp.setRatioText)
184 | },
185 | ratioText: {
186 | type: 'edittext',
187 | text: '',
188 | characters: 10
189 | }
190 | }
191 | },
192 | gr4: {
193 | type: 'group',
194 | alignment: ['fill', 'fill'],
195 | alignChildren: ['fill', 'fill'],
196 | children: {
197 | frameSecond: {
198 | type: 'statictext',
199 | text: loc(sp.frameSecondText)
200 | },
201 | frameSecondText: {
202 | type: 'edittext',
203 | text: '',
204 | characters: 10
205 | }
206 | }
207 | },
208 | gr5: {
209 | type: 'group',
210 | alignment: ['fill', 'fill'],
211 | alignChildren: ['fill', 'fill'],
212 | children: {
213 | frameNum: {
214 | type: 'statictext',
215 | text: loc(sp.frameNumText)
216 | },
217 | frameNumText: {
218 | type: 'edittext',
219 | text: '',
220 | characters: 10
221 | }
222 | }
223 | },
224 | gr0: {
225 | type: 'group',
226 | orientation: 'row',
227 | alignment: ['fill', 'fill'],
228 | alignChildren: ['fill', 'fill'],
229 | children: {
230 | gr2: {
231 | type: 'group',
232 | alignment: ['fill', 'fill'],
233 | alignChildren: ['fill', 'fill'],
234 | children: {
235 | folderName: {
236 | type: 'statictext',
237 | text: loc(sp.folderName)
238 | },
239 | folderNameText: {
240 | type: 'edittext',
241 | text: '',
242 | justify: 'center',
243 | characters: 10
244 | }
245 | }
246 | }
247 | }
248 | },
249 | gr3: {
250 | type: 'group',
251 | alignment: ['fill', 'fill'],
252 | alignChildren: ['fill', 'fill'],
253 | children: {
254 | effectName: {
255 | type: 'statictext',
256 | text: loc(sp.effectName)
257 | },
258 | effectNameText: {
259 | type: 'edittext',
260 | text: '',
261 | characters: 14
262 | }
263 | }
264 | }
265 | }
266 | }, // end of group4
267 | group5: {
268 | type: 'panel',
269 | text: loc(sp.otherOption),
270 | orientation: 'column',
271 | alignment: ['fill', 'fill'],
272 | alignChildren: ['fill', 'fill'],
273 | children: {
274 | group5: {
275 | type: 'group',
276 | orientation: 'row',
277 | alignment: ['fill', 'fill'],
278 | alignChildren: ['fill', 'fill'],
279 | children: {
280 | ch: {
281 | type: 'Button',
282 | text: '中文',
283 | enabled: 0
284 | },
285 | en: {
286 | type: 'Button',
287 | text: 'English',
288 | enabled: 0
289 | }
290 | }
291 | },
292 | group6: {
293 | type: 'group',
294 | orientation: 'row',
295 | alignment: ['fill', 'fill'],
296 | alignChildren: ['fill', 'fill'],
297 | children: {
298 | sourceCode: { type: 'Button', text: loc(sp.sourceCode), enabled: 1 },
299 | openLink: {
300 | type: 'Button',
301 | text: loc(sp.link),
302 | enabled: 1
303 | }
304 | }
305 | },
306 | group7: {
307 | type: 'group',
308 | orientation: 'row',
309 | alignment: ['fill', 'fill'],
310 | alignChildren: ['fill', 'fill'],
311 | children: {
312 | checkVersion: {
313 | type: 'Button',
314 | text: loc(sp.checkVersion),
315 | enabled: 1
316 | },
317 | addIssue: { type: 'Button', text: loc(sp.addIssue), enabled: 1 }
318 | }
319 | }
320 | }
321 | }
322 | }
323 | }
324 |
325 | }
326 | } // end of newWin
327 |
328 | }
329 |
330 | var win = _.newWindow(UIJson)[0]
331 |
332 | _('*').each(function(e) {
333 | switch (e.id) {
334 | default:
335 | if (e.type !== 'checkbox') break
336 | e.value = sp.getSettingAsBool(e.id)
337 | var name = e.id + 'Value'
338 | e.onClick = function() {
339 | sp[name] = this.value
340 | }
341 | break
342 | case 'addIssue':
343 | e.onClick = function() {
344 | if (sp.lang === 'ch') {
345 | var shouldOpen = confirm(loc(sp.issueDesc))
346 | if (shouldOpen) {
347 | sp.openLink(sp.githubIssue)
348 | } else {
349 | sp.openLink(sp.issueLink)
350 | }
351 | } else {
352 | alert(loc(sp.issueDesc))
353 | sp.openLink(sp.githubIssue)
354 | }
355 | }
356 | break
357 | case 'sourceCode':
358 | e.onClick = function() {
359 | sp.openLink(sp.sourceCodeLink)
360 | }
361 | break
362 | case 'ratioText':
363 | e.text = (1 / sp.gridViewScale).toString()
364 | e.onChange = function() {
365 | alert(loc(sp.setRatioHelptip) + '\r\n' + loc(sp.setRatioWarning))
366 | var value = parseFloat(this.text)
367 | if (isNaN(value) || value < 1) {
368 | this.text = (1 / sp.gridViewScale).toString()
369 | return
370 | }
371 |
372 | sp.gridViewScale = 1 / value
373 | sp.saveSetting('gridViewScale', sp.gridViewScale.toString())
374 | sp.gv.refresh()
375 | }
376 | break
377 |
378 | case 'frameSecondText':
379 | e.text = sp.frameSecond.toString()
380 | e.onChange = function() {
381 | if (isNaN(this.text)) {
382 | this.text = sp.frameSecond
383 | return
384 | }
385 |
386 | var value = parseInt(this.text)
387 | if (value >= 200) value = 200
388 | if (value <= 33) value = 33
389 | sp.frameSecond = value
390 | sp.saveSetting('frameSecond', value)
391 | this.text = value.toString()
392 | }
393 | break
394 | case 'frameNumText':
395 | e.text = sp.frameNum.toString()
396 | e.onChange = function() {
397 | if (isNaN(this.text)) {
398 | this.text = sp.frameNum
399 | return
400 | }
401 |
402 | var value = parseInt(this.text)
403 | if (sp.isCC2015) {
404 | if (value >= 300) value = 300
405 | } else {
406 | if (value >= 50) value = 50
407 | }
408 | if (value <= 0) value = 0
409 | sp.frameNum = value
410 | sp.saveSetting('frameNum', value)
411 | this.text = value.toString()
412 | }
413 | break
414 | case 'move':
415 | e.onClick = function() {
416 | if (!_('#wlist')[0].selection || !_('#drop')[0]) return alert(loc(sp.selectGroupFirst))
417 | moveGroupWindow(_('#wlist')[0].selection, _('#drop')[0].selection, win)
418 | }
419 | break
420 | case 'editModule':
421 | e.onClick = function() {
422 | if (!_('#drop')[0]) return alert(loc(sp.selectModuleFirst))
423 | moduleWindow(_('#drop')[0].selection, win, module.exports)
424 | }
425 | break
426 | case 'drop':
427 | sp.xmlGroupNames.forEach(function(item, index) {
428 | this.add('item', item)
429 | }, e)
430 | var ratio = 1 / sp.gv.scale - 1
431 | var addedSeparatorLength = Math.ceil(ratio * sp.xmlGroupNames.length)
432 | for (var i = 0; i < addedSeparatorLength; i++) {
433 | e.add('separator')
434 | }
435 | var wlist = _('#wlist')[0]
436 | e.onChange = function() {
437 | if (!this.selection) return
438 | if (!sp.parentDroplist.selection) return
439 | wlist.removeAll()
440 | sp.parentDroplist.selection = this.selection.index
441 | sp.xmlCurrentFileNames.forEach(function(item, index) {
442 | this.add('item', item)
443 | }, wlist)
444 | sp.gv.refresh()
445 | }
446 | e.selection = sp.parentDroplist.selection ? sp.parentDroplist.selection.index : 0
447 | break
448 | case 'helpText':
449 | e.text = loc(sp.about)
450 | e.onChange = e.onChanging = function() {
451 | this.text = loc(sp.about)
452 | }
453 | break
454 | case 'wlist':
455 | break
456 | case 'deleteFolder':
457 | e.onClick = function() {
458 | var folder = sp.materialFolder
459 | sp.deleteThisFolder(folder)
460 | alert(loc(sp.deleteOk))
461 | }
462 | break
463 | case 'changeGroupName':
464 | e.onClick = function() {
465 | var wlist = _('#wlist')[0]
466 | if (!wlist.selection) return alert(loc(sp.selectGroupFirst))
467 | var newGroupName = prompt(loc(sp.setName), wlist.selection.text)
468 | if (!newGroupName) return
469 | if (sp.xmlFileNames.includes(newGroupName)) {
470 | alert(loc(sp.existName))
471 | return
472 | }
473 |
474 | var file = sp.getFileByName(wlist.selection.text)
475 | file.rename(newGroupName + '.xml')
476 | var xml = new XML(sp.settingsFile.readd())
477 | var index = sp.getGlobalIndexFromFileName(wlist.selection.text)
478 | xml.ListItems.insertChildAfter(xml.ListItems.child(index),
479 | new XML('' + newGroupName.toString() + ''))
480 | xml.ListItems.child(index).setLocalName('waitToDelete')
481 | delete xml.ListItems.waitToDelete
482 | sp.settingsFile.writee(xml)
483 | var folder = sp.getImageFolderByName(wlist.selection.text)
484 | if (folder.exists) { folder.rename(newGroupName) }
485 | wlist.items[wlist.selection.index].text = newGroupName
486 | sp.droplist.items[wlist.selection.index].text = newGroupName
487 | sp.xmlFileNames[index] = newGroupName
488 | sp.droplist.notify('onChange')
489 | }
490 | break
491 | case 'output':
492 | e.onClick = function() {
493 | outputGroupWindow()
494 | }
495 | break
496 | case 'limitText':
497 | e.value = sp.getSettingAsBool('limitText')
498 | e.onClick = function() {
499 | sp.saveSetting('limitText', this.value.toString())
500 | sp.gv.limitText = sp.getSettingAsBool('limitText')
501 | sp.gv.refresh()
502 | }
503 | break
504 |
505 | case 'folderNameText':
506 | e.text = sp.getSetting('folderName')
507 | e.onChange = function() {
508 | sp.saveSetting('folderName', this.text)
509 | }
510 | break
511 | case 'effectNameText':
512 | e.text = sp.getSetting('effectName')
513 | e.onChange = function() {
514 | sp.saveSetting('effectName', this.text)
515 | }
516 | break
517 | case 'ch':
518 | e.enabled = sp.lang === 'en'
519 | if (e.enabled === true) { e.enabled = !sp.isForceEnglish() }
520 | e.onClick = function() {
521 | sp.saveSetting('language', 'ch')
522 | alert('请重新打开脚本,语言会将自动变更为中文.')
523 | _('#en')[0].enabled = true
524 | _('#ch')[0].enabled = false
525 | }
526 | break
527 | case 'en':
528 | e.enabled = sp.lang === 'ch'
529 | e.onClick = function() {
530 | sp.saveSetting('language', 'en')
531 | alert('Please restart script,language will be changed into English.')
532 | _('#en')[0].enabled = false
533 | _('#ch')[0].enabled = true
534 | }
535 | break
536 | case 'checkVersion':
537 | if (sp.lang === 'en') { e.size = _('#openLink')[0].size = [211, 27] }
538 | e.onClick = checkVersion(win)
539 | break
540 | case 'openLink':
541 | e.onClick = function() {
542 | sp.openLink(sp.weiboLink)
543 | }
544 | break
545 | }
546 | })
547 |
548 | var warpDrop = function(a, b, index1, index2) {
549 | var tempD = a.text
550 | a.text = b.text
551 | b.text = tempD
552 | var tempXML = sp.xmlCurrentFileNames[index1]
553 | sp.xmlCurrentFileNames[index1] = sp.xmlCurrentFileNames[index2]
554 | sp.xmlCurrentFileNames[index2] = tempXML
555 | }
556 |
557 | var exchange = function(isUp, wXML) {
558 | var xmlIndex = _('#wlist')[0].selection.index
559 | var groupIndex = _('#drop')[0].selection.index
560 | var name = sp.droplist.selection.text
561 |
562 | if (isUp === true) {
563 | var wupxml = new XML(wXML.ParentGroup.child(groupIndex).child(xmlIndex))
564 | wXML.ParentGroup.child(groupIndex).insertChildBefore(wXML.ParentGroup.child(groupIndex).child(xmlIndex - 1), wupxml)
565 |
566 | wXML.ParentGroup.child(groupIndex).child(xmlIndex + 1).setLocalName('waitToDelete')
567 |
568 | delete wXML.ParentGroup.child(groupIndex).waitToDelete
569 |
570 | sp.settingsFile.writee(wXML)
571 | sp.swap(_('#wlist')[0].items[xmlIndex - 1], _('#wlist')[0].items[xmlIndex])
572 | warpDrop(sp.droplist.items[xmlIndex - 1], sp.droplist.items[xmlIndex], xmlIndex - 1, xmlIndex)
573 | } else {
574 | var wdownxml = new XML(wXML.ParentGroup.child(groupIndex).child(xmlIndex))
575 |
576 | wXML.ParentGroup.child(groupIndex).insertChildAfter(wXML.ParentGroup.child(groupIndex).child(xmlIndex + 1), wdownxml)
577 | wXML.ParentGroup.child(groupIndex).child(xmlIndex).setLocalName('waitToDelete')
578 | delete wXML.ParentGroup.child(groupIndex).waitToDelete
579 |
580 | sp.settingsFile.writee(wXML)
581 | sp.swap(_('#wlist')[0].items[xmlIndex + 1], _('#wlist')[0].items[xmlIndex])
582 | warpDrop(sp.droplist.items[xmlIndex + 1], sp.droplist.items[xmlIndex], xmlIndex + 1, xmlIndex)
583 | }
584 | sp.droplist.selection = sp.droplist.find(name)
585 | sp.droplist.notify('onChange')
586 | sp.gv.refresh()
587 | }
588 |
589 | var handleKey = function(key, control) {
590 | var wXML = new XML(sp.settingsFile.readd())
591 | switch (key.keyName) {
592 | case 'Up':
593 | if (_('#wlist')[0].selection !== null && _('#wlist')[0].selection.index > 0 && _('#drop')[0].selection) {
594 | exchange(true, wXML)
595 | };
596 | break
597 | case 'Down':
598 | if (_('#wlist')[0].selection !== null && _('#wlist')[0].selection.index < _('#wlist')[0].items.length - 1 && _('#drop')[0].selection) {
599 | exchange(false, wXML)
600 | };
601 | break
602 | }
603 | }
604 |
605 | _('#wlist')[0].addEventListener('keydown', function(k) {
606 | handleKey(k, this)
607 | })
608 |
609 | win.center()
610 | win.show()
611 | }
612 |
--------------------------------------------------------------------------------
/lib/GridView.js:
--------------------------------------------------------------------------------
1 | /** ***********************************新界面网格视图的构造函数****************************************/
2 | $.global.GridView = GridView
3 | function GridView(parent, attrs) {
4 | var keepRef = this
5 | /** **********************继承函数************************************************************/
6 | this.extend = function(target, source) {
7 | for (var i in source) target[i] = source[i]
8 | return target
9 | }
10 | /** *********************item 构造器***********************************************************************/
11 | this.item = function(text, image, parent) { // item 构造器
12 | if (!text) text = ''
13 | if (!image) image = null
14 | keepRef.extend(this, {
15 | id: 'item',
16 | index: 0,
17 | type: 'item',
18 | image: image,
19 | text: text,
20 | selected: false,
21 | prev: null,
22 | next: null,
23 | parent: parent,
24 | backgroundColor: null,
25 | strokeColor: null,
26 | rect: [0, 0, 100, 60], // item的矩阵信息
27 | imageRect: [0, 0, 100, 60], // item中图片的矩阵信息,为相对rect的量
28 | fontRect: [0, 90, 100, 10] // item中文字背景的矩阵信息,为相对rect的量
29 | })
30 | /** *****************item 原型****************************************************************************/
31 | keepRef.extend(this, {
32 | remove: function(notRefreshList) { // 移除元素, 若notRefreshList为true,默认不刷新列表
33 | var e = this.parent
34 | var prev = this.prev
35 | var next = this.next
36 | if (prev) {
37 | prev.next = next
38 | if (next) {
39 | next.prev = prev
40 | }
41 | } else {
42 | next.prev = null
43 | }
44 |
45 | if (this === e.lastSelectedItem) e.lastSelectedItem = null
46 | e.getChildren()
47 | e.getSelection()
48 |
49 | if (!notRefreshList) e.refresh()
50 | },
51 | moveUp: function() { // 元素上移
52 | try {
53 | var e = this.parent
54 | var prev = this.prev
55 | var next = this.next
56 | if (prev) {
57 | if (prev.prev) { prev.prev.next = this }
58 | this.prev = prev.prev
59 | this.next = prev
60 | prev.prev = this
61 | prev.next = next
62 | if (next) { next.prev = prev }
63 | }
64 | if (this.prev === null) { e.first = this }
65 | e.getChildren()
66 | e.refresh()
67 | } catch (err) {
68 | alert(err.line.toString())
69 | }
70 | },
71 | moveDown: function() { // 元素下移
72 | try {
73 | var e = this.parent
74 | var prev = this.prev
75 | var next = this.next
76 | if (next) {
77 | var right = this.next.next
78 | if (prev) { prev.next = next }
79 | next.prev = prev
80 | next.next = this
81 | this.prev = next
82 | this.next = right
83 | if (right) { right.prev = this }
84 | }
85 | if (next.prev === null) { e.first = next }
86 | e.getChildren()
87 | e.refresh()
88 | } catch (err) {
89 | alert(err.line.toString())
90 | }
91 | },
92 | moveBefore: function(item) { // 将当前item移动到指定item之前
93 | var e = this.parent
94 | this.remove(1)
95 | if (this.next) { this.next.prev = this.prev }
96 | if (this.prev) { this.prev.next = this.next }
97 | this.next = item
98 | this.prev = item.prev
99 | if (item.prev) {
100 | item.prev.next = this
101 | }
102 | item.prev = this
103 | if (this.prev === null) { e.first = this }
104 | e.getChildren()
105 | e.refresh()
106 | },
107 | moveAfter: function(item) { // 将当前item移动到指定item之后
108 | var e = this.parent
109 | this.remove(1)
110 | this.prev.next = this.next
111 | this.next.prev = this.prev
112 | this.prev = item
113 | this.next = item.next
114 | if (item.next) {
115 | item.next.prev = this
116 | }
117 | item.next = this
118 |
119 | e.getChildren()
120 | e.refresh()
121 | }
122 | })
123 | }
124 |
125 | /** *********************网格视图的默认属性***********************************************************************/
126 | this.extend(this, {
127 | id: 'GridView',
128 | type: 'GridView',
129 |
130 | listHeight: 400, // 列表的总高度
131 | scale: 1, // 列表缩放
132 | backgroundColor: [0.15, 0.15, 0.15], // 背景色
133 | scrollBlockColor: [0.16, 0.16, 0.16], // 滚动条滑块颜色
134 | scrollBarColor: [0.08, 0.08, 0.08], // 滚动条背景颜色
135 | scrollBarWidth: 17, // 滚动条宽度
136 | scrollBarValue: 0, // 滚动条值
137 | scrollBlockRect: [0, 0, 20, 100], // 滚动条滑块的矩阵信息
138 | scrollScale: 1, // 滚动条是否显示,为0时滚动条消失(不可设置)
139 | spacing: [3, 3], // item的间距
140 | itemBackgroundColor: [0, 0, 0, 0], // item的背景颜色
141 | itemStrokeColor: [0.2, 0.2, 0.2, 0], // item的边框描边颜色
142 | itemSelectedColor: [38 / 255, 38 / 255, 38 / 255], // item被选中时的颜色
143 | itemSelectedRecColor: [0.2, 0.7, 1], // item被选中时的颜色
144 | itemFontColor: [1, 1, 1], // item的字体颜色
145 | // itemFontColor: [0.023, 0.023, 0.023],//item的字体颜色
146 | itemSize: [100, 60], // item的大小
147 | itemStrokeSize: 1.6, // item的边框描边大小
148 | itemFontHeight: 0, // item的字体大小
149 | itemFontSize: 20, // item的字体大小
150 | showText: false, // 是否显示文字
151 | limitText: false,
152 | version: 'CC2014',
153 | first: null, // 第一个item
154 | last: null, // 最后一个item
155 | children: [], // 所有的item
156 | selection: [], // 被选中的item
157 | lastSelectedItem: null, // 最后一次被选中的item
158 |
159 | leftClick: function(event) { }, // 左键单击事件
160 | leftDoubleClick: function(event) { }, // 左键双击事件
161 | rightClick: function(event) { }, // 右键单击事件
162 | rightDoubleClick: function(event) { }, // 右键双击事件
163 | mouseMove: function(event) { }, // 鼠标移动事件
164 | mouseOut: function(event) { }
165 | })
166 |
167 | /** *******************网格视图的原型*************************************************************************/
168 | this.extend(this, {
169 | add: function(text, image) { // 添加元素
170 | var newItem = new this.item(text, image, this)
171 | if (this.first) {
172 | this.last.next = newItem
173 | newItem.prev = this.last
174 | this.children.push(newItem)
175 | this.last = this.children[this.children.length - 1]
176 | this.last.index = this.last.prev.index + 1
177 | } else {
178 | this.first = this.last = newItem
179 | this.children.push(newItem)
180 | this.first.index = 0
181 | }
182 |
183 | this.getSelection()
184 |
185 | return newItem
186 | },
187 | removeAll: function() { // 移除所有元素
188 | this.first = this.last = this.lastSelectedItem = null
189 | this.selection = this.children = []
190 | },
191 | getChildren: function() { // 获取子元素
192 | var children = []
193 | var item = this.first
194 | var index = 0
195 |
196 | while (item) {
197 | children.push(item)
198 | item.index = index
199 | item = item.next
200 | index++
201 | }
202 |
203 | this.children = children
204 | if (children.length) {
205 | this.first = children[0]
206 | this.last = children[children.length - 1]
207 | }
208 | return children
209 | },
210 | getSelection: function() { // 获取选中元素
211 | var selection = []
212 | var item = this.first
213 |
214 | while (item) {
215 | if (item.selected) selection.push(item)
216 | item = item.next
217 | }
218 |
219 | this.selection = selection
220 | return selection
221 | },
222 | create: function(parent) { // 创建网格视图,包括监听在内
223 | var e = this
224 | var GV = e.GV = parent.add("group{orientation: 'stack', alignment: ['fill','fill'], margins: 0, spacing: 0}")
225 | var list = e.list = GV.add("button{alignment:['fill','fill']}")
226 | var eventRect = e.eventRect = GV.add("group{alignment:['fill','fill']}")
227 | var screen = $.screens[0].toString().split('-').pop().split(':')
228 | GV.maximumSize =
229 | list.maximumSize =
230 | eventRect.maximumSize = [parseInt(screen[0]), parseInt(screen[1])]
231 |
232 | eventRect.addEventListener('mousedown', function(event) {
233 | e.event.mouseMoving = false
234 | e.event.targetScrollBar = e.getScrollBarFromLocation(event.clientX, event.clientY)
235 | e.event.targetItem = e.getItemFromLocation(event.clientX, event.clientY)
236 | if (event.button === 0) { // 左键
237 | if (event.detail === 1) { // 左键单击
238 | e.event.leftButtonPressed = true
239 | e.event.leftButtonPressedLocation = [event.clientX, event.clientY]
240 | e.event.leftButtonPressedScrollBarValue = e.scrollBarValue
241 | /***************************************/
242 | if (event.ctrlKey === false) { e.mouseMove(event, e.event.targetItem, true) }
243 |
244 | /***************************************/
245 | } else if (event.detail === 2) { // 左键双击
246 | e.leftDoubleClick(event)
247 | }
248 | } else if (event.button === 2) { // 右键
249 | if (event.detail === 1) { // 右键单击
250 | e.event.rightButtonPressed = true
251 | e.event.rightButtonPressedLocation = [event.clientX, event.clientY]
252 | e.event.rightButtonPressedScrollBarValue = e.scrollBarValue
253 | /***************************************/
254 |
255 | /***************************************/
256 | } else if (event.detail === 2) { // 右键双击
257 | }
258 | }
259 | })
260 | eventRect.addEventListener('mousemove', function(event) {
261 | e.event.mouseMoving = true
262 | if (e.event.leftButtonPressed) { // 左键移动
263 | /***************************************/
264 | e.defaultLeftMouseMove(event)
265 | e.refresh()
266 | /***************************************/
267 | } else if (e.event.rightButtonPressed) { // 右键移动
268 |
269 | /***************************************/
270 |
271 | /***************************************/
272 | }
273 | if (event.ctrlKey === false) { e.mouseMove(event, e.getItemFromLocation(event.clientX, event.clientY)) }
274 | })
275 | eventRect.addEventListener('mouseup', function(event) {
276 | if (e.event.leftButtonPressed) { // 左键
277 | if (e.event.mouseMoving) {
278 | /***************************************/
279 | e.defaultLeftClick(event)
280 | e.leftClick(event)
281 | /***************************************/
282 | } else {
283 | e.defaultLeftClick(event)
284 | e.leftClick(event)
285 | }
286 | } else if (e.event.rightButtonPressed) { // 右键
287 | if (e.event.mouseMoving) {
288 | /***************************************/
289 | e.rightClick(event)
290 | /***************************************/
291 | } else if (event.detail === 1) {
292 | e.rightClick(event)
293 | } else if (event.detail === 2) {
294 | e.rightDoubleClick(event)
295 | }
296 | }
297 | e.event.leftButtonPressed = false
298 | e.event.rightButtonPressed = false
299 | e.event.mouseMoving = false
300 | e.event.targetScrollBar = false
301 | e.refresh()
302 | })
303 | /*
304 | eventRect.addEventListener('mouseout', function(event) {
305 | e.event.leftButtonPressed = false;
306 | e.event.rightButtonPressed = false;
307 | e.event.mouseMoving = false;
308 | e.event.targetScrollBar = false;
309 | e.mouseOut();
310 | e.refresh();
311 | });
312 | */
313 |
314 | list.onDraw = e.listDraw
315 | list.GV = e
316 | },
317 | alignment: function(alignment) {
318 | this.GV.alignment = alignment
319 | },
320 | size: function(size) {
321 | this.GV.size = size
322 | this.list.size = size
323 | this.eventRect.size = size
324 | },
325 | location: function(location) {
326 | this.GV.location = location
327 | },
328 | listDraw: function() { // 重绘函数
329 | var e = this.GV
330 | var g = this.graphics
331 | var items = e.children
332 |
333 | var bgBrush = g.newBrush(g.BrushType.SOLID_COLOR, e.backgroundColor)
334 | var itemBgBrush = g.newBrush(g.PenType.SOLID_COLOR, e.itemBackgroundColor)
335 | var strokePen = g.newPen(g.PenType.SOLID_COLOR, e.itemStrokeColor, e.itemStrokeSize)
336 | var selectedPen = g.newPen(g.PenType.SOLID_COLOR, e.itemSelectedRecColor, e.itemStrokeSize)
337 | var selectedBrush = g.newBrush(g.PenType.SOLID_COLOR, e.itemSelectedColor)
338 | var scrollBarBrush = g.newBrush(g.PenType.SOLID_COLOR, e.scrollBarColor)
339 | var scrollBlockBrush = g.newBrush(g.PenType.SOLID_COLOR, e.scrollBlockColor)
340 |
341 | if (e.showText) e.itemFontHeight = e.itemFontSize
342 | else e.itemFontHeight = 0
343 | e.relocationItems()
344 | e.resizeItems()
345 | e.resizeScrollBar()
346 | /******************************************************************************************/
347 | // 绘制背景
348 | g.newPath()
349 | g.rectPath(0, 0, e.list.size[0] - e.scrollBarWidth * e.scale * e.scrollScale, e.list.size[1])
350 | g.fillPath(bgBrush)
351 | /******************************************************************************************/
352 | var shouldDrawArr = []
353 | var pointArr = []
354 | var limit = e.GV.size[1]
355 |
356 | for (var i = 0; i < items.length; i++) {
357 | var target = items[i]
358 | var height = target.rect[1] + target.imageRect[1] - e.scrollBarValue + target.imageRect[3]
359 | var shouldDraw = height > 0 && height - target.imageRect[3] + 10 < limit
360 | shouldDrawArr.push(shouldDraw)
361 | pointArr.push(
362 | [
363 | target.rect[0],
364 | target.rect[1],
365 | target.rect[2],
366 | target.rect[3],
367 | target.rect[1] - e.scrollBarValue
368 | ]
369 | )
370 | }
371 | // item背景色填充
372 | g.newPath()
373 | for (i = 0; i < items.length; i++) {
374 | var item = items[i]
375 | var rect = pointArr[i]
376 | if (items[i].backgroundColor) continue
377 |
378 | g.rectPath(
379 | rect[0],
380 | rect[4],
381 | rect[2],
382 | rect[3] - item.fontRect[3]
383 | )
384 | }
385 | g.fillPath(itemBgBrush)
386 | // 添加item指定的背景色
387 | for (i = 0; i < items.length; i++) {
388 | item = items[i]
389 | rect = pointArr[i]
390 | if (item.backgroundColor) {
391 | var brush = g.newBrush(g.PenType.SOLID_COLOR, item.backgroundColor)
392 | g.newPath()
393 | g.rectPath(
394 | rect[0],
395 | rect[4],
396 | rect[2],
397 | rect[3]
398 | )
399 | g.fillPath(brush)
400 | }
401 | // item图片绘制
402 | if (item.image && shouldDrawArr[i]) {
403 | var image = ScriptUI.newImage(item.image)
404 | g.drawImage(
405 | image,
406 | rect[0] + item.imageRect[0],
407 | rect[1] + item.imageRect[1] - e.scrollBarValue,
408 | item.imageRect[2],
409 | item.imageRect[3]
410 | )
411 | }
412 | }
413 |
414 | /******************************************************************************************/
415 | // item描边
416 | g.newPath()
417 | for (i = 0; i < items.length; i++) {
418 | item = items[i]
419 | if (!item.selected) {
420 | if (item.strokeColor) continue
421 | if (shouldDrawArr[i]) {
422 | rect = pointArr[i]
423 | g.rectPath(
424 | rect[0],
425 | rect[4],
426 | rect[2],
427 | rect[3]
428 | )
429 | }
430 | }
431 | }
432 | g.strokePath(strokePen)
433 | // 为指定了描边颜色的item描边
434 | for (i = 0; i < items.length; i++) {
435 | item = items[i]
436 | if (item.strokeColor && shouldDrawArr[i]) {
437 | rect = pointArr[i]
438 | var pen = g.newPen(g.PenType.SOLID_COLOR, item.strokeColor, e.itemStrokeSize)
439 | g.newPath()
440 | g.rectPath(
441 | rect[0],
442 | rect[4],
443 | rect[2],
444 | rect[3]
445 | )
446 | g.strokePath(pen)
447 | }
448 | }
449 |
450 | if (e.showText) {
451 | // 为被选中的item文字添加背景色
452 | g.newPath()
453 | for (i = 0; i < items.length; i++) {
454 | item = items[i]
455 | if (item.selected && shouldDrawArr[i]) {
456 | g.rectPath(
457 | item.rect[0] + item.fontRect[0] + 1,
458 | item.rect[1] + item.fontRect[1] - e.scrollBarValue,
459 | item.fontRect[2],
460 | item.fontRect[3]
461 | )
462 | }
463 | }
464 | g.fillPath(selectedBrush)
465 | }
466 | // 为被选中的item描边
467 | g.newPath()
468 | for (i = 0; i < items.length; i++) {
469 | item = items[i]
470 | if (item.selected && shouldDrawArr[i]) {
471 | rect = pointArr[i]
472 | g.rectPath(
473 | rect[0],
474 | rect[4],
475 | rect[2],
476 | rect[3]
477 | )
478 | }
479 | }
480 | g.strokePath(selectedPen)
481 |
482 | /******************************************************************************************/
483 | if (e.showText) {
484 | // item文字
485 | var fontPen = g.newPen(g.PenType.SOLID_COLOR, e.itemFontColor, e.itemFontSize * e.scale)
486 | var font = ScriptUI.newFont('Microsoft YaHei', ScriptUI.FontStyle.REGULAR, e.itemFontSize * e.scale * 0.6)
487 |
488 | var trickWidthForCC2014 = 20
489 | var trickForOther = 0
490 | for (i = 0; i < items.length; i++) {
491 | item = items[i]
492 | if (!shouldDrawArr[i]) continue
493 | var textRect = g.measureString(item.text, font)
494 | var thisText = item.text
495 | var totalText = item.text
496 | var base = textRect.width - item.imageRect[2] - e.spacing[0] * 2
497 | if (e.limitText === true && e.version === 'CC2014') {
498 | if (base >= -trickWidthForCC2014) {
499 | for (var j = 0; j < item.text.length; j++) {
500 | thisText = item.text.slice(0, totalText.length - 2 - j)
501 | textRect = g.measureString(thisText, font)
502 | var newBase = textRect.width - item.imageRect[2] - e.spacing[0] * 2
503 | if (newBase < -trickWidthForCC2014) {
504 | break
505 | }
506 | }
507 | }
508 | } else if (e.version !== 'CC2014') {
509 | if (base >= trickForOther) {
510 | for (j = 0; j < item.text.length; j++) {
511 | thisText = item.text.slice(0, totalText.length - 2 - j)
512 | textRect = g.measureString(thisText, font)
513 | newBase = textRect.width - item.imageRect[2] - e.spacing[0] * 2
514 | if (newBase < trickForOther) {
515 | break
516 | }
517 | }
518 | }
519 | }
520 |
521 | var value = parseInt(thisText)
522 | if (!isNaN(value) && value.toString() === thisText) {
523 | // it's a number, add a space after it to avoid location bug in drawString method
524 | thisText += ' '
525 | }
526 | if (e.version === 'CC2014') {
527 | g.drawString(
528 | thisText,
529 | fontPen,
530 | item.rect[0] + item.fontRect[0],
531 | item.rect[1] + item.fontRect[1] - e.scrollBarValue - 10, // trick for CC2014 location bug
532 | font
533 | )
534 | } else {
535 | g.drawString(
536 | thisText,
537 | fontPen,
538 | item.rect[0] + item.fontRect[0],
539 | item.rect[1] + item.fontRect[1] - e.scrollBarValue,
540 | font
541 | )
542 | }
543 | }
544 | } // end of showText
545 |
546 | /******************************************************************************************/
547 | if (e.scrollScale) {
548 | // 绘制滚动条背景
549 | g.newPath()
550 | g.rectPath(
551 | e.list.size[0] * e.scale - e.scrollBarWidth * e.scale,
552 | 0,
553 | e.scrollBarWidth * e.scale,
554 | e.list.size[1] * e.scale
555 | )
556 | g.fillPath(scrollBarBrush)
557 |
558 | // 绘制滚动条滑块
559 | g.newPath()
560 | g.rectPath(
561 | e.scrollBlockRect[0],
562 | e.scrollBlockRect[1],
563 | e.scrollBlockRect[2],
564 | e.scrollBlockRect[3]
565 | )
566 | g.fillPath(scrollBlockBrush)
567 | }
568 | },
569 | resizeItems: function() { // 对所有的item的大小重新指定
570 | var e = this
571 | var items = e.children
572 | for (var i = 0; i < items.length; i++) {
573 | items[i].rect[2] = e.itemSize[0] * e.scale
574 | items[i].rect[3] = e.itemSize[1] * e.scale
575 | items[i].imageRect[2] = e.itemSize[0] * e.scale
576 | items[i].imageRect[3] = e.itemSize[1] * e.scale
577 | // items[i].imageRect = e.resizeImage(ScriptUI.newImage(items[i].image));
578 | items[i].fontRect[0] = 0
579 | items[i].fontRect[1] = (e.itemSize[1] - e.itemFontHeight) * e.scale + 5
580 | items[i].fontRect[2] = e.itemSize[0] * e.scale
581 | items[i].fontRect[3] = 15
582 | }
583 | },
584 | relocationItems: function() { // 对所有的item的位置重新指定
585 | var e = this
586 | var list = e.list
587 | var items = e.children
588 | e.scrollScale = 0
589 |
590 | var numWidth = Math.floor((list.size[0] * e.scale - e.scrollBarWidth * e.scale * e.scrollScale) / (e.itemSize[0] * e.scale + e.spacing[0]))
591 | if (numWidth === 0) numWidth = 1
592 | e.listHeight = Math.ceil(items.length / numWidth) * (e.itemSize[1] * e.scale + e.spacing[1])
593 |
594 | for (var i = 0; i < items.length; i++) {
595 | items[i].rect[0] = e.spacing[0] + i % numWidth * (e.itemSize[0] * e.scale + e.spacing[0])
596 | items[i].rect[1] = e.spacing[1] + Math.floor(i / numWidth) * (e.itemSize[1] * e.scale + e.spacing[1])
597 | }
598 | e.scrollScale = 1
599 | },
600 | resizeImage: function(image) { // 在不改变图片比例的情况下重新指定图片大小
601 | var e = this
602 |
603 | var WH = [e.itemSize[0], e.itemSize[1]]
604 | var wh = image.size
605 | var k = Math.min(WH[0] / wh[0], WH[1] / wh[1])
606 | var xy
607 | wh = [k * wh[0], k * wh[1]]
608 | xy = [(WH[0] - wh[0]) / 2, (WH[1] - wh[1]) / 2]
609 |
610 | return [xy[0] * e.scale, xy[1] * e.scale, wh[0] * e.scale, wh[1] * e.scale]
611 | },
612 | resizeScrollBar: function() { // 重新指定滚动条的尺寸
613 | var e = this
614 | var list = e.list
615 | e.scrollBarMaxValue = e.listHeight - list.size[1] * e.scale + 7 / e.scale
616 | if (e.scrollBarMaxValue < 0) e.scrollBarValue = 0
617 |
618 | e.scrollBlockRect[0] = list.size[0] * e.scale - e.scrollBarWidth * e.scale + 1 // 这里加1是为了让滚动条有一条边线
619 | e.scrollBlockRect[2] = e.scrollBarWidth * e.scale - 2 // 这里减2是为了让滚动条有一条边线
620 | if (e.listHeight < list.size[1] * e.scale) {
621 | e.scrollScale = 0
622 | e.scrollBlockRect[3] = list.size[1] * e.scale
623 | } else {
624 | e.scrollScale = 1
625 | e.scrollBlockRect[3] = list.size[1] * e.scale * list.size[1] * e.scale / e.listHeight * e.scale
626 | }
627 | e.scrollBlockRect[1] = (e.list.size[1] * e.scale - e.scrollBlockRect[3]) * e.scrollBarValue / e.scrollBarMaxValue
628 | },
629 | defaultLeftClick: function(event) { // 默认的左键点击事件
630 | var e = this
631 | var s = e.selection
632 | var c = e.children
633 | var currentItem = e.event.targetItem
634 | if (!currentItem) {
635 | for (var i = 0; i < s.length; i++) s[i].selected = 0
636 | e.lastSelectedItem = null
637 | e.getSelection()
638 | }
639 |
640 | if (currentItem) {
641 | var preSelected = currentItem.selected
642 | if (event.ctrlKey === false) {
643 | for (i = 0; i < c.length; i++) c[i].selected = 0
644 | }
645 | if (e.lastSelectedItem && event.shiftKey === true) {
646 | var startIndex = e.lastSelectedItem.index
647 | var endIndex = currentItem.index
648 | for (i = 0; i < c.length; i++) {
649 | if ((c[i].index - startIndex) * (c[i].index - endIndex) <= 0) { // 判断e.index是否在startIndex和endIndex之间
650 | c[i].selected = 1
651 | }
652 | }
653 | }
654 |
655 | currentItem.selected = true
656 | if (e.lastSelectedItem && event.ctrlKey === true) {
657 | if (preSelected === true) {
658 | currentItem.selected = false
659 | }
660 | } else {
661 | e.lastSelectedItem = currentItem
662 | }
663 |
664 | e.getSelection()
665 | } else if (e.event.targetScrollBar === 1) {
666 | e.scrollBarValue = e.scrollBarMaxValue * event.clientY / e.list.size[1]
667 | }
668 | /** **********这里添加点击事件***************/
669 |
670 | /********************************************/
671 | },
672 | defaultLeftMouseMove: function(event) { // 默认的左键移动事件
673 | var e = this
674 | if (e.event.targetScrollBar === 2) {
675 | e.scrollBarValue = (e.event.leftButtonPressedScrollBarValue + (event.clientY - e.event.leftButtonPressedLocation[1]) * e.scrollBarMaxValue / (e.list.size[1] * e.scale - e.scrollBlockRect[3]))
676 | } else {
677 | e.scrollBarValue = (e.event.leftButtonPressedScrollBarValue - event.clientY + e.event.leftButtonPressedLocation[1])
678 | }
679 | if (e.scrollBarValue < 0) {
680 | e.scrollBarValue = 0
681 | } else if (e.scrollBarValue > e.scrollBarMaxValue) {
682 | e.scrollBarValue = e.scrollBarMaxValue
683 | }
684 | },
685 | defaultRightMouseMove: function(event) { // 默认的右键移动事件
686 | var e = this
687 | e.scrollBarValue = e.event.rightButtonPressedScrollBarValue - event.clientY + e.event.rightButtonPressedLocation[1]
688 |
689 | if (e.scrollBarValue < 0) {
690 | e.scrollBarValue = 0
691 | } else if (e.scrollBarValue > e.scrollBarMaxValue) {
692 | e.scrollBarValue = e.scrollBarMaxValue
693 | }
694 | },
695 | getItemFromLocation: function(x, y) { // 从点击位置获取当前item
696 | var e = this
697 | var c = e.children
698 | for (var i = 0; i < c.length; i++) {
699 | if (x - c[i].rect[0] > 0 && x - c[i].rect[0] < c[i].rect[2] && y - c[i].rect[1] + e.scrollBarValue > 0 && y - c[i].rect[1] + e.scrollBarValue < c[i].rect[3]) { return c[i] }
700 | }
701 | return null
702 | },
703 | getScrollBarFromLocation: function(x, y) { // 当前位置不是滚动条返回0,为滚动条背景返回1,为滚动条滑块返回2
704 | var e = this
705 |
706 | if (x > e.list.size[0] * e.scale - e.scrollBarWidth) {
707 | if (y > e.scrollBlockRect[1] && y < e.scrollBlockRect[1] + e.scrollBlockRect[3]) { return 2 }
708 | return 1
709 | }
710 | return 0
711 | },
712 | refresh: function() { // 刷新列表
713 | this.list.notify('onDraw')
714 | }
715 | })
716 |
717 | if (attrs) this.extend(this, attrs) // 将指定属性赋值给新的网格视图
718 |
719 | this.event = { // 监听事件的辅助变量
720 | leftButtonPressed: false, // 左键是否在按下状态
721 | leftButtonPressedLocation: [0, 0], // 左键按下时的位置
722 | rightButtonPressed: false, // 右键是否在按下状态
723 | rightButtonPressedLocation: [0, 0], // 右键按下时的位置
724 | leftButtonPressedScrollBarValue: 0, // 左键在按下时的滚动条值
725 | rightButtonPressedScrollBarValue: 0, // 右键在按下时的滚动条值
726 | targetItem: null, // 左键在按下时的item目标,没有item为null
727 | targetScrollBar: 0, // 左键在按下时的滚动条目标,不是滚动条为0,滚动条背景为1,滚动条滑块为2
728 | mouseMoving: false // 鼠标是否在移动
729 | }
730 |
731 | if (parent) this.create(parent)
732 | }
733 |
--------------------------------------------------------------------------------
/lib/Translate.js:
--------------------------------------------------------------------------------
1 | /** ***********************************Sp_translate v1.7,自动修复多语言版本造成的表达式报错问题**************************************/
2 | $.global.translate = translate
3 | function translate(thisObj, expProps) {
4 | var you = this
5 |
6 | var tsp = {
7 | trans: { en: 'Translate', ch: '开始' },
8 | allComp: { en: 'Translate all comps', ch: '翻译所有合成' },
9 | activeComp: { en: 'Translate active comp', ch: '翻译当前合成' },
10 | selectedComp: { en: 'Translate selected comps', ch: '翻译选中合成' },
11 | wrongExp: { en: 'Translate wrong exps', ch: '仅翻译错误表达式' },
12 | rightExp: { en: 'Translate right exps', ch: '仅翻译正确表达式' },
13 | allExp: { en: 'Translate all expressions', ch: '翻译所有的表达式' },
14 | log: { en: 'log', ch: '记录' },
15 | about: { en: 'About', ch: '关于' },
16 | editBtn: { en: 'Edit hot words', ch: '编辑关键词' },
17 | str: {
18 | en: 'This script can fix wrong expressions caused by different language version of AE.By smallpath',
19 | ch: '外文工程表达式报错?本脚本可以快速解决这个问题~ @秋风_小径'
20 | },
21 | ok: { en: 'Ok', ch: '确认' },
22 | cancel: { en: 'Cancel', ch: '取消' },
23 | add: { en: 'Add', ch: '增加' },
24 | edit: { en: 'Edit', ch: '编辑' },
25 | change: { en: 'Change', ch: '更改' },
26 | deleteE: { en: 'Delete', ch: '删除' },
27 | sureDelete: { en: 'Are you sure to delete it ?', ch: '确认删除吗?' },
28 | addHelp: {
29 | en: 'Input new hot words,or choose one item to edit and delete.Make sure what you input has double quotation.',
30 | ch: '你可以新增关键词,编辑或者删除选中的条目.请确认你输入的名称有双引号'
31 | },
32 | openFile: { en: 'Do you want to open the log file?', ch: '想要打开记录文件吗?' },
33 | complete: { en: 'Complete!', ch: '完成!' },
34 | _1: { en: 'This is the log file', ch: '这里是记录文件' },
35 | _2: {
36 | en: '\r\rWrong expressions that can not be fixed at all are as follows.Check them in their comp.\r',
37 | ch: '\r\r没有被修复的表达式的位置如下,请进入合成检查'
38 | },
39 | _3: { en: '\rComp index =', ch: '\r合成索引数 =' },
40 | _4: { en: 'Comp name =', ch: '合成名 =' },
41 | _5: {
42 | en: '\r\rInfo above is the expressions that has not been fixed.\r\r',
43 | ch: '上面的是没有被修复的表达式的位置.\r\r'
44 | },
45 | _6: {
46 | en: '\r\rInfo as follows is the expressions that has been fixed.\r',
47 | ch: '下面的信息是被成功修复的表达式.'
48 | },
49 | _7: { en: '\rComp index =', ch: '\r合成索引数' },
50 | _8: { en: 'Comp name =', ch: '合成名 =' },
51 | _9: { en: '\r Layer index =', ch: '\r 图层索引数 =' },
52 | _10: { en: ' Layer name =', ch: '\r 图层名 =' },
53 | _11: { en: ' Property name =', ch: ' 属性名 =' }
54 |
55 | }
56 |
57 | this.supportedLanguages = $.global.translate.supportedLanguages = 4
58 | this.hotWords = []
59 |
60 | var thisFolder, thisFile
61 | if ($.layer) {
62 | thisFolder = new Folder($.layer.tempFolder.toString())
63 | if (!thisFolder.exists) thisFolder.create()
64 | thisFile = new File(thisFolder.fullName + $.layer.slash.toString() + 'whiteList.xml')
65 | } else {
66 | thisFolder = new Folder(Folder.userData.fullName + '/Aescripts/Sp_memory')
67 | if (!thisFolder.exists) thisFolder.create()
68 | thisFile = File(thisFolder.fullName + '/whiteList.xml')
69 | }
70 |
71 | var allWords = [
72 | ['"Angle Control"', '"角度控制"', '"角度制御"', '"ADBE Angle Control"'],
73 | ['"Checkbox Control"', '"复选框控制"', '"チェックボックス制御"', '"ADBE Checkbox Control"'],
74 | ['"Color Control"', '"色彩控制"', '"カラー制御"', '"ADBE Color Control"'],
75 | ['"Layer Control"', '"图层控制"', '"レイヤー制御"', '"ADBE Layer Control"'],
76 | ['"Point Control"', '"点控制"', '"ポイント制御"', '"ADBE Point Control"'],
77 | ['"Slider Control"', '"滑杆控制"', '"スライダー制御"', '"ADBE Slider Control"'],
78 | ['"Angle"', '"角度"', '"角度"', '"ADBE Angle Control-0001"'],
79 | ['"Checkbox"', '"检测框"', '"チェックボックス"', '"ADBE Checkbox Control-0001"'],
80 | ['"Color"', '"颜色"', '"カラー"', '"ADBE Color Control-0001"'],
81 | ['"Layer"', '"图层"', '"レイヤー"', '"ADBE Layer Control-0001"'],
82 | ['"Point"', '"点"', '"ポイント"', '"ADBE Point Control-0001"'],
83 | ['"Slider"', '"滑块"', '"スライダー"', '"ADBE Slider Control-0001"'],
84 | ['"Motion Tile"', '"动态平铺"', '"モーションタイル"', '"ADBE Tile"'],
85 | ['"Tile Width"', '"平铺宽度"', '"タイルの幅"', '"ADBE Tile-0003"']
86 | ]
87 | if (thisFile.exists) {
88 | var content = thisFile.readd()
89 | var hahaxml = new XML(content)
90 | if (hahaxml.settings.version.toString() !== '1.6') thisFile.remove()
91 | }
92 | var iii
93 | if (!thisFile.exists || thisFile.length === -1) {
94 | var newxml = new XML('')
95 | newxml.settings.version = '1.6'
96 | newxml.settings.author = 'smallpath'
97 | for (iii = 0; iii < allWords.length; iii++) {
98 | newxml.words.words[iii] = allWords[iii]
99 | }
100 | if (sp.os === 'mac') {
101 | thisFile.encoding = 'UTF-8'
102 | }
103 | thisFile.writee(newxml)
104 | }
105 | content = thisFile.readd()
106 | var myxml = new XML(content)
107 | for (iii = 0; iii < myxml.words.words.length(); iii++) {
108 | var arr = myxml.words.words[iii].split(',')
109 | this.hotWords.push(arr)
110 | }
111 |
112 | this.changeNode = function(index, en, ch, ja, adbe) {
113 | if (en !== '' || ch !== '' || ja !== '' || adbe !== '') {
114 | if (en === '') en = 'None'
115 | if (ch === '') ch = 'None'
116 | if (ja === '') ja = 'None'
117 | if (adbe === '') adbe = 'None'
118 |
119 | content = thisFile.readd()
120 | var xml = new XML(content)
121 | xml.words.words[index] = [en, ch, ja, adbe]
122 | thisFile.writee(xml)
123 |
124 | this.hotWords = []
125 | for (var iii = 0; iii < xml.words.words.length(); iii++) {
126 | arr = xml.words.words[iii]
127 | arr = arr.split(',')
128 | this.hotWords.push(arr)
129 | }
130 | }
131 | }
132 |
133 | this.deleteNode = function(index) {
134 | content = thisFile.readd()
135 | var deletexml = new XML(content)
136 | delete deletexml.words.words[index]
137 | thisFile.writee(deletexml)
138 | this.hotWords = []
139 | for (var iii = 0; iii < deletexml.words.words.length(); iii++) {
140 | arr = deletexml.words.words[iii]
141 | arr = arr.split(',')
142 | this.hotWords.push(arr)
143 | }
144 | }
145 |
146 | this.addNode = function(en, ch, ja, adbe) {
147 | if (en !== '' || ch !== '' || ja !== '' || adbe !== '') {
148 | if (en === '') en = 'None'
149 | if (ch === '') ch = 'None'
150 | if (ja === '') ja = 'None'
151 | if (adbe === '') adbe = 'None'
152 |
153 | content = thisFile.readd()
154 | var addxml = new XML(content)
155 | addxml.words.words[addxml.words.words.length()] = [en, ch, ja, adbe]
156 | thisFile.writee(addxml)
157 |
158 | this.hotWords = []
159 | for (var iii = 0; iii < addxml.words.words.length(); iii++) {
160 | arr = addxml.words.words[iii]
161 | arr = arr.split(',')
162 | this.hotWords.push(arr)
163 | }
164 | }
165 | }
166 |
167 | this.findReplace = function(prop, langId, compid) {
168 | try {
169 | var expr = prop.expression
170 | var oldExp = prop.expression
171 | if (expr !== '') {
172 | for (var l = 0; l < this.supportedLanguages; l++) {
173 | if (l !== langId) {
174 | for (var i = 0; i < this.hotWords.length; i++) {
175 | if (this.hotWords[i][l] !== 'None') {
176 | var regExp = new RegExp(this.hotWords[i][l], 'g')
177 | expr = expr.replace(regExp, this.hotWords[i][langId])
178 | }
179 | }
180 | }
181 | }
182 | app.beginSuppressDialogs()
183 | try {
184 | prop.expression = expr
185 | } catch (e) {
186 | try {
187 | prop.expressionEnabled = true
188 | prop.valueAtTime(0, false)
189 | if (lista.selection.index === 0) {
190 | if (prop.expressionEnabled === false) {
191 | prop.expression = oldExp
192 | }
193 | }
194 | } catch (er) {
195 | // writeLn("Skip wrong expressions.");
196 | wrongcomps.push(compid)
197 | };
198 | }
199 | app.endSuppressDialogs(false)
200 | }
201 | } catch (err) { }
202 | }
203 |
204 | Array.prototype.add = function(str) {
205 | var check = false
206 | for (var ia = 0; ia < this.length; ia++) {
207 | if (this[ia] === str) {
208 | check = true
209 | }
210 | }
211 | if (check === false) {
212 | this[this.length] = str
213 | }
214 | }
215 |
216 | function recursiveScanLayerForExpr(ref, compindex, ja) {
217 | var global = $.global.translate.helper
218 | if (ref !== null) {
219 | var prop
220 | for (var i = 1; i <= ref.numProperties; i++) {
221 | prop = ref.property(i)
222 | var isLayerStyle = prop.matchName === 'ADBE Layer Styles' && prop.canSetEnabled === false
223 | var isMaterial = prop.matchName === 'ADBE Material Options Group' && prop.propertyGroup(prop.propertyDepth).threeDLayer === false
224 | var isAudio = prop.matchName === 'ADBE Audio Group' && prop.propertyGroup(prop.propertyDepth).hasAudio === false
225 | var isExtra = prop.matchName === 'ADBE Extrsn Options Group'
226 | var isPlane = prop.matchName === 'ADBE Plane Options Group'
227 | var isVector = prop.matchName === 'ADBE Vector Materials Group'
228 | var shouldRecursiveScan = !(isLayerStyle || isMaterial || isAudio || isExtra || isPlane || isVector)
229 | if (checkb.value === true) {
230 | if ((prop.propertyType === PropertyType.PROPERTY) && (prop.expression !== '') && prop.canSetExpression && (prop.expressionEnabled === true)) { // .expressionError
231 | global.propArr.push(prop)
232 | prop.selected = true
233 | global.exps.push(prop.name)
234 | global.comps.add(compindex)
235 | global.layerTemp.add(ja)
236 | } else if ((prop.propertyType === PropertyType.INDEXED_GROUP) || (prop.propertyType === PropertyType.NAMED_GROUP)) {
237 | if (shouldRecursiveScan) {
238 | recursiveScanLayerForExpr(prop, compindex, ja)
239 | }
240 | }
241 | } else if (checka.value === true) {
242 | if ((prop.propertyType === PropertyType.PROPERTY) && (prop.expression !== '') && prop.canSetExpression && (prop.expressionEnabled === false)) {
243 | global.propArr.push(prop)
244 | prop.selected = true
245 | global.exps.push(prop.name)
246 | global.comps.add(compindex)
247 | global.layerTemp.add(ja)
248 | } else if ((prop.propertyType === PropertyType.INDEXED_GROUP) || (prop.propertyType === PropertyType.NAMED_GROUP)) {
249 | if (shouldRecursiveScan) {
250 | recursiveScanLayerForExpr(prop, compindex, ja)
251 | }
252 | }
253 | } else if (checkc.value === true) {
254 | if ((prop.propertyType === PropertyType.PROPERTY) && (prop.expression !== '') && prop.canSetExpression) {
255 | global.propArr.push(prop)
256 | prop.selected = true
257 | global.exps.push(prop.name)
258 | global.comps.add(compindex)
259 | global.layerTemp.add(ja)
260 | } else if ((prop.propertyType === PropertyType.INDEXED_GROUP) || (prop.propertyType === PropertyType.NAMED_GROUP)) {
261 | if (shouldRecursiveScan) {
262 | recursiveScanLayerForExpr(prop, compindex, ja)
263 | }
264 | }
265 | }
266 | }
267 | }
268 | }
269 |
270 | function isInId(itemid, array) {
271 | var check = false
272 | for (var ie = 0; ie < array.length; ie++) {
273 | if (itemid === array[ie]) {
274 | check = true
275 | }
276 | }
277 | return check
278 | }
279 |
280 | function ScanProjectForExpr(blackList) {
281 | var global = $.global.translate.helper = {}
282 | global.propArr = []
283 | global.exps = []
284 | global.layerExps = []
285 | global.comps = []
286 | global.layers = []
287 | global.layerTemp = []
288 | wrongcomps = []
289 | var j
290 | for (var i = 1; i <= app.project.numItems; i++) {
291 | var item = app.project.item(i)
292 | if (item instanceof CompItem) {
293 | if (isInId(i, blackList) === true) {
294 | writeLn('Proccessing: ' + item.name)
295 | for (j = 1; j <= item.numLayers; j++) {
296 | item.layer(j).selected = false
297 | recursiveScanLayerForExpr(item.layer(j), i, j)
298 | if (global.exps.length !== 0) {
299 | global.layerExps.push(global.exps)
300 | }
301 | global.exps = []
302 | }
303 | }
304 | if (global.layerTemp.length !== 0) {
305 | global.layers.push(global.layerTemp)
306 | }
307 | global.layerTemp = []
308 | var selProps = global.propArr
309 | app.beginUndoGroup('Undo translate')
310 | for (var ic = 0; ic < selProps.length; ic++) {
311 | if (lista.selection.index === 0) {
312 | switch (app.language) {
313 | case Language.ENGLISH:
314 | you.findReplace(selProps[ic], 0, i)
315 | break
316 | case Language.CHINESE:
317 | you.findReplace(selProps[ic], 1, i)
318 | break
319 | case Language.JAPANESE:
320 | you.findReplace(selProps[ic], 2, i)
321 | break
322 | default:
323 | break
324 | }
325 | } else if (lista.selection.index === 1) {
326 | you.findReplace(selProps[ic], 0, i)
327 | } else if (lista.selection.index === 2) {
328 | you.findReplace(selProps[ic], 1, i)
329 | } else if (lista.selection.index === 3) {
330 | you.findReplace(selProps[ic], 2, i)
331 | } else if (lista.selection.index === 4) {
332 | you.findReplace(selProps[ic], 3, i)
333 | }
334 | }
335 | app.endUndoGroup()
336 | for (j = 1; j <= item.numLayers; j++) {
337 | item.layer(j).selected = false
338 | }
339 | }
340 | }
341 | return [global.comps, global.layers, global.layerExps, wrongcomps]
342 | }
343 |
344 | function searchExpression(excludeByName, expFilters) {
345 | var allExps = ScanProjectForExpr(excludeByName)
346 | return allExps
347 | }
348 |
349 | var winW = (thisObj instanceof Panel) ? thisObj : new Window('palette', 'Sp_translate v1.7', undefined, {
350 | resizeable: true
351 | })
352 | winW.margins = 10
353 | var thisRes = `Group{
354 | orientation:'column',
355 | alignChildren:['left','fill'],
356 | list:DropDownList{preferredSize:[200,25],properties:{items:['` + loc(tsp.allComp) + `','` + loc(tsp.activeComp) + `','` + loc(tsp.selectedComp) + `']}},
357 | start:Button{text:'` + loc(tsp.trans) + `',preferredSize:[200,50]},
358 | group:Group{
359 | alignChildren:['left','fill'],
360 | checka:Checkbox{text:'` + loc(tsp.wrongExp) + `',value:0},
361 | lista:DropDownList{properties:{items:['Default','English','中文','日本語','Common']},size:[60,25]}
362 | }
363 | groupa:Group{
364 | alignChildren:['left','fill'],
365 | checkb:Checkbox{text:'` + loc(tsp.rightExp) + `',value:0},
366 | about:Button{text:'` + loc(tsp.about) + `',size:[70,25]},
367 | }
368 | groupb:Group{
369 | alignChildren:['left','fill'],
370 | checkc:Checkbox{text:'` + loc(tsp.allExp) + `',value:1},
371 | checkFile:Checkbox{text:'` + loc(tsp.log) + `',size:[80,10]}
372 | }
373 | addbtn:Button{text:'` + loc(tsp.editBtn) + `',preferredSize:[200,30]}
374 | }`
375 | try { var winTempA = winW.add(thisRes) } catch (err) { }
376 | winW.maximumSize.width = 220
377 | winTempA.list.selection = 1
378 | winTempA.group.lista.selection = 0
379 | var list = winTempA.list
380 | var start = winTempA.start
381 | var group = winTempA.group
382 | var checka = group.checka
383 | var lista = group.lista
384 | var groupa = winTempA.groupa
385 | var checkb = groupa.checkb
386 | var about = groupa.about
387 | var groupb = winTempA.groupb
388 | var checkc = groupb.checkc
389 | var checkFile = groupb.checkFile
390 | var addbtn = winTempA.addbtn
391 | var outFile
392 |
393 | lista.selection = 0
394 |
395 | about.onClick = function() {
396 | var text = loc(tsp.str)
397 | var wina = new Window('palette', loc(tsp.about))
398 | var a = wina.add('edittext')
399 | a.text = text
400 | var groupa = wina.add('group')
401 | var abtn = groupa.add('button', undefined, loc(tsp.ok))
402 | var bbtn = groupa.add('button', undefined, loc(tsp.cancel))
403 |
404 | a.onChange = a.onChanging = function() {
405 | this.text = text
406 | }
407 |
408 | abtn.onClick = bbtn.onClick = function() {
409 | wina.close()
410 | }
411 | wina.center()
412 | wina.show()
413 | }
414 |
415 | checkFile.onClick = function() {
416 | if (checkFile.value === true) {
417 | outFile = File.saveDialog('', 'txt')
418 | if (outFile === null) checkFile.value = false
419 | }
420 | }
421 |
422 | addbtn.onClick = function() {
423 | var www = new Window('palette', loc(tsp.editBtn), undefined, {
424 | resizeable: false
425 | })
426 | var gr1 = www.add('group')
427 | var stat1 = gr1.add('statictext', undefined, 'English ')
428 | stat1.characters = 19
429 | var stat2 = gr1.add('statictext', undefined, '中文 ')
430 | stat2.characters = 19
431 | var stat3 = gr1.add('statictext', undefined, ' 日本語')
432 | stat3.characters = 19
433 | var stat4 = gr1.add('statictext', undefined, ' Common')
434 | stat4.characters = 19
435 | var gr2 = www.add('group')
436 | var edit1 = gr2.add('edittext', undefined)
437 | edit1.characters = 19
438 | var edit2 = gr2.add('edittext', undefined)
439 | edit2.characters = 19
440 | var edit3 = gr2.add('edittext', undefined)
441 | edit3.characters = 19
442 | var edit4 = gr2.add('edittext', undefined)
443 | edit4.characters = 19
444 | var addde = www.add('group')
445 | var adda = addde.add('button', undefined, loc(tsp.add))
446 | adda.size = [180, 40]
447 | var stackgroup = addde.add('group')
448 | stackgroup.orientation = 'stack'
449 | var addb = stackgroup.add('button', undefined, loc(tsp.edit))
450 | addb.size = [180, 40]
451 | addb.visible = true
452 | var addchange = stackgroup.add('button', undefined, loc(tsp.change))
453 | addchange.size = [180, 40]
454 | addchange.visible = false
455 | var addc = addde.add('button', undefined, loc(tsp.deleteE))
456 | addc.size = [180, 40]
457 | var stackgroupa = addde.add('group')
458 | stackgroupa.orientation = 'stack'
459 | var addd = stackgroupa.add('button', undefined, loc(tsp.about))
460 | addd.size = [180, 40]
461 | addd.visible = true
462 | var cancel = stackgroupa.add('button', undefined, loc(tsp.cancel))
463 | cancel.size = [180, 40]
464 | cancel.visible = false
465 | var myList = www.add('listbox', undefined, '', {
466 | numberOfColumns: 5,
467 | showHeaders: true,
468 | columnTitles: ['No', 'English', '中文', '日本語', 'Common'],
469 | columnWidths: [45, 165, 165, 165, 205]
470 | })
471 | for (var iii = 0; iii < you.hotWords.length; iii++) {
472 | var item = myList.add('item', iii + 1)
473 | for (var jjj = 0; jjj < you.hotWords[iii].length; jjj++) {
474 | if (you.hotWords[iii][jjj] !== 'None') {
475 | item.subItems[jjj].text = you.hotWords[iii][jjj]
476 | } else {
477 | item.subItems[jjj].text = ''
478 | }
479 | }
480 | }
481 |
482 | adda.onClick = function() {
483 | you.addNode(edit1.text, edit2.text, edit3.text, edit4.text)
484 | if (edit1.text !== '' || edit2.text !== '' || edit3.text !== '' || edit4.text !== '') {
485 | var item = myList.add('item', myList.children.length + 1)
486 | item.subItems[0].text = edit1.text
487 | item.subItems[1].text = edit2.text
488 | item.subItems[2].text = edit3.text
489 | item.subItems[3].text = edit4.text
490 | }
491 | edit1.text = ''
492 | edit2.text = ''
493 | edit3.text = ''
494 | edit4.text = ''
495 | }
496 |
497 | addb.onClick = function() {
498 | if (myList.selection instanceof Object) {
499 | adda.enabled = addc.enabled = false
500 | cancel.visible = true
501 | addd.visible = false
502 | edit1.text = (you.hotWords[myList.selection.index][0] !== 'None') ? you.hotWords[myList.selection.index][0] : ''
503 | edit2.text = (you.hotWords[myList.selection.index][1] !== 'None') ? you.hotWords[myList.selection.index][1] : ''
504 | edit3.text = (you.hotWords[myList.selection.index][2] !== 'None') ? you.hotWords[myList.selection.index][2] : ''
505 | edit4.text = (you.hotWords[myList.selection.index][3] !== 'None') ? you.hotWords[myList.selection.index][3] : ''
506 | addchange.visible = true
507 | addb.visible = false
508 | myList.enabled = false
509 | }
510 | }
511 |
512 | cancel.onClick = function() {
513 | adda.enabled = addc.enabled = true
514 | addd.visible = addb.visible = true
515 | cancel.visible = addchange.visible = false
516 | edit1.text = ''
517 | edit2.text = ''
518 | edit3.text = ''
519 | edit4.text = ''
520 | myList.enabled = true
521 | }
522 |
523 | addchange.onClick = function() {
524 | you.changeNode(myList.selection.index, edit1.text, edit2.text, edit3.text, edit4.text)
525 | adda.enabled = addc.enabled = true
526 | cancel.visible = false
527 | addd.visible = true
528 | var creatindex = myList.selection.index
529 | myList.remove(myList.items[creatindex])
530 | var item = myList.add('item', creatindex + 1, creatindex)
531 | item.subItems[0].text = edit1.text
532 | item.subItems[1].text = edit2.text
533 | item.subItems[2].text = edit3.text
534 | item.subItems[3].text = edit4.text
535 | edit1.text = edit2.text = edit3.text = edit4.text = ''
536 | addb.visible = true
537 | addchange.visible = false
538 | myList.enabled = true
539 | }
540 |
541 | addc.onClick = function() {
542 | if (myList.selection instanceof Object) {
543 | var wwww = new Window('palette', 'Alert', undefined)
544 | wwww.add('statictext', undefined, loc(tsp.sureDelete))
545 | var g = wwww.add('group')
546 | var yes = g.add('button', undefined, loc(tsp.ok), {
547 | name: 'ok'
548 | })
549 | yes.size = [60, 30]
550 | var no = g.add('button', undefined, loc(tsp.cancel), {
551 | name: 'cancel'
552 | })
553 | no.size = [60, 30]
554 | wwww.show()
555 | yes.onClick = function() {
556 | you.deleteNode(myList.selection.index)
557 | myList.remove(myList.items[myList.selection.index])
558 | wwww.close()
559 | }
560 | no.onClick = function() {
561 | wwww.close()
562 | }
563 | }
564 | }
565 |
566 | addd.onClick = function() {
567 | var text = loc(tsp.addHelp)
568 | var winb = new Window('palette', 'About')
569 | var a = winb.add('edittext')
570 | a.text = text
571 | var groupa = winb.add('group')
572 | var abtn = groupa.add('button', undefined, loc(tsp.ok))
573 | var bbtn = groupa.add('button', undefined, loc(tsp.cancel))
574 |
575 | a.onChange = a.onChanging = function() {
576 | this.text = text
577 | }
578 |
579 | abtn.onClick = bbtn.onClick = function() {
580 | winb.close()
581 | }
582 | winb.center()
583 | winb.show()
584 | }
585 |
586 | www.center()
587 | www.show()
588 | }
589 |
590 | checka.onClick = function() {
591 | if (checka.value === true) {
592 | checkb.value = false
593 | checkc.value = false
594 | }
595 | }
596 |
597 | checkb.onClick = function() {
598 | if (checkb.value === true) {
599 | checka.value = false
600 | checkc.value = false
601 | }
602 | }
603 |
604 | checkc.onClick = function() {
605 | if (checkc.value === true) {
606 | checkb.value = false
607 | checka.value = false
608 | }
609 | }
610 |
611 | if (typeof expProps === 'undefined') {
612 | if (winW instanceof Window) {
613 | winW.center()
614 | winW.show()
615 | // winW.size=[268,100];
616 | } else {
617 | winW.layout.layout(true)
618 | }
619 | } else {
620 | try {
621 | var wrongcomps = wrongcomps || []
622 | var selProps = expProps
623 | var i = -1
624 | for (var ic = 0; ic < selProps.length; ic++) {
625 | switch (app.language) {
626 | case Language.ENGLISH:
627 | you.findReplace(selProps[ic], 0, i)
628 | break
629 | case Language.CHINESE:
630 | you.findReplace(selProps[ic], 1, i)
631 | break
632 | case Language.JAPANESE:
633 | you.findReplace(selProps[ic], 2, i)
634 | break
635 | default:
636 | break
637 | }
638 | }
639 | clearOutput()
640 | if (wrongcomps.length !== 0) {
641 | if (loc(tsp.trans) === 'Translate') { writeLn(wrongcomps.length + ' wrong expressions found,which can not be translated.') } else { writeLn('存在' + wrongcomps.length + '个不能被正确翻译的表达式') }
642 | } else {
643 | if (loc(tsp.trans) === 'Translate') { writeLn(selProps.length + ' wrong expressions were translated correctly.') } else { writeLn('存在' + selProps.length + '个已经被正确翻译的表达式') }
644 | }
645 | } catch (err) { }
646 | }
647 |
648 | start.onClick = function() {
649 | var ib
650 | var allId = []
651 | var compid = []
652 | var excludeByName
653 | if (list.selection.index === 1) {
654 | var thisCompnames = []
655 | for (ib = 0; ib < app.project.items.length; ib++) {
656 | if (app.project.item(ib + 1) === app.project.activeItem && app.project.item(ib + 1) instanceof CompItem) {
657 | compid.push(ib + 1)
658 | thisCompnames.push(app.project.item(ib + 1).name)
659 | }
660 | }
661 | excludeByName = compid
662 | }
663 |
664 | if (list.selection.index === 0) {
665 | for (ib = 0; ib < app.project.items.length; ib++) {
666 | allId.push(ib + 1)
667 | }
668 | excludeByName = allId
669 | }
670 | if (list.selection.index === 2) {
671 | var thisCompname = []
672 | var tempId = []
673 | for (ib = 0; ib < app.project.items.length; ib++) {
674 | allId.push(ib + 1)
675 | for (var haha = 0; haha < app.project.selection.length; haha++) {
676 | if (app.project.item(ib + 1) === app.project.selection[haha] && app.project.item(ib + 1) instanceof CompItem) {
677 | tempId.add(ib + 1)
678 | thisCompname.push(app.project.item(ib + 1).name)
679 | }
680 | }
681 | }
682 | excludeByName = tempId
683 | }
684 | var expFilters = []
685 | var result = searchExpression(excludeByName, expFilters)
686 | clearOutput()
687 | if (checkFile.value === true) {
688 | var outString = ''
689 | outString += loc(tsp._1)
690 | outString += '\r----------------------------------------------------------------\r'
691 | outString += loc(tsp._2)
692 | var i
693 | for (i = 0; i < result[3].length; i++) {
694 | outString += loc(tsp._3) + result[3][i].toString() + '\r'
695 | outString += loc(tsp._4) + app.project.item(result[3][i]).name.toString() + '\r'
696 | }
697 | outString += loc(tsp._5)
698 | outString += loc(tsp._6)
699 | if (result[0].length !== 0) {
700 | for (i = 0; i < result[0].length; i++) {
701 | outString += loc(tsp._7) + result[0][i].toString() + '\r'
702 | outString += loc(tsp._8) + app.project.item(result[0][i]).name.toString() + '\r'
703 | var thisComp = app.project.item(result[0][i])
704 | var layerArray = result[1][i].toString()
705 | layerArray = layerArray.split(',')
706 | for (var j = 0; j < layerArray.length; j++) {
707 | var number = parseInt(layerArray[j].toString())
708 | var thisLayer = thisComp.layer(number)
709 | outString += loc(tsp._9) + layerArray[j].toString() + '\r'
710 | outString += loc(tsp._10) + thisLayer.name.toString() + '\r\r'
711 | var propertyArray = result[2][j].toString()
712 | propertyArray = propertyArray.split(',')
713 | for (var x = 0; x < propertyArray.length; x++) { outString += loc(tsp._11) + propertyArray[x].toString() + '\r' }
714 | }
715 | }
716 | }
717 | outFile.writee(outString)
718 | if (confirm(loc(tsp.openFile))) {
719 | outFile = outFile.fsName
720 | outFile = encodeURI(outFile)
721 | outFile = String(outFile)
722 | system.callSystem('explorer ' + decodeURI(outFile))
723 | }
724 | checkFile.value = false
725 | } else {
726 | alert(loc(tsp.complete))
727 | }
728 | }
729 | }
730 |
--------------------------------------------------------------------------------