├── .gitignore ├── com.shspage.csxs.plaincanvas ├── js │ ├── runPaperScript.js │ ├── libs │ │ ├── paperjs-v0.12.17 │ │ │ └── node │ │ │ │ ├── xml.js │ │ │ │ ├── self.js │ │ │ │ ├── canvas.js │ │ │ │ └── extend.js │ │ ├── CSInterface.js │ │ └── jquery-3.7.1.slim.min.js │ ├── undoManager.js │ ├── themeManager.js │ ├── optionManager.js │ └── main.js ├── icons │ ├── iconNormal.png │ └── iconDarkNormal.png ├── .debug ├── CSXS │ └── manifest.xml ├── css │ └── theme.css ├── index.html └── jsx │ └── hostscript.jsx ├── image └── desc_plaincanvas.png ├── scripts ├── image │ ├── desc_cube.png │ ├── desc_juzu2.png │ ├── desc_cylinder.png │ ├── desc_fiddlehead.png │ ├── desc_hatchingline.png │ ├── desc_hatchinglinearc.png │ └── extra_hatchinglinearc_getarcheightvector.png ├── run.js ├── README.md ├── hatchingLine.js ├── juzu.js ├── hatchingLineArc.js ├── cylinder.js ├── cube.js └── fiddlehead.js ├── LICENSE.txt ├── README_ja.md └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | _backup/ 2 | .DS_Store 3 | 4 | -------------------------------------------------------------------------------- /com.shspage.csxs.plaincanvas/js/runPaperScript.js: -------------------------------------------------------------------------------- 1 | var runPaperScript; 2 | -------------------------------------------------------------------------------- /image/desc_plaincanvas.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shspage/plainCanvas/HEAD/image/desc_plaincanvas.png -------------------------------------------------------------------------------- /scripts/image/desc_cube.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shspage/plainCanvas/HEAD/scripts/image/desc_cube.png -------------------------------------------------------------------------------- /scripts/image/desc_juzu2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shspage/plainCanvas/HEAD/scripts/image/desc_juzu2.png -------------------------------------------------------------------------------- /scripts/image/desc_cylinder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shspage/plainCanvas/HEAD/scripts/image/desc_cylinder.png -------------------------------------------------------------------------------- /scripts/image/desc_fiddlehead.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shspage/plainCanvas/HEAD/scripts/image/desc_fiddlehead.png -------------------------------------------------------------------------------- /scripts/image/desc_hatchingline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shspage/plainCanvas/HEAD/scripts/image/desc_hatchingline.png -------------------------------------------------------------------------------- /scripts/image/desc_hatchinglinearc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shspage/plainCanvas/HEAD/scripts/image/desc_hatchinglinearc.png -------------------------------------------------------------------------------- /com.shspage.csxs.plaincanvas/icons/iconNormal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shspage/plainCanvas/HEAD/com.shspage.csxs.plaincanvas/icons/iconNormal.png -------------------------------------------------------------------------------- /com.shspage.csxs.plaincanvas/icons/iconDarkNormal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shspage/plainCanvas/HEAD/com.shspage.csxs.plaincanvas/icons/iconDarkNormal.png -------------------------------------------------------------------------------- /scripts/image/extra_hatchinglinearc_getarcheightvector.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shspage/plainCanvas/HEAD/scripts/image/extra_hatchinglinearc_getarcheightvector.png -------------------------------------------------------------------------------- /com.shspage.csxs.plaincanvas/.debug: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright (c) 2015 Hiroyuki Sato 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the "Software"), 6 | to deal in the Software without restriction, including without limitation 7 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | and/or sell copies of the Software, and to permit persons to whom the Software 9 | is furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /scripts/run.js: -------------------------------------------------------------------------------- 1 | // run example 2 | (function() { 3 | paper.setup("canvas"); 4 | with(paper){ 5 | 6 | //optionManager.noOption(); 7 | var values = { 8 | min_radius : 10, 9 | max_radius : 50 10 | }; 11 | optionManager.setupOptionsUI(["min_radius", "max_radius"], values); 12 | 13 | // draws a circle on random position in random size and random color 14 | runPaperScript = function(){ 15 | if(!optionManager.getOptionsFromUI(values)){ 16 | return; 17 | } 18 | var radius = getRadius(); 19 | 20 | var circle = new Path.Circle({ 21 | center: new Point(window.innerWidth, window.innerHeight) 22 | .multiply(Point.random()), 23 | radius: radius, 24 | fillColor: Color.random() 25 | }); 26 | 27 | undoManager.keep(circle); 28 | } 29 | 30 | function getRadius(){ 31 | return values.min_radius + Math.random() 32 | * (values.max_radius - values.min_radius); 33 | } 34 | } 35 | })(); -------------------------------------------------------------------------------- /scripts/README.md: -------------------------------------------------------------------------------- 1 | These scripts are written to be loaded from plainCanvas add-on. 2 | 3 | ## run.js 4 | An executable script example. Draws a circle on random position in random size and random color. 5 | Some options are available. 6 | 7 | ## juzu.js 8 | Drag or click to draw. Some options are available. 9 | If there is an loaded image, the color of that image near the drawing point will be used for a drawn object. 10 | Otherwise, a random gray color will be used. 11 | ![desc_juzu](https://github.com/shspage/plainCanvas/raw/master/scripts/image/desc_juzu2.png) 12 | 13 | ## hatchingLineArc.js 14 | Drag to draw. Some options are available. 15 | ![desc_hatchingLineArc](https://github.com/shspage/plainCanvas/raw/master/scripts/image/desc_hatchinglinearc.png) 16 | 17 | ## hatchingLine.js 18 | Drag to draw. Some options are available. 19 | ![desc_hatchingLine](https://github.com/shspage/plainCanvas/raw/master/scripts/image/desc_hatchingline.png) 20 | 21 | ## cube.js 22 | Drag or click to draw. Some options are available. 23 | ![desc_cube](https://github.com/shspage/plainCanvas/raw/master/scripts/image/desc_cube.png) 24 | 25 | ## cylinder.js 26 | Drag or click to draw. Some options are available. 27 | ![desc_cylinder](https://github.com/shspage/plainCanvas/raw/master/scripts/image/desc_cylinder.png) 28 | 29 | ## fiddlehead.js 30 | Drag to draw. Some options are available. 31 | ![desc_fiddlehead](https://github.com/shspage/plainCanvas/raw/master/scripts/image/desc_fiddlehead.png) 32 | -------------------------------------------------------------------------------- /com.shspage.csxs.plaincanvas/js/libs/paperjs-v0.12.17/node/xml.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. 3 | * http://paperjs.org/ 4 | * 5 | * Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey 6 | * http://juerglehni.com/ & https://puckey.studio/ 7 | * 8 | * Distributed under the MIT license. See LICENSE file for details. 9 | * 10 | * All rights reserved. 11 | */ 12 | 13 | module.exports = function(self) { 14 | // Define XMLSerializer shim, to emulate browser behavior. 15 | // Effort to bring XMLSerializer to jsdom: 16 | // https://github.com/tmpvar/jsdom/issues/1368 17 | self.XMLSerializer = function XMLSerializer() { 18 | }; 19 | 20 | self.XMLSerializer.prototype = { 21 | serializeToString: function(node) { 22 | if (!node) 23 | return ''; 24 | // Fix a jsdom issue where all SVG tagNames are lowercased: 25 | // https://github.com/tmpvar/jsdom/issues/620 26 | var text = node.outerHTML, 27 | tagNames = ['linearGradient', 'radialGradient', 'clipPath', 28 | 'textPath']; 29 | for (var i = 0, l = tagNames.length; i < l; i++) { 30 | var tagName = tagNames[i]; 31 | text = text.replace( 32 | new RegExp('(<| 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | ./index.html 23 | ./jsx/hostscript.jsx 24 | 25 | 26 | true 27 | 28 | 29 | Panel 30 | plainCanvas 31 | 32 | 33 | 500 34 | 700 35 | 36 | 37 | 100 38 | 500 39 | 40 | 41 | 2000 42 | 2000 43 | 44 | 45 | 46 | 47 | ./icons/iconNormal.png 48 | ./icons/iconDarkNormal.png 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /com.shspage.csxs.plaincanvas/js/libs/paperjs-v0.12.17/node/self.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. 3 | * http://paperjs.org/ 4 | * 5 | * Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey 6 | * http://juerglehni.com/ & https://puckey.studio/ 7 | * 8 | * Distributed under the MIT license. See LICENSE file for details. 9 | * 10 | * All rights reserved. 11 | */ 12 | 13 | // Node.js emulation layer of browser environment, based on jsdom with node- 14 | // canvas integration. 15 | 16 | var path = require('path'); 17 | // Determine the name by which name the module was required (either 'paper', 18 | // 'paper-jsdom' or 'paper-jsdom-canvas'), and use this to determine if error 19 | // exceptions should be thrown or if loading should fail silently. 20 | var parent = module.parent && module.parent.parent, 21 | requireName = parent && path.basename(path.dirname(parent.filename)); 22 | requireName = /^paper/.test(requireName) ? requireName : 'paper'; 23 | 24 | var jsdom, 25 | self; 26 | 27 | try { 28 | jsdom = require('jsdom'); 29 | } catch(e) { 30 | // Check the required module's name to see if it contains jsdom, and only 31 | // complain about its lack if the module requires it. 32 | if (/\bjsdom\b/.test(requireName)) { 33 | throw new Error('Unable to load jsdom module.'); 34 | } 35 | } 36 | 37 | if (jsdom) { 38 | // Create our document and window objects through jsdom. 39 | /* global document:true, window:true */ 40 | var document = new jsdom.JSDOM('', { 41 | // Use the current working directory as the document's origin, so 42 | // requests to local files work correctly with CORS. 43 | url: 'file://' + process.cwd() + '/', 44 | resources: 'usable' 45 | }); 46 | self = document.window; 47 | require('./canvas.js')(self, requireName); 48 | require('./xml.js')(self); 49 | } else { 50 | self = { 51 | navigator: { 52 | userAgent: 'Node.js (' + process.platform + '; U; rv:' + 53 | process.version + ')' 54 | } 55 | }; 56 | } 57 | 58 | module.exports = self; 59 | -------------------------------------------------------------------------------- /com.shspage.csxs.plaincanvas/css/theme.css: -------------------------------------------------------------------------------- 1 | /* 2 | This stylesheet represents CC app styles 3 | Empty classes will be edited at runtime with dynamic app values 4 | */ 5 | html, 6 | body { 7 | margin: 0; 8 | position:relative; 9 | height: 100%; 10 | -webkit-user-select: none; 11 | } 12 | button 13 | { 14 | border:1px solid; 15 | font-family:inherit; 16 | color:inherit; 17 | font-size:inherit; 18 | } 19 | 20 | canvas 21 | { 22 | background-color:#FFFFFF; 23 | } 24 | canvas[resize] { 25 | width: 100%; 26 | height: 100%; 27 | } 28 | 29 | .css_btn_class { 30 | margin-right:4px; 31 | border:1px solid #333333; 32 | background:-webkit-gradient( linear, left top, left bottom, color-stop(5%, #626262), color-stop(100%, #494949) ); 33 | background-color:#626262; 34 | -webkit-box-shadow:inset 1px 1px 0px 0px #6c6c6c; 35 | padding:3px 8px; 36 | text-decoration:none; 37 | display:inline-block; 38 | vertical-align:middle; 39 | }.css_btn_class:hover { 40 | background:-webkit-gradient( linear, left top, left bottom, color-stop(5%, #494949), color-stop(100%, #626262) ); 41 | background-color:#494949; 42 | }.css_btn_class:active { 43 | position:relative; 44 | top:1px; 45 | } 46 | /* This css button was generated by css-button-generator.com */ 47 | 48 | table.options{ 49 | font-size:80%; 50 | color:#000000; 51 | } 52 | input[type="number"] { 53 | width:50px; 54 | } 55 | input[type="file"]{ 56 | color:#000000; 57 | } 58 | label.memo{ 59 | color:#999; 60 | font-size:80%; 61 | } 62 | span.black_text{ 63 | color:#000000; 64 | } 65 | 66 | #div_canvas{ 67 | top: 0px; 68 | position: absolute; 69 | width: 100%; 70 | height: 100%; 71 | } 72 | #div_screen{ 73 | top: 0px; 74 | position: absolute; 75 | width: 100%; 76 | height: 100%; 77 | background-color:#333333; 78 | opacity:0.5; 79 | } 80 | #div_buttons{ 81 | top: 0px; 82 | position: absolute 83 | } 84 | #div_dropzone{ 85 | top: 0px; 86 | position: absolute; 87 | width: 100%; 88 | height: 100%; 89 | display: -webkit-flex; 90 | display: flex; 91 | -webkit-flex-wrap: wrap; 92 | flex-wrap: wrap; 93 | align-items: center; 94 | justify-content: center; 95 | } 96 | #span_dropzone_text{ 97 | font: 20pt bold; 98 | color: #fff; 99 | } 100 | 101 | .hostFont{} 102 | .hostBgd{} 103 | .hostElt{} 104 | -------------------------------------------------------------------------------- /scripts/hatchingLine.js: -------------------------------------------------------------------------------- 1 | // hatchingLine 2 | // for plainCanvas v.1.1.2 or later 3 | (function() { 4 | paper.setup("canvas"); 5 | with(paper){ 6 | var tool = new Tool(); 7 | 8 | var lastPoint; 9 | var preLastPoint; 10 | var gr; 11 | var opts = { 12 | lineWidth : 0.5, 13 | hatchWidth : 12, 14 | interval : 2, 15 | angle_multiplier : 4, 16 | ok : 0 17 | } 18 | // -------------------------- 19 | optionManager.setupOptionsUI(["lineWidth","hatchWidth","interval","angle_multiplier"], opts); 20 | // -------------------------- 21 | tool.onMouseDown = function(event){ 22 | opts.ok = optionManager.getOptionsFromUI(opts); 23 | if(opts.ok){ 24 | opts.hatchWidth /= 2; 25 | preLastPoint = null; 26 | lastPoint = event.point; 27 | gr = new Group(); 28 | } 29 | } 30 | // -------------------------- 31 | tool.onMouseDrag = function(event) { 32 | if(opts.ok == 0) return; 33 | if(lastPoint.getDistance(event.point) < opts.interval) return; 34 | 35 | var lp = preLastPoint ? preLastPoint : lastPoint; 36 | var path = make_a_path(opts.lineWidth, null); 37 | gr.addChild(path); 38 | var w = opts.hatchWidth; 39 | var y = (Math.random() -0.5) * w * opts.angle_multiplier; 40 | path.moveTo(new Point(w, y)); 41 | path.lineTo(new Point(-w, -y)); 42 | path.rotate(event.point.subtract(lp).getAngle() + 90); 43 | path.translate(event.point); 44 | 45 | preLastPoint = lastPoint; 46 | lastPoint = event.point; 47 | } 48 | // -------------------------- 49 | tool.onMouseUp = function(event){ 50 | if(opts.ok && gr){ 51 | if(gr.children.length < 1){ 52 | gr.remove(); 53 | } else { 54 | undoManager.keep(gr); 55 | } 56 | } 57 | } 58 | // ---------------------------------------------- 59 | function make_a_path(w, c){ 60 | var path = new Path({ 61 | closed: false, 62 | strokeWidth: w, 63 | strokeColor: new Color(0), 64 | fillColor: c 65 | }); 66 | return path; 67 | } 68 | } // with(paper){ 69 | })(); 70 | -------------------------------------------------------------------------------- /com.shspage.csxs.plaincanvas/js/libs/paperjs-v0.12.17/node/canvas.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. 3 | * http://paperjs.org/ 4 | * 5 | * Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey 6 | * http://juerglehni.com/ & https://puckey.studio/ 7 | * 8 | * Distributed under the MIT license. See LICENSE file for details. 9 | * 10 | * All rights reserved. 11 | */ 12 | 13 | // Add some useful extensions to HTMLCanvasElement: 14 | // - HTMLCanvasElement#type, so we can switch to a PDF canvas 15 | // - Various Node-Canvas methods, routed through from HTMLCanvasElement: 16 | // toBuffer, pngStream, createPNGStream, jpegStream, createJPEGStream 17 | 18 | module.exports = function(self, requireName) { 19 | var Canvas; 20 | try { 21 | Canvas = require('canvas').Canvas; 22 | } catch(error) { 23 | // Remove `self.window`, so we still have the global `self` reference, 24 | // but no `window` object: 25 | // - On the browser, this corresponds to a worker context. 26 | // - On Node.js, it basically means the canvas is missing or not working 27 | // which can be treated the same way. 28 | delete self.window; 29 | // Check the required module's name to see if it contains canvas, and 30 | // only complain about its lack if the module requires it. 31 | if (/\bcanvas\b/.test(requireName)) { 32 | throw new Error('Unable to load canvas module.'); 33 | } 34 | return; 35 | } 36 | 37 | var HTMLCanvasElement = self.HTMLCanvasElement, 38 | idlUtils = require('jsdom/lib/jsdom/living/generated/utils'); 39 | 40 | // Add fake HTMLCanvasElement#type property: 41 | Object.defineProperty(HTMLCanvasElement.prototype, 'type', { 42 | get: function() { 43 | var canvas = idlUtils.implForWrapper(this)._canvas; 44 | return canvas && canvas.type || 'image'; 45 | }, 46 | 47 | set: function(type) { 48 | // Allow replacement of internal node-canvas, so we can switch to a 49 | // PDF canvas. 50 | var impl = idlUtils.implForWrapper(this), 51 | size = impl._canvas || impl; 52 | impl._canvas = new Canvas(size.width, size.height, type); 53 | impl._context = null; 54 | } 55 | }); 56 | 57 | // Extend HTMLCanvasElement with useful methods from the underlying Canvas: 58 | var methods = ['toBuffer', 'pngStream', 'createPNGStream', 'jpegStream', 59 | 'createJPEGStream']; 60 | methods.forEach(function(key) { 61 | HTMLCanvasElement.prototype[key] = function() { 62 | var canvas = idlUtils.implForWrapper(this)._canvas; 63 | return canvas[key].apply(canvas, arguments); 64 | }; 65 | }); 66 | }; 67 | -------------------------------------------------------------------------------- /scripts/juzu.js: -------------------------------------------------------------------------------- 1 | // juzu 2 | // for plainCanvas v.1.1.2 or later 3 | (function() { 4 | paper.setup("canvas"); 5 | with(paper){ 6 | var tool = new Tool(); 7 | 8 | var minRadius, maxRadius, margin, grayRange, separation; 9 | var lastPnt, prevRadius, nextRadius, interval, gr; 10 | // -------------------------- 11 | function setupOptions(){ 12 | minRadius = 6; 13 | maxRadius = 12; 14 | separation = 0; 15 | 16 | grayRange = 8; // (0-10) : 0 = 50% only 17 | 18 | margin = minRadius / 2; 19 | maxRadius -= minRadius; 20 | 21 | optionManager.setupOptionsUI(["min radius", "max radius", "separation (px)", "gray range (0-10)"], 22 | [minRadius, maxRadius + minRadius, separation, grayRange]); 23 | } 24 | setupOptions(); 25 | 26 | // -------------------------- 27 | function getOptions(){ 28 | var opt = optionManager.getOptionsFromUI(); 29 | 30 | if(opt != null){ 31 | minRadius = opt[0]; 32 | maxRadius = opt[1] - opt[0]; 33 | margin = minRadius / 2; 34 | separation = opt[2]; 35 | grayRange = Math.min(10, Math.max(0, opt[3])) / 10; 36 | } 37 | } 38 | // -------------------------- 39 | tool.onMouseDown = function(event){ 40 | getOptions(); 41 | gr = new Group(); 42 | lastPnt = event.point; 43 | drawCircle(getRadius()); 44 | } 45 | // -------------------------- 46 | tool.onMouseDrag = function(event) { 47 | if(lastPnt.getDistance(event.point) < interval) return; 48 | var v = event.point.subtract(lastPnt).normalize(); 49 | lastPnt = lastPnt.add(v.multiply(interval + margin)); 50 | drawCircle(nextRadius); 51 | } 52 | // -------------------------- 53 | tool.onMouseUp = function(event){ 54 | if(gr){ 55 | if(gr.children.length < 1){ 56 | gr.remove(); 57 | } else { 58 | if(undoManager) undoManager.keep(gr); 59 | } 60 | gr = null; 61 | } 62 | lastPnt = null; 63 | } 64 | // -------------------------- 65 | function drawCircle(r){ 66 | var c = new Path.Circle(lastPnt, r); 67 | c.strokeColor = null; 68 | 69 | var raster = project.activeLayer.data.raster; 70 | if(raster){ 71 | c.fillColor = raster.getAverageColor(c); 72 | } else { 73 | var color_value = Math.min(1, Math.max(0, (Math.random() - 0.5) * grayRange + 0.5)); 74 | 75 | c.fillColor = new Color(color_value); 76 | } 77 | 78 | //c.fillColor = new Color(0); // use opacity 79 | //c.opacity = color_value; 80 | 81 | gr.addChild( c ); 82 | 83 | prevRadius = r; 84 | nextRadius = getRadius(); 85 | var sep = separation; 86 | interval = nextRadius + prevRadius - margin + sep; 87 | if(interval <= 0) interval = 1; 88 | } 89 | // --------------------------- 90 | function getRadius(){ 91 | return Math.random() * maxRadius + minRadius; 92 | } 93 | } // with(paper){ 94 | })(); 95 | -------------------------------------------------------------------------------- /scripts/hatchingLineArc.js: -------------------------------------------------------------------------------- 1 | // hatchingLineArc 2 | // for plainCanvas v.1.1.2 or later 3 | (function() { 4 | paper.setup("canvas"); 5 | with(paper){ 6 | var tool = new Tool(); 7 | 8 | var lastPoint; 9 | var preLastPoint; 10 | var gr; 11 | var opts = { 12 | lineWidth : 0.5, 13 | hatchWidth : 16, 14 | interval : 3, 15 | angle_multiplier : 4, 16 | ok : 0 17 | } 18 | // -------------------------- 19 | optionManager.setupOptionsUI(["lineWidth","hatchWidth","interval","angle_multiplier"], opts); 20 | // -------------------------- 21 | tool.onMouseDown = function(event){ 22 | opts.ok = optionManager.getOptionsFromUI(opts); 23 | if(opts.ok){ 24 | if(opts.hatchWidth == 0){ 25 | alert("hatchWidth must be not 0"); 26 | opts.ok = 0; 27 | } else { 28 | opts.hatchWidth /= 2; 29 | preLastPoint = null; 30 | lastPoint = event.point; 31 | gr = new Group(); 32 | } 33 | } 34 | } 35 | // -------------------------- 36 | tool.onMouseDrag = function(event) { 37 | if(opts.ok == 0) return; 38 | if(lastPoint.getDistance(event.point) < opts.interval) return; 39 | 40 | var path = make_a_path(opts.lineWidth, null); 41 | gr.addChild(path); 42 | 43 | var w = opts.hatchWidth; 44 | var lp = preLastPoint ? preLastPoint : lastPoint; 45 | 46 | var y = (Math.random() -0.5) * w * opts.angle_multiplier; 47 | path.moveTo(new Point(-w, -y)); 48 | path.arcTo(getArcHeightVector(w, y), 49 | new Point(w, y)); 50 | path.rotate(event.point.subtract(lp).getAngle() + 90); 51 | path.translate(event.point); 52 | 53 | preLastPoint = lastPoint; 54 | lastPoint = event.point; 55 | } 56 | // -------------------------- 57 | tool.onMouseUp = function(event){ 58 | if(opts.ok && gr){ 59 | if(gr.children.length < 1){ 60 | gr.remove(); 61 | } else { 62 | undoManager.keep(gr); 63 | } 64 | } 65 | } 66 | // ---------------------------------------------- 67 | // about variables, refer to ./image/extra_hatchinglinearc_getarcheightvector.png 68 | function getArcHeightVector(w, y){ 69 | // must (w != 0) 70 | var d = Math.sqrt(w*w+y*y); 71 | var sin_t = y / d; 72 | var t = Math.asin(sin_t); 73 | var tc = Math.PI / 2 - t; 74 | var sin_tc = Math.sin(tc); 75 | var r = d / sin_tc; 76 | var r1 = Math.abs(r * sin_t); 77 | 78 | // adjusts arc height not to be too high 79 | r1 = Math.max(r * 0.75, r1); 80 | var v = new Point(Math.cos(tc), sin_tc).normalize(r - r1); 81 | return v; 82 | } 83 | // ---------------------------------------------- 84 | function make_a_path(w, c){ 85 | var path = new Path({ 86 | closed: false, 87 | strokeWidth: w, 88 | strokeColor: new Color(0), 89 | fillColor: c 90 | }); 91 | return path; 92 | } 93 | } // with(paper){ 94 | })(); 95 | -------------------------------------------------------------------------------- /com.shspage.csxs.plaincanvas/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 |
14 | 16 |
17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -- 33 | 34 |
35 | 47 |
48 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /scripts/cylinder.js: -------------------------------------------------------------------------------- 1 | // cylinder 2 | // for plainCanvas v.1.1.2 or later 3 | (function() { 4 | paper.setup("canvas"); 5 | with(paper){ 6 | var tool = new Tool(); 7 | 8 | var v0 = new Point(0, 0); 9 | var v1 = new Point(1, 0); 10 | 11 | var grs; // groups 12 | 13 | // ---------------------------------------------- 14 | var values = { 15 | diameter: 10, 16 | height: 30, 17 | interval: 20, 18 | lineWidth: 1.0, 19 | jitter: 18, 20 | ok: 0 21 | }; 22 | optionManager.setupOptionsUI(["diameter", "height", "interval", "lineWidth", "jitter"], values); 23 | 24 | // ---------------------------------------------- 25 | tool.onMouseDown = function(event){ 26 | values.ok = optionManager.getOptionsFromUI(values); 27 | tool.minDistance = values.interval; 28 | grs = new Group(); 29 | drawCylinder(event.point); 30 | } 31 | // ---------------------------------------------- 32 | tool.onMouseDrag = function(event){ 33 | if(values.ok == 0) return; 34 | 35 | drawCylinder(event.point.add( v1.rotate(Math.random() * 360, v0 ) 36 | .multiply(Math.random() * values.jitter))); 37 | } 38 | // ---------------------------------------------- 39 | tool.onMouseUp = function(){ 40 | if(values.ok == 0) return; 41 | 42 | if(grs){ 43 | if(grs.children.length < 1){ 44 | grs.remove(); 45 | } else { 46 | undoManager.keep(grs); 47 | } 48 | grs = null; 49 | } 50 | } 51 | // ---------------------------------------------- 52 | function drawCylinder(pnt){ 53 | var d = values.diameter; 54 | var r = values.diameter / 2; // radius 55 | var h = values.height; 56 | var w = values.lineWidth; 57 | var w2 = w / 2; 58 | 59 | var rad_v = (Math.random() * 0.8 + 0.1) * Math.PI / 2; 60 | var sn = Math.sin(rad_v); 61 | var cs = Math.cos(rad_v); 62 | 63 | var t = Math.random() * 360; 64 | 65 | h *= cs / sn; 66 | 67 | var gr = new Group(); 68 | 69 | var path = make_a_path(w, new Color(1)); 70 | path.moveTo(v0); 71 | path.arcTo( new Point(r, r), new Point(d, 0)); 72 | path.lineTo(new Point(d, -h)); 73 | path.arcTo( new Point(r, -h-r), new Point(0, -h)); 74 | path.closePath(); 75 | gr.addChild(path); 76 | 77 | var path1 = make_a_path(w2, new Color(1)); 78 | path1.moveTo(v0); 79 | path1.arcTo(new Point(r, -r), new Point(d, 0)); 80 | gr.addChild(path1); 81 | 82 | gr.translate(-r, h / 2); 83 | gr.scale(1, sn); 84 | gr.rotate(t); 85 | gr.translate(pnt); 86 | 87 | if( ! grs) grs = new Group(); 88 | grs.addChild(gr); 89 | } 90 | // ---------------------------------------------- 91 | function make_a_path(w, c){ 92 | var path = new Path({ 93 | closed: false, 94 | strokeWidth: w, 95 | strokeColor: new Color(0), 96 | fillColor: c 97 | }); 98 | return path; 99 | } 100 | } // with(paper){ 101 | })(); 102 | -------------------------------------------------------------------------------- /com.shspage.csxs.plaincanvas/js/undoManager.js: -------------------------------------------------------------------------------- 1 | /* 2 | undoManager 3 | v.1.0 4 | 5 | undoManager.keep(item); 6 | ... regist an item as a target of undo/redo 7 | 8 | undoManager.undo(); 9 | ... perform undo 10 | (it just makes the last item kept invisible) 11 | 12 | undoManager.redo(); 13 | ... preform redo 14 | (it makes the last item undoed visible) 15 | 16 | undoManager.clearHistory(); 17 | ... clears undo/redo storage. 18 | (also removes invisible items in the history) 19 | 20 | 21 | undoManager.keep([item, item, item...], "dd"); 22 | ... regist items as targets of undo/redo 23 | 24 | undoManager.keep(item, "m"); 25 | ... regist a translation of an item as a target of undo/redo 26 | */ 27 | 28 | var undoManager = (function() { 29 | 'use strict'; 30 | 31 | var _UNDO_LIMIT = 200; 32 | 33 | var _MODE_DRAW = "d"; 34 | var _MODE_DRAW_ITEMS = "dd"; 35 | var _MODE_MOVE = "m"; 36 | 37 | 38 | var _undoRedoSystemArray = function( name ){ 39 | this.name = name; 40 | this.r = []; 41 | }; 42 | _undoRedoSystemArray.prototype = { 43 | clear : function(limit, remove_visible_item){ 44 | if(!limit) limit = 0; 45 | if(!remove_visible_item) remove_visible_item = false; 46 | 47 | var arr; 48 | var typ; 49 | var itm; 50 | 51 | while(this.r.length > limit){ 52 | arr = this.r.shift(); 53 | typ = arr[0]; 54 | itm = arr[1]; 55 | if(typ == _MODE_DRAW_ITEMS){ 56 | if(itm){ 57 | for(var i = itm.length - 1; i >= 0; i--){ 58 | if(itm[i] && (remove_visible_item || !itm[i].visible)){ 59 | itm[i].remove(); 60 | } 61 | } 62 | } 63 | } else { 64 | if(itm && (remove_visible_item || !itm.visible)){ 65 | itm.remove(); 66 | } 67 | } 68 | } 69 | }, 70 | 71 | store : function(arr){ 72 | this.r.push(arr); 73 | if(_UNDO_LIMIT > 0 && this.name == "undo"){ 74 | this.clear(_UNDO_LIMIT, true); 75 | } 76 | } 77 | }; 78 | 79 | var undoArray = new _undoRedoSystemArray("undo"); 80 | var redoArray = new _undoRedoSystemArray("redo"); 81 | 82 | var _perform = function( arr, is_undo ){ 83 | var itm = arr[1]; 84 | if(arr[0] == _MODE_DRAW){ 85 | if(itm){ 86 | itm.visible = ! itm.visible; 87 | } 88 | 89 | } else if(arr[0] == _MODE_DRAW_ITEMS){ 90 | // itm = [item, item,... 91 | for(var i = itm.length - 1; i >= 0; i--){ 92 | if(itm[i]){ 93 | itm[i].visible = ! itm[i].visible; 94 | } 95 | } 96 | 97 | } else if(arr[0] == _MODE_MOVE){ 98 | itm.translate(is_undo ? arr[2] : arr[3]); 99 | } 100 | } 101 | 102 | var undo = function(){ 103 | if(undoArray.r.length > 0){ 104 | var arr = undoArray.r.pop(); 105 | _perform( arr, true ); 106 | redoArray.store( arr ); 107 | } 108 | } 109 | 110 | var redo = function(){ 111 | if(redoArray.r.length > 0){ 112 | var arr = redoArray.r.pop(); 113 | _perform( arr, false ); 114 | undoArray.store( arr ); 115 | } 116 | } 117 | 118 | var keep = function(item, mode){ 119 | if(!mode) mode = _MODE_DRAW; 120 | undoArray.store([mode, item]); 121 | redoArray.clear(); 122 | } 123 | 124 | var clearHistory = function(){ 125 | undoArray.clear(); 126 | redoArray.clear(); 127 | } 128 | 129 | return { 130 | undo : undo, 131 | redo : redo, 132 | keep : keep, 133 | clearHistory : clearHistory 134 | } 135 | })(); 136 | -------------------------------------------------------------------------------- /scripts/cube.js: -------------------------------------------------------------------------------- 1 | // cube 2 | // for plainCanvas v.1.1.2 or later 3 | (function() { 4 | paper.setup("canvas"); 5 | with(paper){ 6 | var tool = new Tool(); 7 | 8 | var v0 = new Point(0, 0); 9 | var v1 = new Point(1, 0); 10 | 11 | var grs; // group 12 | 13 | // ---------------------------------------------- 14 | var values = { 15 | cubeSize: 10, 16 | interval: 10, 17 | jitter: 10, 18 | ok : 1, 19 | }; 20 | 21 | optionManager.setupOptionsUI(["cubeSize", "interval", "jitter"], values); 22 | 23 | // ---------------------------------------------- 24 | tool.onMouseDown = function(event){ 25 | values.ok = optionManager.getOptionsFromUI(values); 26 | 27 | if(values.ok){ 28 | tool.minDistance = values.interval; 29 | grs = new Group(); 30 | drawCube(event.point); 31 | } 32 | } 33 | // ---------------------------------------------- 34 | tool.onMouseDrag = function(event){ 35 | if(values.ok){ 36 | drawCube(event.point.add( v1.rotate(Math.random() * 360, v0 ) 37 | .multiply(Math.random() * values.jitter))); 38 | } 39 | } 40 | // ---------------------------------------------- 41 | tool.onMouseUp = function(){ 42 | if(values.ok){ 43 | if(grs){ 44 | if(grs.children.length < 1){ 45 | grs.remove(); 46 | } else { 47 | undoManager.keep(grs); 48 | } 49 | grs = null; 50 | } 51 | } 52 | } 53 | // ---------------------------------------------- 54 | function points2segments(points){ 55 | for(var i = 0; i < points.length; i++){ 56 | points[i] = new Segment(points[i]); 57 | } 58 | return points; 59 | } 60 | // ---------------------------------------------- 61 | function drawCube(pnt){ 62 | var radian_v = (Math.random() * 0.7 + 0.15) * Math.PI / 2; 63 | var angle_h = (Math.random() - 0.5) * (90 * 0.85); 64 | var radius = values.cubeSize / Math.sqrt(2); 65 | var v = new Point(1, 0); 66 | var v2 = v.rotate(angle_h).multiply(radius); 67 | var sn = Math.sin(radian_v); 68 | var p_sn = new Point(1, sn); 69 | 70 | var face_top = [v2.multiply(p_sn), 71 | v2.rotate(90).multiply(p_sn), 72 | v2.rotate(180).multiply(p_sn), 73 | v2.rotate(-90).multiply(p_sn)]; 74 | 75 | var cs = values.cubeSize * Math.cos(radian_v); 76 | var p_cs = new Point(0, -cs); 77 | 78 | var face_side = [v2.rotate(180).multiply(p_sn).add(p_cs), 79 | v2.rotate(-90).multiply(p_sn).add(p_cs), 80 | v2.multiply(p_sn).add(p_cs)]; 81 | 82 | var path = make_a_path(1, new Color(1)); 83 | 84 | path.closed = true; 85 | path.strokeJoin = 'round'; 86 | 87 | var gr = new Group(); 88 | gr.insertChild(0, path); 89 | path.segments = points2segments( 90 | [face_top[0], face_top[1], face_top[2], 91 | face_side[0], face_side[1], face_side[2]]); 92 | 93 | 94 | path = make_a_path(0.5, null); 95 | gr.addChild(path); 96 | path.segments = points2segments([face_top[0], face_top[3]]); 97 | 98 | path = make_a_path(0.5, null); 99 | gr.addChild(path); 100 | path.segments = points2segments([face_top[2], face_top[3]]); 101 | 102 | path = make_a_path(0.5, null); 103 | gr.addChild(path); 104 | path.segments = points2segments([face_side[1], face_top[3]]); 105 | 106 | gr.position = gr.position.add(new Point(0, cs / 2)); 107 | gr.rotate( Math.random() * 360 ); 108 | gr.position = gr.position.add(pnt); 109 | if( ! grs) grs = new Group(); 110 | grs.addChild(gr); 111 | } 112 | // ---------------------------------------------- 113 | function make_a_path(w, c){ 114 | var path = new Path({ 115 | closed: false, 116 | strokeWidth: w, 117 | strokeColor: new Color(0), 118 | fillColor: c 119 | }); 120 | return path; 121 | } 122 | } // with(paper){ 123 | })(); 124 | -------------------------------------------------------------------------------- /com.shspage.csxs.plaincanvas/js/themeManager.js: -------------------------------------------------------------------------------- 1 | /*jslint vars: true, plusplus: true, devel: true, nomen: true, regexp: true, indent: 4, maxerr: 50 */ 2 | /*global window, document, CSInterface*/ 3 | 4 | 5 | /* 6 | 7 | Responsible for overwriting CSS at runtime according to CC app 8 | settings as defined by the end user. 9 | 10 | */ 11 | 12 | var themeManager = (function () { 13 | 'use strict'; 14 | 15 | /** 16 | * Convert the Color object to string in hexadecimal format; 17 | */ 18 | function toHex(color, delta) { 19 | 20 | function computeValue(value, delta) { 21 | var computedValue = !isNaN(delta) ? value + delta : value; 22 | if (computedValue < 0) { 23 | computedValue = 0; 24 | } else if (computedValue > 255) { 25 | computedValue = 255; 26 | } 27 | 28 | computedValue = Math.floor(computedValue); 29 | 30 | computedValue = computedValue.toString(16); 31 | return computedValue.length === 1 ? "0" + computedValue : computedValue; 32 | } 33 | 34 | var hex = ""; 35 | if (color) { 36 | hex = computeValue(color.red, delta) + computeValue(color.green, delta) + computeValue(color.blue, delta); 37 | } 38 | return hex; 39 | } 40 | 41 | 42 | function reverseColor(color, delta) { 43 | return toHex({ 44 | red: Math.abs(255 - color.red), 45 | green: Math.abs(255 - color.green), 46 | blue: Math.abs(255 - color.blue) 47 | }, 48 | delta); 49 | } 50 | 51 | 52 | function addRule(stylesheetId, selector, rule) { 53 | var stylesheet = document.getElementById(stylesheetId); 54 | 55 | if (stylesheet) { 56 | stylesheet = stylesheet.sheet; 57 | if (stylesheet.addRule) { 58 | stylesheet.addRule(selector, rule); 59 | } else if (stylesheet.insertRule) { 60 | stylesheet.insertRule(selector + ' { ' + rule + ' }', stylesheet.cssRules.length); 61 | } 62 | } 63 | } 64 | 65 | 66 | 67 | /** 68 | * Update the theme with the AppSkinInfo retrieved from the host product. 69 | */ 70 | function updateThemeWithAppSkinInfo(appSkinInfo) { 71 | 72 | var panelBgColor = appSkinInfo.panelBackgroundColor.color; 73 | var bgdColor = toHex(panelBgColor); 74 | 75 | var darkBgdColor = toHex(panelBgColor, 20); 76 | 77 | var fontColor = "F0F0F0"; 78 | if (panelBgColor.red > 122) { 79 | fontColor = "000000"; 80 | } 81 | var lightBgdColor = toHex(panelBgColor, -100); 82 | 83 | var styleId = "hostStyle"; 84 | 85 | addRule(styleId, ".hostElt", "background-color:" + "#" + bgdColor); 86 | addRule(styleId, ".hostElt", "font-size:" + appSkinInfo.baseFontSize + "px;"); 87 | addRule(styleId, ".hostElt", "font-family:" + appSkinInfo.baseFontFamily); 88 | addRule(styleId, ".hostElt", "color:" + "#" + fontColor); 89 | 90 | addRule(styleId, ".hostBgd", "background-color:" + "#" + bgdColor); 91 | addRule(styleId, ".hostBgdDark", "background-color: " + "#" + darkBgdColor); 92 | addRule(styleId, ".hostBgdLight", "background-color: " + "#" + lightBgdColor); 93 | addRule(styleId, ".hostFontSize", "font-size:" + appSkinInfo.baseFontSize + "px;"); 94 | addRule(styleId, ".hostFontFamily", "font-family:" + appSkinInfo.baseFontFamily); 95 | addRule(styleId, ".hostFontColor", "color:" + "#" + fontColor); 96 | 97 | addRule(styleId, ".hostFont", "font-size:" + appSkinInfo.baseFontSize + "px;"); 98 | addRule(styleId, ".hostFont", "font-family:" + appSkinInfo.baseFontFamily); 99 | addRule(styleId, ".hostFont", "color:" + "#" + fontColor); 100 | 101 | addRule(styleId, ".hostButton", "background-color:" + "#" + darkBgdColor); 102 | addRule(styleId, ".hostButton:hover", "background-color:" + "#" + bgdColor); 103 | addRule(styleId, ".hostButton:active", "background-color:" + "#" + darkBgdColor); 104 | addRule(styleId, ".hostButton", "border-color: " + "#" + lightBgdColor); 105 | } 106 | 107 | 108 | function onAppThemeColorChanged(event) { 109 | var skinInfo = JSON.parse(window.__adobe_cep__.getHostEnvironment()).appSkinInfo; 110 | updateThemeWithAppSkinInfo(skinInfo); 111 | } 112 | 113 | 114 | function init() { 115 | 116 | var csInterface = new CSInterface(); 117 | 118 | updateThemeWithAppSkinInfo(csInterface.hostEnvironment.appSkinInfo); 119 | 120 | csInterface.addEventListener(CSInterface.THEME_COLOR_CHANGED_EVENT, onAppThemeColorChanged); 121 | } 122 | 123 | return { 124 | init: init 125 | }; 126 | 127 | }()); 128 | -------------------------------------------------------------------------------- /com.shspage.csxs.plaincanvas/js/optionManager.js: -------------------------------------------------------------------------------- 1 | /* 2 | optionManager 3 | v.1.1 4 | 5 | // ---------------------- 6 | // functions for UI and optional values 7 | // ---------------------- 8 | setupOptionsUI(titles, options) 9 | ... titles: titles for input text boxes, an array of string. max = 5 10 | options: an object which has properties with a name of each title. 11 | each value must be a number. 12 | ex. setupOptionsUI(["item1", "item2", "item3"], options) 13 | -> 4th and 5th text boxes are hidden. 14 | -> options = { "item1":0, "item2":1, ... } 15 | ... sets up option UI. maximum number of text boxes is 5. 16 | ... "options" can be an array of number. if you want to use a title 17 | different from the property name of "options", use this style. 18 | 19 | getOptionsFromUI(options) 20 | ... options: an object 21 | ... gets values from option UI, and set as properties of options 22 | with a name of the title of the each input text box. 23 | if there's a invalid value, shows an alert and return 0. 24 | otherwise return 1. 25 | ... if "options" is undefined, returns an array of values. 26 | ( on error, returns null ) 27 | 28 | resetOptions() 29 | ... resets option UI to default status 30 | 31 | noOption() 32 | ... hides the UIs for option 33 | // ---------------------- 34 | */ 35 | 36 | var optionManager = (function() { 37 | 'use strict'; 38 | 39 | var OPTION_COUNT = 5; 40 | 41 | // ---------------------- 42 | // functions for UI and optional values 43 | // ---------------------- 44 | var setupOptionsUI = function(titles, options) { 45 | if(options instanceof Array){ 46 | // obsolete style 47 | // ex. titles:["item1","item2","item3"], options:[1,2,3] 48 | _setupOptionsUI_main(titles, options); 49 | return; 50 | } 51 | 52 | var values = []; 53 | for(var i = 0; i < titles.length; i++){ 54 | values.push(options[titles[i]]); 55 | } 56 | _setupOptionsUI_main(titles, values); 57 | } 58 | 59 | var _setupOptionsUI_main = function(titles, values) { 60 | if(!titles || titles.length < 1){ 61 | document.getElementById("div_no_option").style.display = "block"; 62 | document.getElementById("div_options").style.display = "none"; 63 | } else { 64 | document.getElementById("div_no_option").style.display = "none"; 65 | for(var i = 1; i <= OPTION_COUNT; i++){ 66 | if(i > titles.length){ 67 | document.getElementById("td" + i).innerText = ""; 68 | document.getElementById("input" + i).style.display = "none"; 69 | } else { 70 | document.getElementById("td" + i).innerText = titles[i-1]; 71 | document.getElementById("input" + i).value = values[i-1]; 72 | } 73 | } 74 | } 75 | } 76 | // ---- 77 | var getOptionsFromUI = function(options) { 78 | if(!options){ 79 | return _getOptionsFromUI_returnArray(); 80 | } 81 | 82 | for(var i = 1; i <= OPTION_COUNT; i++){ 83 | try{ 84 | var title = document.getElementById("td" + i).innerText; 85 | if(title != ""){ 86 | var v = document.getElementById("input" + i).value; 87 | v = eval(v) - 0; 88 | options[title] = v; 89 | } 90 | } catch(e){ 91 | alert(e); 92 | return 0; 93 | } 94 | } 95 | return 1; 96 | } 97 | // ---- 98 | // reset the status of the UIs for option 99 | var resetOptions = function() { 100 | document.getElementById("table_options").style.display = "block"; 101 | for(var i = 1; i <= OPTION_COUNT; i++){ 102 | document.getElementById("td" + i).innerText = "item" + i; 103 | document.getElementById("input" + i).style.display = "block"; 104 | document.getElementById("input" + i).value = 0; 105 | } 106 | 107 | document.getElementById("div_no_option").style.display = "none"; 108 | } 109 | 110 | // ---- 111 | // hides the UIs for option 112 | var noOption = function(){ 113 | document.getElementById("table_options").style.display = "none"; 114 | document.getElementById("div_no_option").style.display = "block"; 115 | } 116 | 117 | // ------------------------------------ 118 | // obsolete 119 | var _getOptionsFromUI_returnArray = function() { 120 | var optionalValues = []; 121 | 122 | for(var i = 1; i <= OPTION_COUNT; i++){ 123 | try{ 124 | var v = document.getElementById("input" + i).value; 125 | v = eval(v) - 0; 126 | optionalValues.push(v); 127 | } catch(e){ 128 | alert(e); 129 | return null; 130 | } 131 | } 132 | 133 | return optionalValues; 134 | } 135 | 136 | 137 | // ------------------------------------ 138 | return { 139 | setupOptionsUI : setupOptionsUI, 140 | getOptionsFromUI : getOptionsFromUI, 141 | resetOptions : resetOptions, 142 | noOption : noOption 143 | } 144 | })(); 145 | -------------------------------------------------------------------------------- /README_ja.md: -------------------------------------------------------------------------------- 1 | # plainCanvas 2 | 3 |  Adobe Illustrator (CC 2014-) 用の add-on です。以下のことが可能です。 4 | 5 | * [paper.js](http://paperjs.org) 用に書かれた JavaScript ファイルを読み込んで実行する。 6 | (初期状態では、ドラッグで線を描くツールが使用できます。) 7 | * add-on パネル上に作成した画像を、アートボードに書き出す。 8 | * アートボード上のパスを、add-on パネル上に取り込む。 9 | 10 | ![image of the panel](https://github.com/shspage/plainCanvas/raw/master/image/desc_plaincanvas.png "image of the panel") 11 | 12 | ### 導入方法 13 |  諸々のスクリプトを読み込んで実行するという性格上、デバッグ機能を利用することを想定しています。このため、導入には通常のadd-onと異なる手順が必要です。 14 | 15 | 1. [CEP 10 HTML Extension Cookbook](https://github.com/Adobe-CEP/CEP-Resources/blob/master/CEP_10.x/Documentation/CEP%2010.0%20HTML%20Extension%20Cookbook.md#cep-10-html-extension-cookbook) の [Debugging Unsigned Extensions](https://github.com/Adobe-CEP/CEP-Resources/blob/master/CEP_10.x/Documentation/CEP%2010.0%20HTML%20Extension%20Cookbook.md#debugging-unsigned-extensions) にしたがって、debug mode flagを設定してください。(CSXS.10とありますが、数字はイラレのバージョンにより異なります。例えば Ai 2024(28.2)では CSXS.11 です。) 16 | 2. [CEP 10 HTML Extension Cookbook](https://github.com/Adobe-CEP/CEP-Resources/blob/master/CEP_10.x/Documentation/CEP%2010.0%20HTML%20Extension%20Cookbook.md#cep-10-html-extension-cookbook) の [Extension Folders](https://github.com/Adobe-CEP/CEP-Resources/blob/master/CEP_10.x/Documentation/CEP%2010.0%20HTML%20Extension%20Cookbook.md#extension-folders) にしたがって、com.shspage.csxs.plaincanvas フォルダを、extensions フォルダに置いてください。 17 | 3. Illustrator を実行して、メニューの ウィンドウ -> エクステンション の中にある plainCanvas を選んでください。 18 | 19 | ### パネル上のボタンについて 20 | * __in__ : Illustratorで選択されているパスが、パネル上に取り込まれます。 21 | * __out__ : パネル上のパスが、アートボードに書き出されます。 22 | * __run__ : 実行機能があるスクリプトを実行します。 23 | * __opt__ : オプション入力欄を表示/非表示します。入力できるオプションがない場合、no option と表示されます。 24 | * __<__ : 直前の描画を取り消します。 25 | * __>__ : 直前に取り消した描画をやり直します。 26 | * __CL__ : パネル上の描画をクリアします。 27 | * __DB__ : 既定のブラウザでデバッグツールを開きます。 28 | * __RL__ : パネルをリロードします。( hostscript.jsx はリロードされません。) 29 | * __load__ : スクリプトファイルを選択するダイアログを表示します。 30 | 31 | ### スクリプトファイルの読み込み 32 | * 読み込みたいスクリプトファイルを、パネルへドラッグ&ドロップしてください。 33 | __load__ ボタンでスクリプトファイルを選択することもできます。 34 | * 読み込み完了後、パネル上の描画はクリアされます。 35 | 36 | ### 読み込んで実行できる JavaScript スクリプト 37 | * [scripts](https://github.com/shspage/plainCanvas/tree/master/scripts) フォルダにサンプルスクリプトがあります。 38 | * javascript として記述してください (paperscript ではなく)。詳しくは、http://paperjs.org の、チュートリアル "[Using JavaScript Directly](http://paperjs.org/tutorials/getting-started/using-javascript-directly/)" をご覧下さい。 39 |   __例:__ new Path() -> new paper.Path() // または "with(paper){" ステートメントを使うなど 40 |   __例:__ point1 + point2 -> point1.add(point2) 41 |   __例:__ function onMouseDown(event) -> tool.onMouseDown = function(event) 42 | * 文字コードは utf-8 で作成してください。(js/main.js 内の SCRIPT_ENCODING で変更することもできます。変更した場合は、index.htmlのcharset も変更してください。) 43 | * パネルのオプション入力欄を利用する場合、または、 オプション入力欄を非表示にする場合、optionManager.js のメソッドが利用できます。使用方法については同ファイル内の説明やサンプルスクリプトをご覧下さい。 44 | * object の描画が完了した時点で以下を実行すると、undo/redoの対象にできます。("object" は描画したオブジェクトを示す変数に置き換えてください。) 45 | ```javascript 46 | undoManager.keep(object); 47 | ``` 48 | undo は、対象にしたオブジェクトを不可視にすることで行われるため、paper.project 上には存在したままです。ただし、undoManager.js の UNDO_LIMIT を超えた場合は古いものから削除されます。また、不可視オブジェクトは書き出されません。 49 | * 読み込んだスクリプトファイルは、index.html 内に新たに生成した script タグの内容として挿入されます。 50 | 51 | 52 | ### 色の扱い 53 | * canvas は CMYKカラーを扱えないため、CMYKカラーを取り込んだ場合はRGBに変換して表示します。このため、元の色と違って見える場合があります。元のCMYKの値はメモリに保持しており(*1)、書き出す際には元の色になります。 54 | (*1: js/main.js の ALWAYS_EXPORT_RGB が false の場合) 55 | * js/main.js の ALWAYS_EXPORT_RGB が true の場合、paper.Color.type == "gray" の色は RGBColor で書き出されます。 56 | * 取り込み/書き出しの処理は、グラデーション、特色 に対応していません。 57 | 58 | ### アートボードへの書き出し 59 | * canvas 上の paper.Path インスタンスの、以下の属性が書き出されます。 60 | _segments, strokeWidth, strokeColor, fillColor, opacity_ 61 | 62 | ### パスの取り込み 63 | * アートボード上の選択範囲に含まれる PathItem の以下の属性が取り込まれます。 64 | _pathPoints, strokeWidth, strokeColor, fillColor_ 65 | * グループと複合パスは解除された状態で取り込まれます。 66 | 67 | ### 画像の読み込み 68 | * パネルへのドラッグ&ドロップ、または__load__ ボタンによって画像を読み込むことができます。対応画像形式は jpeg, png です。 69 | * 画像読み込み後にパネル右上に表示される[hide image]をクリックすると画像を非表示にできます。再度クリックすると表示します。 70 | * 読み込んだ画像は __paper.project.activeLayer.data.raster__ に保持され、スクリプトで利用することができます。 71 | * 画像は、スクリプトファイルの読み込みや CL・RLボタンによる画面クリアの際に破棄されます。 72 | 73 | ### 変更履歴 74 | #### v.1.2.2 75 | * 画像読み込みに対応。 76 | #### v.1.2.1 77 | * スクリプト読み込みエラー アラートと実行エラー アラートを追加しました。 78 | #### v.1.2.0 79 | * ライブラリ類を更新。 80 | #### v.1.1.8 81 | * runボタンを追加。runボタン用のサンプルスクリプトを追加。 82 | * 修正:前回と同じ名前のスクリプトファイルを読み込んだ際に、変更が反映されます。 83 | #### v.1.1.7 84 | * loadボタンでもスクリプトファイルを読み込めるようにしました。 85 | #### v.1.1.6 86 | * manifest.xml で対応バージョンの上限を 99.9 に変更 87 | #### v.1.1.4 88 | * manifest.xml で対応バージョンの上限を 24.9 に変更 89 | #### v.1.1.3 90 | * グレーカラーのインポート/エクスポートでの問題を修正 91 | #### v.1.1.2 92 | * loadボタンを廃止し、スクリプトファイルのドロップを常に受け付けるようにしました。 93 | * paper.js の基本オブジェクトをグローバルにしました。これに合わせてサンプルスクリプトも更新しました。 94 | * パネルの最大サイズを2000×2000に拡大しました。 95 | #### v.1.1.1 96 | * 読み込み時以外、パネルへのドロップを受け付けないようにしました。 97 | #### v.1.1.0 98 | * パネル上のドラッグでテキストが選択されないようにしました。 99 | * スクリプトファイルをドラッグ&ドロップで読み込むようにしました。 100 | 101 | ### TODO / 既知の問題 102 | * TODO: 外部スクリプトファイルの読み込み方法を再検討する。 103 | * アートボードから取り込んだ図形の白黒が反転する場合がある。 104 | * 書き出した際に、アートボードから取り込んだものとcanvas上で描画したものの前後関係が正しくない場合がある。 105 | * TODO: アートボードとのやりとりに importSVG, exportSVG を使う? 106 | 107 | ### ライセンス、その他 108 | * ※ 改変して公開する場合は、必ず __バンドルID__ を変更してください。(バンドルID … CSXS/manifest.xml および.debug 内の com.shspage.csxs.plaincanvas。) 109 | * MIT ライセンスの下で公開しています。詳細はLICENSE.txtをご覧下さい。 110 | ただし、以下の使用ライブラリは、それぞれのライセンスに従います。 111 | 112 | * Paper.js v0.12.17 - The Swiss Army Knife of Vector Graphics Scripting. 113 | http://paperjs.org/ 114 | Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey 115 | http://juerglehni.com/ & https://puckey.studio/ 116 | All rights reserved. 117 | 118 | * Creative Cloud Extension Builder for Brackets 119 | https://github.com/davidderaedt/CC-Extension-Builder-for-Brackets 120 | Copyright (c) 2012 Adobe Systems Incorporated. All rights reserved. 121 | 122 | -------------------------------------------------------------------------------- /scripts/fiddlehead.js: -------------------------------------------------------------------------------- 1 | // fiddlehead (zenmai) 2 | // for plainCanvas v.1.1.2 or later 3 | (function() { 4 | paper.setup("canvas"); 5 | with(paper){ 6 | var tool = new Tool(); 7 | 8 | var hlen = 4 * (Math.sqrt(2) - 1) / 3; 9 | var hpi = 90; 10 | var qpi = hpi / 2; 11 | var po = new Point(0,0); 12 | 13 | var line, lastPnt, gr; 14 | var angleRange, stemLen, spiralRadius, lineWidth; 15 | var interval, growDir, lineCol; 16 | 17 | function setupOptions(){ 18 | angleRange = 45; 19 | stemLen = 100; 20 | spiralRadius = 10; 21 | lineWidth = 0.5; 22 | 23 | // init 24 | interval = spiralRadius / 2; 25 | growDir = 1; // 1:normal, 2:drawing direction 26 | lineCol = "black"; //new Color(1); //or selectedLineCol_or_Black(); 27 | 28 | stemLen /= 2; 29 | spiralRadius /= 2; 30 | 31 | optionManager.setupOptionsUI(["stem length", "spiral radius", "interval", "angle range", "direction(1,2)"], 32 | [stemLen*2, spiralRadius*2, interval, angleRange, growDir]); 33 | } 34 | setupOptions(); 35 | 36 | // --------------------- 37 | function getOptions(){ 38 | var opt = optionManager.getOptionsFromUI(); 39 | if(opt != null){ 40 | for(var i=0; i 0){ 73 | v = (event.delta).normalize(); 74 | if(growDir > 1) v = v.rotate(hpi); 75 | } 76 | makeline(); 77 | 78 | zenmai(v.rotate(hpi), event); 79 | } 80 | // -------------------------- 81 | tool.onMouseUp = function(event){ 82 | if(gr){ 83 | if(gr.children.length < 2){ 84 | if(gr.children.length == 1) gr.firstChild.moveAbove(gr); 85 | gr.remove(); 86 | } else { 87 | if(undoManager) undoManager.keep(gr); 88 | } 89 | gr = null; 90 | } 91 | lastPnt = null; 92 | line = null; 93 | } 94 | // -------------------------- 95 | function makeline(){ 96 | line = new Path({ 97 | fillColor: null, 98 | strokeColor: lineCol, 99 | strokeWidth: lineWidth 100 | }); 101 | if(!gr) gr = new Group(); 102 | gr.addChild(line); 103 | } 104 | // -------------------------- 105 | function zenmai(v, event){ 106 | var m = Math.random() + 1; 107 | var len = stemLen * m; 108 | var hlen = len/3; 109 | // 1st point 110 | line.segments = [new Segment(lastPnt, 111 | po, 112 | v.multiply(hlen))]; 113 | // 2nd point 114 | v = v.rotate(angleRange * (Math.random()-0.5)); 115 | var p = lastPnt.add( v.multiply(len)); 116 | line.add(new Segment(p, 117 | v.rotate(angleRange * (Math.random()-0.5)) * (-hlen), 118 | po)); 119 | 120 | addSpiral(line.segments, spiralRadius * m, 0.85, 12, (Math.random() < 0.5)); 121 | } 122 | // -------------------------- 123 | function addSpiral(segs, 124 | r, // first radius 125 | m, // rate 126 | n, // number of segments 127 | rl){ // turn right (t/f) 128 | var qp = rl ? -qpi : qpi; 129 | 130 | var len = segs.length - 1; 131 | if(len < 1) return; 132 | var p = segs[len].point; 133 | // define v 134 | var v; 135 | if(segs[len].handleIn.equals(po)){ 136 | with(segs[len - 1]){ 137 | if(p.equals(point)) return; 138 | if(p.equals(point.add(handleOut))){ 139 | v = (p.subtract(point)).normalize(); 140 | } else { 141 | v = (p.subtract(point.add(handleOut))).normalize(); 142 | } 143 | } 144 | } else { 145 | v = (segs[len].handleIn.multiply(-1)).normalize(); 146 | } 147 | // make spiral 148 | var seg; 149 | var h = r * hlen; 150 | segs[len].handleOut = v.multiply(h); 151 | for(var i=0; i 0){ 88 | s = s.replace(/0+$/,""); 89 | return s.replace(/\.$/,""); 90 | } 91 | } 92 | 93 | // serialize a color object to draw on a canvas 94 | function serializeColor(col){ 95 | if(col.typename == "NoColor"){ 96 | return ["N", 0, 0, 0, 0]; 97 | } else if(col.typename == "GrayColor"){ 98 | return ["G", _f2s(col.gray / 100), 0, 0, 0]; 99 | } else if(col.typename == "RGBColor"){ 100 | return ["RGB", _f2s(col.red / 255), _f2s(col.green / 255), _f2s(col.blue / 255), 0]; 101 | } else if(col.typename == "CMYKColor"){ 102 | return ["CMYK", _f2s(col.cyan), _f2s(col.magenta), _f2s(col.yellow), _f2s(col.black)]; 103 | } else { 104 | // GradientColor, SpotColor etc. 105 | return ["UNKNOWN", 0, 0, 0, 0]; 106 | } 107 | } 108 | 109 | // find the top-left point of paths 110 | function getTopLeftOfPaths(paths){ 111 | if(paths.length < 1) return [0,0]; 112 | 113 | var top = paths[0].top; 114 | var left = paths[0].left; 115 | 116 | for(var i = 0, iEnd = paths.length; i < iEnd; i++){ 117 | 118 | var cb = paths[i].controlBounds; // left, top, right, bottom 119 | 120 | if(cb[1] > top) top = cb[1]; 121 | if(cb[0] < left) left = cb[0]; 122 | } 123 | return [top, left]; 124 | } 125 | 126 | // serialize an array of pathItems to draw on a canvas 127 | function serializePaths(){ 128 | var paths = extractSelectedPaths(); 129 | var data = []; 130 | 131 | var MARGIN_TOP = 50; 132 | var MARGIN_LEFT = 25; 133 | 134 | var top_left = getTopLeftOfPaths(paths); 135 | var top = top_left[0] + MARGIN_TOP; 136 | var left = top_left[1] - MARGIN_LEFT; 137 | 138 | for(var i = paths.length - 1; i >= 0; i--){ 139 | var r = ["@"]; // "@" is a mark that means the beginning of a path 140 | var p = paths[i]; 141 | 142 | r.push(p.closed ? "1" : "0"); 143 | 144 | r.push([p.filled ? "1" : "0", 145 | serializeColor(p.fillColor)]); 146 | 147 | r.push([p.stroked && p.strokeColor.typename != "NoColor" ? "1" : "0", 148 | _f2s(p.strokeWidth), 149 | serializeColor(p.strokeColor)]); 150 | 151 | for(var j = 0, jEnd = p.pathPoints.length; j < jEnd; j++){ 152 | var ppt = p.pathPoints[j]; 153 | var anc = ppt.anchor; 154 | r.push([_f2s(anc[0] - left), _f2s(anc[1] - top), 155 | _f2s(ppt.rightDirection[0] - anc[0]), 156 | _f2s(ppt.rightDirection[1] - anc[1]), 157 | _f2s(ppt.leftDirection[0] - anc[0]), 158 | _f2s(ppt.leftDirection[1] - anc[1])]); 159 | // ignore pointType becauses paper js doesn't have this property 160 | } 161 | 162 | data[data.length] = r; 163 | } 164 | 165 | // "data" is passed to callback function as a comma separated string 166 | return data; 167 | } 168 | 169 | function extractSelectedPaths(items, paths){ 170 | if(!items) items = app.activeDocument.selection; 171 | if(!paths) paths = []; 172 | for(var i = 0, iEnd = items.length; i < iEnd; i++){ 173 | if(items[i].typename == "PathItem"){ 174 | paths.push(items[i]); 175 | } else if(items[i].typename == "GroupItem"){ 176 | extractSelectedPaths(items[i].pageItems, paths); 177 | } else if(items[i].tyepname == "CompoundPathItem"){ 178 | extractSelectedPaths(items[i].pathItems, paths); 179 | } 180 | } 181 | return paths; 182 | } 183 | -------------------------------------------------------------------------------- /com.shspage.csxs.plaincanvas/js/libs/paperjs-v0.12.17/node/extend.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. 3 | * http://paperjs.org/ 4 | * 5 | * Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey 6 | * http://juerglehni.com/ & https://puckey.studio/ 7 | * 8 | * Distributed under the MIT license. See LICENSE file for details. 9 | * 10 | * All rights reserved. 11 | */ 12 | 13 | var fs = require('fs'), 14 | path = require('path'); 15 | 16 | module.exports = function(paper) { 17 | if (paper.PaperScript) { 18 | var sourceMapSupport = 'require("source-map-support").install(paper.PaperScript.sourceMapSupport);\n', 19 | sourceMaps = {}; 20 | 21 | paper.PaperScript.sourceMapSupport = { 22 | retrieveSourceMap: function(source) { 23 | var map = sourceMaps[source]; 24 | return map ? { url: source, map: map } : null; 25 | } 26 | }; 27 | 28 | // Register the .pjs extension for automatic compilation as PaperScript 29 | require.extensions['.pjs'] = function(module, filename) { 30 | // Requiring a PaperScript on Node.js returns an initialize method which 31 | // needs to receive a Canvas object when called and returns the 32 | // PaperScope. 33 | module.exports = function(canvas) { 34 | var source = fs.readFileSync(filename, 'utf8'), 35 | code = sourceMapSupport + source, 36 | compiled = paper.PaperScript.compile(code, { 37 | url: filename, 38 | source: source, 39 | sourceMaps: true, 40 | offset: -1 // remove sourceMapSupport... 41 | }), 42 | scope = new paper.PaperScope(); 43 | // Keep track of sourceMaps so retrieveSourceMap() can link them up 44 | scope.setup(canvas); 45 | scope.__filename = filename; 46 | scope.__dirname = path.dirname(filename); 47 | // Expose core methods and values 48 | scope.require = require; 49 | scope.console = console; 50 | sourceMaps[filename] = compiled.map; 51 | paper.PaperScript.execute(compiled, scope); 52 | return scope; 53 | }; 54 | }; 55 | } 56 | 57 | paper.PaperScope.inject({ 58 | createCanvas: function(width, height, type) { 59 | // Do not use CanvasProvider.getCanvas(), since we may be changing 60 | // the underlying node-canvas when requesting PDF support, and don't 61 | // want to release it after back into the pool. 62 | var canvas = paper.document.createElement('canvas'); 63 | canvas.width = width; 64 | canvas.height = height; 65 | canvas.type = type; 66 | return canvas; 67 | }, 68 | 69 | /** 70 | * @deprecated, use use {@link #createCanvas(width, height)} instead. 71 | */ 72 | Canvas: '#createCanvas' 73 | }); 74 | 75 | // Override requestAnimationFrame() to avoid setInterval() timers. 76 | // NOTE: In Node.js, we only support manual updating for now, but 77 | // View#exportFrames() below offers a way to emulate animations by exporting 78 | // them frame by frame at the given frame-rate. 79 | paper.DomEvent.requestAnimationFrame = function(callback) { 80 | }; 81 | 82 | // Node.js based image exporting code. 83 | paper.CanvasView.inject({ 84 | // DOCS: CanvasView#exportFrames(options); 85 | exportFrames: function(options) { 86 | options = paper.Base.set({ 87 | fps: 30, 88 | prefix: 'frame-', 89 | amount: 1, 90 | format: 'png' // Supported: 'png' or 'jpeg' 91 | }, options); 92 | if (!options.directory) 93 | throw new Error('Missing options.directory'); 94 | if (options.format && !/^(jpeg|png)$/.test(options.format)) 95 | throw new Error('Unsupported format. Use "png" or "jpeg"'); 96 | var view = this, 97 | count = 0, 98 | frameDuration = 1 / options.fps, 99 | startTime = Date.now(), 100 | lastTime = startTime, 101 | padding = options.padding || ((options.amount - 1) + '').length, 102 | paddedStr = Array(padding + 1).join('0'); 103 | 104 | // Start exporting frames by exporting the first frame: 105 | exportFrame(options); 106 | 107 | function exportFrame() { 108 | // Convert to a Base object, for #toString() 109 | view.emit('frame', new paper.Base({ 110 | delta: frameDuration, 111 | time: frameDuration * count, 112 | count: count 113 | })); 114 | var file = path.join(options.directory, 115 | options.prefix + (paddedStr + count).slice(-padding) 116 | + '.' + options.format); 117 | var out = view.exportImage(file, function() { 118 | // Once the file has been closed, export the next fame: 119 | var then = Date.now(); 120 | if (options.onProgress) { 121 | options.onProgress({ 122 | count: count, 123 | amount: options.amount, 124 | percentage: Math.round((count + 1) / options.amount 125 | * 10000) / 100, 126 | time: then - startTime, 127 | delta: then - lastTime 128 | }); 129 | } 130 | lastTime = then; 131 | if (++count < options.amount) { 132 | exportFrame(); 133 | } else { 134 | // Call onComplete handler when finished: 135 | if (options.onComplete) { 136 | options.onComplete(); 137 | } 138 | } 139 | }); 140 | } 141 | }, 142 | 143 | // DOCS: CanvasView#exportImage(path, callback); 144 | exportImage: function(path, callback) { 145 | this.update(); 146 | var out = fs.createWriteStream(path), 147 | format = /\.jp(e?)g$/.test(path) ? 'jpeg' : 'png', 148 | stream = this._element[format + 'Stream'](); 149 | stream.pipe(out); 150 | if (callback) { 151 | out.on('close', callback); 152 | } 153 | return out; 154 | } 155 | }); 156 | }; 157 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # plainCanvas 2 | 3 | Adobe Illustrator (CC 2014-) add-on with following functions. 4 | (Japanese README is [here](https://github.com/shspage/plainCanvas/blob/master/README_ja.md)) 5 | 6 | * loads and executes a script file written for [paper.js](http://paperjs.org). 7 | (at the initial state, you can use a simple drawing tool.) 8 | * exports the image created on the panel onto the artboard. 9 | * imports selected paths on the artboard onto the panel. 10 | 11 | ![image of the panel](https://github.com/shspage/plainCanvas/raw/master/image/desc_plaincanvas.png "image of the panel") 12 | 13 | ### Installation 14 | Because of the character of this add-on that loads external script files, it is released with an assumtion of doing debugs. Installation steps are as follows. 15 | 16 | 1. Setting the __debug mode flag__ refer to Adobe's document - [Debugging Unsigned Extensions](https://github.com/Adobe-CEP/CEP-Resources/blob/master/CEP_10.x/Documentation/CEP%2010.0%20HTML%20Extension%20Cookbook.md#debugging-unsigned-extensions). 17 | (It says "CSXS.10", but the number varies depending on the Illustrator's version. ex."CSXS.11" for Ai 2024(28.2)) 18 | 2. Put the folder "com.shspage.csxs.plaincanvas" in the right folder refer to Adobe's document - [Extension Folders](https://github.com/Adobe-CEP/CEP-Resources/blob/master/CEP_10.x/Documentation/CEP%2010.0%20HTML%20Extension%20Cookbook.md#extension-folders). 19 | 3. Launch Illustrator and navigate Window -> Extensions fo find plainCanvas. 20 | 21 | 22 | ### buttons on the panel 23 | * __in__ : imports selected paths on the artboard onto the canvas 24 | * __out__ : exports the image created on the canvas onto the artboard 25 | * __run__ : executes a script that has an executable function 26 | * __opt__ : shows/hides the form for optional values 27 | * __<__ : undo 28 | * __>__ : redo 29 | * __CL__ : clears the canvas 30 | * __DB__ : opens the debug tool with a default browser. 31 | * __RL__ : reloads the extention panel 32 | * __load__ : opens a dialog to select a script file to lead 33 | 34 | ### loading a script file 35 | * Drag and drop a script file you want to load onto the panel. 36 | You can also use __load__ button to select a script file. 37 | * Drawing on the panel will be cleared after loading is complete. 38 | 39 | ### script files that can be loaded 40 | * There're some sample scripts in "[scripts](https://github.com/shspage/plainCanvas/tree/master/scripts)" folder. 41 | * Write in __JavaScript__ (not paperscript). For details, see "[Using JavaScript Directly](http://paperjs.org/tutorials/getting-started/using-javascript-directly/)" in http://paperjs.org. 42 | __ex:__ new Path() -> new paper.Path() // or use "with(paper){" statement 43 | __ex:__ point1 + point2 -> point1.add(point2) 44 | __ex:__ function onMouseDown(event) -> tool.onMouseDown = function(event) 45 | * Set the character encoding to __UTF-8__. 46 | * You can use the UIs for optional values with simple methods. see "js/optionManager.js". 47 | * You can set a drawn object as a target for undo/redo by calling the method like this. 48 | ```javascript 49 | undoManager.keep(object); 50 | ``` 51 | Note that undoed objects are just hidden, and still exists in the current paper.project. 52 | 53 | 54 | 55 | ### colors 56 | * Since html5 canvas uses RGB color, imported CMYK and GRAY colors may look different from they look on the artboard. 57 | * If ALWAYS_EXPORT_RGB (js/main.js) is set false, the original CMYK colors are kept in memory 58 | and are applied when they are exported. (When DefaultColorSpace of the artboard 59 | is CMYK.) 60 | * If ALWAYS_EXPORT_RGB is true, GRAY colors are exported in RGB. 61 | * Gradient color and spot color are not supported for now. 62 | 63 | ### exports to an artboard 64 | * Following attributes of paper.Path instance on the canvas are exported. 65 | _segments, strokeWidth, strokeColor, fillColor, opacity_ 66 | 67 | ### imports from an artboard 68 | * Following attributes of selected PathItems are imported. 69 | _pathPoints, strokeWidth, strokeColor, fillColor._ 70 | * Grouped paths and compoundpaths are imported in released condition. 71 | 72 | ### Loading images 73 | * You can load images by dragging and dropping them onto the panel or by using the __load__ button. Supported image formats are jpeg and png. 74 | * You can hide the image by clicking [hide image] displayed at the top right of the panel after loading the image. Click again to display. 75 | * The loaded image is stored in __paper.project.activeLayer.data.raster__ and can be used in scripts. 76 | * The loaded image is discarded when loading a script file or clearing the screen using the CL/RL buttons. 77 | 78 | 79 | ### changelog 80 | #### v.1.2.2 81 | * Supports image loading. 82 | #### v.1.2.1 83 | * Added script loading error alert and run error alert. 84 | #### v.1.2.0 85 | * updated libraries 86 | #### v.1.1.8 87 | * Added "run" button. Added sample script for "run" button. 88 | * Fix: Even if you load a script file with the same name as one currently loaded, the changes will take effect. 89 | #### v.1.1.7 90 | * The "load" button is back. 91 | #### v.1.1.6 92 | * Set the upper limit of supported versions to 99.9 in manifest.xml. 93 | #### v.1.1.4 94 | * Set the upper limit of supported versions to 24.9 in manifest.xml. 95 | #### v.1.1.3 96 | * Fixed grayColor import/export issue. 97 | #### v.1.1.2 98 | * Removed the "load" button. A drop of a script file is always accepted. 99 | * Simplified optionManager methods. Updated the contents of the sample script accordingly. 100 | * Expanded the maximum panel size to 2000 x 2000 pixels. 101 | #### v.1.1.1 102 | * Improved to invalidate drop to panel except when loading. 103 | #### v.1.1.0 104 | * Improved to prevent the text on the panel from being selected by dragging. 105 | * The script file is loaded by drag-and-drop to the panel. 106 | 107 | ### TODO / known issues 108 | * TODO: Review the external script file reading method. 109 | * When exporting, there may be cases where the context of things captured from the artboard and those drawn on the canvas are incorrect. 110 | * TODO: use importSVG, exportSVG to exchange data with artboard ? 111 | 112 | ### License 113 | * When you distribute a modified version, make sure changing the __bundle ID__. 114 | It is represented as "com.shspage.csxs.plaincanvas" in CSXS/manifest.xml and .debug. 115 | * Copyright (c) 2015 Hiroyuki Sato. All rights reserved. 116 | http://shspage.com/ 117 | This software is distributed under the MIT License. 118 | See the LICENSE.txt for details. 119 | This software uses the following libraries that may have 120 | licenses differing from that of the software itself. You can find the 121 | libraries and their respective licenses below. 122 | 123 | * Paper.js v0.12.17 - The Swiss Army Knife of Vector Graphics Scripting. 124 | http://paperjs.org/ 125 | Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey 126 | http://juerglehni.com/ & https://puckey.studio/ 127 | All rights reserved. 128 | 129 | * Creative Cloud Extension Builder for Brackets 130 | https://github.com/davidderaedt/CC-Extension-Builder-for-Brackets 131 | Copyright (c) 2012 Adobe Systems Incorporated. All rights reserved. 132 | 133 | -------------------------------------------------------------------------------- /com.shspage.csxs.plaincanvas/js/main.js: -------------------------------------------------------------------------------- 1 | /*global $, window, location, CSInterface, SystemPath, themeManager, paper, optionManager, undoManager, runPaperScript*/ 2 | 3 | (function () { 4 | 'use strict'; 5 | 6 | // if true, show "debug" button and "reload" button 7 | var DEBUG_MODE = true; 8 | 9 | // Since html5 canvas uses RGB color, imported CMYK and GRAY colors 10 | // may look different from how they look on the artboard. 11 | // * If ALWAYS_EXPORT_RGB is false, the original CMYK colors are kept in memory 12 | // and are applied when they are exported. (When DefaultColorSpace of the artboard 13 | // is CMYK.) 14 | // * If ALWAYS_EXPORT_RGB is true, GRAY colors are exported in RGB. 15 | var ALWAYS_EXPORT_RGB = false; 16 | 17 | // port number defined in ".debug" file 18 | var DEBUG_TOOL_PORT_NUMBER = "8080"; 19 | 20 | // encoding of a script file which is loaded 21 | var SCRIPT_ENCODING = "utf-8"; 22 | 23 | // holds various values 24 | var _spec = { 25 | inputFileName : "", 26 | inputFileObj : null 27 | } 28 | 29 | 30 | var csInterface = new CSInterface(); 31 | 32 | // Opens the chrome developer tools in host app 33 | function showDevTools() { 34 | if(confirm("open the debug tool?")){ 35 | csInterface.openURLInDefaultBrowser("http://localhost:" + DEBUG_TOOL_PORT_NUMBER); 36 | } 37 | } 38 | // Reloads extension panel 39 | function reloadPanel() { 40 | if(confirm("reload the panel?")){ 41 | location.reload(); 42 | } 43 | } 44 | 45 | 46 | // ---------------------- 47 | // functions for CMYK colors 48 | // ---------------------- 49 | // Since paper.js can't handle CMYK colors, these functions 50 | // keep values of them in "_ids" object, associated with 51 | // id of paper.Item. 52 | 53 | // _ids 54 | // key: id of paper.Item 55 | // value: CMYK instance 56 | var _ids = {}; 57 | 58 | var CMYK = function(){ 59 | // each value is comma separated cmyk values. ex:"50.5,20,0,100" 60 | this.fill; 61 | this.stroke; 62 | } 63 | // ---- 64 | var registCmykColor = function(id, cmykSpec, is_fill){ 65 | if(!(id in _ids)) _ids[id] = new CMYK(); 66 | 67 | if(is_fill){ 68 | _ids[id].fill = cmykSpec; // ex:"50.5,20,0,100" 69 | } else { 70 | _ids[id].stroke = cmykSpec; 71 | } 72 | } 73 | // ---- 74 | var getRegistedColor = function(id, is_fill){ 75 | if(id in _ids){ 76 | if(is_fill){ 77 | if(_ids[id].fill) return "," + _ids[id].fill; 78 | } else { 79 | if(_ids[id].stroke) return "," + _ids[id].stroke; 80 | } 81 | } 82 | return ""; 83 | } 84 | 85 | // ---------------------- 86 | // functions to serialize/unserialize objects 87 | // ---------------------- 88 | // shorten the length of a string form of a float value 89 | function f2s(f){ 90 | var s = f.toFixed(4); 91 | if(s.indexOf(".") > 0){ 92 | s = s.replace(/0+$/,""); 93 | return s.replace(/\.$/,""); 94 | } 95 | } 96 | 97 | // parseFloat 98 | function pf(s){ return parseFloat(s); } 99 | 100 | // get paths on canvas 101 | function getPathsOnCanvas(){ 102 | var lay = paper.project.activeLayer; 103 | var paths = []; 104 | if(lay) getPathsOnCanvas_sub(paths, lay); 105 | return paths; 106 | } 107 | 108 | // sub function of getPathsOnCanvas 109 | function getPathsOnCanvas_sub(paths, gr){ 110 | for(var i = gr.children.length - 1; i >= 0; i--){ 111 | if(gr.children[i] instanceof paper.Path 112 | && gr.children[i].visible){ // items undoed by undoManager are invisible 113 | paths.push(gr.children[i]); 114 | } else if(gr.children[i] instanceof paper.Group){ 115 | getPathsOnCanvas_sub(paths, gr.children[i]); 116 | } 117 | } 118 | } 119 | 120 | // corrects the range of the color 121 | function correctRange(v, maxval){ 122 | return Math.max(0, Math.min(v, maxval)); 123 | } 124 | 125 | // serialize a color of a paper object 126 | function serializePaperColor(col, c_id, is_fill){ 127 | var s = ""; 128 | var v; 129 | if(col.type == "gray"){ 130 | v = correctRange(col.gray, 1); 131 | s = f2s(v * 255); 132 | s = ALWAYS_EXPORT_RGB 133 | ? s +","+ s +","+ s 134 | : f2s((1 - v) * 100); 135 | } else if(col.type == "rgb"){ 136 | s = f2s(correctRange(col.red, 1) * 255) +","+ 137 | f2s(correctRange(col.green, 1) * 255) +","+ 138 | f2s(correctRange(col.blue, 1) * 255); 139 | if( ! ALWAYS_EXPORT_RGB) s += getRegistedColor(c_id, is_fill); 140 | } else{ 141 | s = ALWAYS_EXPORT_RGB ? "0,0,0" : "0,0"; // black 142 | } 143 | return s; 144 | } 145 | 146 | // create a RGB type paper.Color instance from CMYK specification 147 | // it's inaccurate and just for displaying the color tentatively 148 | function cmyk2rgbColor(cmyk){ // cmyk: [c, m, y, k] 149 | var c = pf(cmyk[0]) / 100; var m = pf(cmyk[1]) / 100; 150 | var y = pf(cmyk[2]) / 100; var k = pf(cmyk[3]) / 100; 151 | 152 | var r = 1 - Math.min(1, c * (1 - k) + k); 153 | var g = 1 - Math.min(1, m * (1 - k) + k); 154 | var b = 1 - Math.min(1, y * (1 - k) + k); 155 | return new paper.Color(r, g, b); 156 | } 157 | 158 | // create a paper.Color instance from a serialized AI color 159 | function getPaperColorFromResult(p_id, color_type, c1, c2, c3, c4, is_fill) { 160 | var col; 161 | if(color_type == "N"){ // N,0,0,0,0, 162 | col = null; 163 | } else if(color_type == "G"){ 164 | col = new paper.Color(1 - pf(c1)); 165 | } else if(color_type == "RGB"){ 166 | col = new paper.Color(pf(c1), pf(c2), pf(c3)); 167 | } else if(color_type == "CMYK"){ 168 | var colorSpec = [c1, c2, c3, c4]; 169 | if( ! ALWAYS_EXPORT_RGB) registCmykColor(p_id, colorSpec.join(","), is_fill) 170 | col = cmyk2rgbColor(colorSpec); 171 | } else { 172 | col = new paper.Color(0); 173 | } 174 | return col; 175 | } 176 | 177 | // ---------------------- 178 | // functions to load a script file 179 | // ---------------------- 180 | function handleFileSelect(evt){ 181 | evt.stopPropagation(); 182 | evt.preventDefault(); 183 | var files = evt.dataTransfer.files; 184 | if(files.length > 0){ 185 | var fileobj = files[0]; 186 | var type = fileobj.type; 187 | 188 | if(type != "application/x-javascript" 189 | && type != "application/javascript" 190 | && type != "text/javascript" 191 | && type != "image/png" 192 | && type != "image/jpeg"){ 193 | 194 | if(type == ""){ 195 | type = "(unknown type)"; 196 | } 197 | 198 | alert("Please select a JavaScript file, or a png/jpeg Image.\n" 199 | + "Selected file is \"" + type + "\"."); 200 | return false; 201 | } 202 | 203 | // confirm 204 | _spec.inputFileObj = fileobj; 205 | $("#span_dropzone_text").text("load " + fileobj.name + " ?") 206 | $("#div_dropzone").show(); 207 | $("#div_screen").show(); 208 | } 209 | } 210 | function handleDragOver(evt){ 211 | evt.stopPropagation(); 212 | evt.preventDefault(); 213 | evt.dataTransfer.dropEffect = "copy"; 214 | } 215 | 216 | // ---- 217 | function removeRaster(){ 218 | var image = document.getElementById("raster"); 219 | if(image){ 220 | image.remove(); 221 | } 222 | if(paper.project.activeLayer.data.raster){ 223 | paper.project.activeLayer.data.raster.remove(); 224 | paper.project.activeLayer.data.raster = null; 225 | } 226 | $("#raster_indicator").text(""); 227 | } 228 | 229 | function clearCanvas(){ 230 | if(undoManager) undoManager.clearHistory(); 231 | removeRaster(); 232 | if(paper.project){ 233 | var cs = paper.project.activeLayer.children; 234 | for(var i = cs.length - 1; i >= 0; i--){ 235 | cs[i].remove(); 236 | } 237 | } 238 | _ids = {}; 239 | } 240 | 241 | // load a script file and insert its contents into the document 242 | function insertPaperScript(fileobj){ 243 | _spec.inputFileName = fileobj.name; 244 | 245 | var fr = new FileReader(); 246 | fr.onload = function(e){ 247 | var data = e.target.result; 248 | try { 249 | Function(data); 250 | } catch(err){ 251 | console.log(err); 252 | alert("Failed to load : " + err.name + "\n" + err.message); 253 | return; 254 | } 255 | 256 | clearCanvas(); 257 | paper.remove(); 258 | 259 | optionManager.resetOptions(); 260 | runPaperScript = undefined; 261 | 262 | $("#script_paper").remove(); 263 | var script = document.createElement("script"); 264 | script.setAttribute("id","script_paper"); 265 | script.type = "text/javascript"; 266 | script.innerHTML = e.target.result; 267 | document.body.appendChild( script ); 268 | 269 | $("#script_filename").text(_spec.inputFileName); 270 | } 271 | fr.readAsText(fileobj, SCRIPT_ENCODING); 272 | } 273 | 274 | // load an image 275 | function insertRaster(fileobj){ 276 | var fr = new FileReader(); 277 | fr.onload = function (e) { 278 | removeRaster(); 279 | var image = document.createElement('img'); 280 | image.setAttribute("id","raster"); 281 | image.onload = function () { 282 | var raster = new paper.Raster(image); 283 | raster.sendToBack(); 284 | raster.fitBounds(new paper.Rectangle(0,0, 285 | window.innerWidth, window.innerHeight)); 286 | raster.visible = true; 287 | paper.project.activeLayer.data.raster = raster; 288 | $("#raster_indicator").text(" [hide image]"); 289 | }; 290 | image.src = e.target.result; 291 | document.body.appendChild( image ); 292 | }; 293 | fr.readAsDataURL(fileobj); 294 | } 295 | // ---------------------- 296 | // initialize the extension 297 | // ---------------------- 298 | function init() { 299 | themeManager.init(); 300 | 301 | if(DEBUG_MODE){ 302 | $("#btn_debug").show(); 303 | $("#btn_reload").show(); 304 | $("#btn_debug").click(showDevTools); 305 | $("#btn_reload").click(reloadPanel); 306 | } 307 | 308 | document.addEventListener('dragover', handleDragOver); 309 | document.addEventListener('drop', handleFileSelect); 310 | 311 | // in button 312 | // serialize paths selected in artboard 313 | // and convert it into paths as paper object 314 | $("#btn_in").click(function () { 315 | csInterface.evalScript('serializePaths()', function(result){ 316 | if(paper.project == null) return; 317 | if(result == "") return; 318 | 319 | var r = result.split(","); 320 | var p; 321 | var i = 0; 322 | var rlen = r.length; 323 | 324 | while(i < rlen){ 325 | if(r[i] == "@"){ 326 | p = new paper.Path(); 327 | p.closed = r[++i] == "1"; 328 | 329 | // fill 330 | if(r[++i] == "1"){ // filled 331 | p.fillColor = getPaperColorFromResult( 332 | p.id, r[++i],r[++i],r[++i],r[++i],r[++i], true); 333 | i++; 334 | } else { 335 | i += 6; 336 | } 337 | 338 | // stroke 339 | if(r[i++] == "1"){ // stroked 340 | p.strokeWidth = pf(r[i]); 341 | p.strokeColor = getPaperColorFromResult( 342 | p.id, r[++i],r[++i],r[++i],r[++i],r[++i], false); 343 | i++; 344 | } else { 345 | p.strokeWidth = 0; 346 | p.strokeColor = null; 347 | i += 6; 348 | } 349 | 350 | } else { 351 | var anc = new paper.Point(pf(r[i++]), -pf(r[i++])); 352 | var handleOut = new paper.Point(pf(r[i++]), -pf(r[i++])); 353 | var handleIn = new paper.Point(pf(r[i++]), -pf(r[i++])); 354 | var seg = new paper.Segment(anc, handleIn, handleOut); 355 | p.add(seg); 356 | } 357 | } 358 | }); 359 | }); 360 | 361 | // out button 362 | // serialize paths on a canvas as a series of code 363 | // and eval it to draw the paths on an artboard 364 | $("#btn_out").click(function () { 365 | var paths = getPathsOnCanvas(); 366 | var code = "(function(){"; 367 | 368 | if(paths.length < 1){ 369 | code += "alert('There is nothing to output');"; 370 | } else { 371 | code += "if(isBadCondition()) return;"; 372 | code += "var "; 373 | 374 | for(var i = paths.length - 1; i >= 0; i--){ 375 | var c = paths[i]; 376 | code += "m=new M();"; 377 | 378 | if(c.closed) code += "m.C();"; 379 | 380 | if(c.fillColor != null){ 381 | code += "m.Fc(" + serializePaperColor(c.fillColor, c.id, true) + ");"; 382 | } 383 | 384 | if(c.strokeColor != null && c.strokeWidth > 0){ 385 | code += "m.W(" + f2s(c.strokeWidth) +");"; 386 | code += "m.Sc(" + serializePaperColor(c.strokeColor, c.id, false) + ");"; 387 | } 388 | 389 | if(c.opacity < 1){ 390 | code += "m.Op(" + f2s(c.opacity * 100.0) + ");"; 391 | } 392 | for(var j = 0, jEnd = c.segments.length; j < jEnd; j++){ 393 | var seg = c.segments[j]; 394 | code += "m.B(" + f2s(seg.point.x) + "," + f2s(-seg.point.y) 395 | + "," + f2s(seg.handleIn.x) + "," + f2s(-seg.handleIn.y) 396 | + "," + f2s(seg.handleOut.x) + "," + f2s(-seg.handleOut.y) + ");"; 397 | } 398 | } 399 | } 400 | code += "})();"; 401 | 402 | //console.log(code); 403 | csInterface.evalScript(code); 404 | }); 405 | 406 | // run button 407 | $("#btn_run").click(function(){ 408 | if(runPaperScript){ 409 | try { 410 | runPaperScript(); 411 | } catch(err){ 412 | console.log(err); 413 | alert("ERROR : " + err.name + "\n" + err.message); 414 | } 415 | } else { 416 | alert("nothing to run"); 417 | } 418 | }); 419 | 420 | // option button 421 | // show or hide controls for optional values 422 | $("#btn_opt").click(function () { 423 | $("#div_options").toggle(); 424 | $("#div_screen").toggle(); 425 | }); 426 | 427 | // undo ( < ) button 428 | // you need to call undoManager.keep( *item* ) previously 429 | // to regist an *item* as a target of undo/redo 430 | $("#btn_undo").click(function(e){ 431 | if(undoManager) undoManager.undo(); 432 | }); 433 | 434 | // redo ( > ) button 435 | $("#btn_redo").click(function(e){ 436 | if(undoManager) undoManager.redo(); 437 | }); 438 | 439 | // clear button 440 | $("#btn_clear").click(function(e){ 441 | if(confirm("clear the canvas?")){ 442 | clearCanvas(); 443 | } 444 | }); 445 | 446 | $("#btn_file_ok").click(function(e){ 447 | if(_spec.inputFileObj != null){ 448 | if(_spec.inputFileObj.type.startsWith("image")){ 449 | insertRaster(_spec.inputFileObj); 450 | } else { 451 | insertPaperScript(_spec.inputFileObj); 452 | } 453 | $("#div_dropzone").hide(); 454 | $("#div_screen").hide(); 455 | _spec.inputFileObj = null; 456 | } 457 | }); 458 | $("#btn_file_cancel").click(function(e){ 459 | $("#div_dropzone").hide(); 460 | $("#div_screen").hide(); 461 | _spec.inputFileObj = null; 462 | }); 463 | 464 | $("#fileSelect").change(function(e){ 465 | var fileobj = e.target.files[0]; 466 | var type = fileobj.type; 467 | if(type == "application/x-javascript" 468 | || type == "application/javascript" 469 | || type == "text/javascript"){ 470 | insertPaperScript(fileobj); 471 | } else if(type == "image/png" 472 | || type == "image/jpeg"){ 473 | insertRaster(fileobj); 474 | } else { 475 | alert("Select a JavaScript file or a png/jpeg Image.\n" 476 | + "Selected file is \"" + type + "\"."); 477 | return false; 478 | } 479 | this.value = null; 480 | }); 481 | 482 | $("#btn_file").click(function(e){ 483 | $("#fileSelect").click(); 484 | }); 485 | 486 | // toggles visibility of loaded image 487 | $("#raster_indicator").click(function(e){ 488 | var raster = paper.project.activeLayer.data.raster; 489 | if(raster){ 490 | if(raster.visible){ 491 | raster.visible = false; 492 | $("#raster_indicator").text(" [show image]"); 493 | } else { 494 | raster.visible = true; 495 | $("#raster_indicator").text(" [hide image]"); 496 | } 497 | } 498 | }); 499 | } 500 | 501 | init(); 502 | 503 | }()); 504 | 505 | -------------------------------------------------------------------------------- /com.shspage.csxs.plaincanvas/js/libs/CSInterface.js: -------------------------------------------------------------------------------- 1 | /************************************************************************************************** 2 | * 3 | * ADOBE SYSTEMS INCORPORATED 4 | * Copyright 2013 Adobe Systems Incorporated 5 | * All Rights Reserved. 6 | * 7 | * NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the 8 | * terms of the Adobe license agreement accompanying it. If you have received this file from a 9 | * source other than Adobe, then your use, modification, or distribution of it requires the prior 10 | * written permission of Adobe. 11 | * 12 | **************************************************************************************************/ 13 | 14 | /** CSInterface - v5.2.0 */ 15 | 16 | /** 17 | * Stores constants for the window types supported by the CSXS infrastructure. 18 | */ 19 | function CSXSWindowType() 20 | { 21 | }; 22 | 23 | /** Constant for the CSXS window type Panel. */ 24 | CSXSWindowType._PANEL = "Panel"; 25 | 26 | /** Constant for the CSXS window type Modeless. */ 27 | CSXSWindowType._MODELESS = "Modeless"; 28 | 29 | /** Constant for the CSXS window type ModalDialog. */ 30 | CSXSWindowType._MODAL_DIALOG = "ModalDialog"; 31 | 32 | /** EvalScript error message */ 33 | EvalScript_ErrMessage = "EvalScript error."; 34 | 35 | /** 36 | * @class Version 37 | * Defines a version number with major, minor, micro, and special 38 | * components. The major, minor and micro values are numeric; the special 39 | * value can be any string. 40 | * 41 | * @param major The major version component, a positive integer up to nine digits long. 42 | * @param minor The minor version component, a positive integer up to nine digits long. 43 | * @param micro The micro version component, a positive integer up to nine digits long. 44 | * @param special The special version component, an arbitrary string. 45 | * 46 | * @return A new \c Version object. 47 | */ 48 | function Version(major, minor, micro, special) 49 | { 50 | this.major = major; 51 | this.minor = minor; 52 | this.micro = micro; 53 | this.special = special; 54 | }; 55 | 56 | /** 57 | * The maximum value allowed for a numeric version component. 58 | * This reflects the maximum value allowed in PlugPlug and the manifest schema. 59 | */ 60 | Version.MAX_NUM = 999999999; 61 | 62 | /** 63 | * @class VersionBound 64 | * Defines a boundary for a version range, which associates a \c Version object 65 | * with a flag for whether it is an inclusive or exclusive boundary. 66 | * 67 | * @param version The \c #Version object. 68 | * @param inclusive True if this boundary is inclusive, false if it is exclusive. 69 | * 70 | * @return A new \c VersionBound object. 71 | */ 72 | function VersionBound(version, inclusive) 73 | { 74 | this.version = version; 75 | this.inclusive = inclusive; 76 | }; 77 | 78 | /** 79 | * @class VersionRange 80 | * Defines a range of versions using a lower boundary and optional upper boundary. 81 | * 82 | * @param lowerBound The \c #VersionBound object. 83 | * @param upperBound The \c #VersionBound object, or null for a range with no upper boundary. 84 | * 85 | * @return A new \c VersionRange object. 86 | */ 87 | function VersionRange(lowerBound, upperBound) 88 | { 89 | this.lowerBound = lowerBound; 90 | this.upperBound = upperBound; 91 | }; 92 | 93 | /** 94 | * @class Runtime 95 | * Represents a runtime related to the CEP infrastructure. 96 | * Extensions can declare dependencies on particular 97 | * CEP runtime versions in the extension manifest. 98 | * 99 | * @param name The runtime name. 100 | * @param version A \c #VersionRange object that defines a range of valid versions. 101 | * 102 | * @return A new \c Runtime object. 103 | */ 104 | function Runtime(name, versionRange) 105 | { 106 | this.name = name; 107 | this.versionRange = versionRange; 108 | }; 109 | 110 | /** 111 | * @class Extension 112 | * Encapsulates a CEP-based extension to an Adobe application. 113 | * 114 | * @param id The unique identifier of this extension. 115 | * @param name The localizable display name of this extension. 116 | * @param mainPath The path of the "index.html" file. 117 | * @param basePath The base path of this extension. 118 | * @param windowType The window type of the main window of this extension. 119 | Valid values are defined by \c #CSXSWindowType. 120 | * @param width The default width in pixels of the main window of this extension. 121 | * @param height The default height in pixels of the main window of this extension. 122 | * @param minWidth The minimum width in pixels of the main window of this extension. 123 | * @param minHeight The minimum height in pixels of the main window of this extension. 124 | * @param maxWidth The maximum width in pixels of the main window of this extension. 125 | * @param maxHeight The maximum height in pixels of the main window of this extension. 126 | * @param defaultExtensionDataXml The extension data contained in the default \c ExtensionDispatchInfo section of the extension manifest. 127 | * @param specialExtensionDataXml The extension data contained in the application-specific \c ExtensionDispatchInfo section of the extension manifest. 128 | * @param requiredRuntimeList An array of \c Runtime objects for runtimes required by this extension. 129 | * @param isAutoVisible True if this extension is visible on loading. 130 | * @param isPluginExtension True if this extension has been deployed in the Plugins folder of the host application. 131 | * 132 | * @return A new \c Extension object. 133 | */ 134 | function Extension(id, name, mainPath, basePath, windowType, width, height, minWidth, minHeight, maxWidth, maxHeight, 135 | defaultExtensionDataXml, specialExtensionDataXml, requiredRuntimeList, isAutoVisible, isPluginExtension) 136 | { 137 | this.id = id; 138 | this.name = name; 139 | this.mainPath = mainPath; 140 | this.basePath = basePath; 141 | this.windowType = windowType; 142 | this.width = width; 143 | this.height = height; 144 | this.minWidth = minWidth; 145 | this.minHeight = minHeight; 146 | this.maxWidth = maxWidth; 147 | this.maxHeight = maxHeight; 148 | this.defaultExtensionDataXml = defaultExtensionDataXml; 149 | this.specialExtensionDataXml = specialExtensionDataXml; 150 | this.requiredRuntimeList = requiredRuntimeList; 151 | this.isAutoVisible = isAutoVisible; 152 | this.isPluginExtension = isPluginExtension; 153 | }; 154 | 155 | /** 156 | * @class CSEvent 157 | * A standard JavaScript event, the base class for CEP events. 158 | * 159 | * @param type The name of the event type. 160 | * @param scope The scope of event, can be "GLOBAL" or "APPLICATION". 161 | * @param appId The unique identifier of the application that generated the event. 162 | * @param extensionId The unique identifier of the extension that generated the event. 163 | * 164 | * @return A new \c CSEvent object 165 | */ 166 | function CSEvent(type, scope, appId, extensionId) 167 | { 168 | this.type = type; 169 | this.scope = scope; 170 | this.appId = appId; 171 | this.extensionId = extensionId; 172 | }; 173 | 174 | /** Event-specific data. */ 175 | CSEvent.prototype.data = ""; 176 | 177 | /** 178 | * @class SystemPath 179 | * Stores operating-system-specific location constants for use in the 180 | * \c #CSInterface.getSystemPath() method. 181 | * @return A new \c SystemPath object. 182 | */ 183 | function SystemPath() 184 | { 185 | }; 186 | 187 | /** The path to user data. */ 188 | SystemPath.USER_DATA = "userData"; 189 | 190 | /** The path to common files for Adobe applications. */ 191 | SystemPath.COMMON_FILES = "commonFiles"; 192 | 193 | /** The path to the user's default document folder. */ 194 | SystemPath.MY_DOCUMENTS = "myDocuments"; 195 | 196 | /** @deprecated. Use \c #SystemPath.Extension. */ 197 | SystemPath.APPLICATION = "application"; 198 | 199 | /** The path to current extension. */ 200 | SystemPath.EXTENSION = "extension"; 201 | 202 | /** The path to hosting application's executable. */ 203 | SystemPath.HOST_APPLICATION = "hostApplication"; 204 | 205 | /** 206 | * @class ColorType 207 | * Stores color-type constants. 208 | */ 209 | function ColorType() 210 | { 211 | }; 212 | 213 | /** RGB color type. */ 214 | ColorType.RGB = "rgb"; 215 | 216 | /** Gradient color type. */ 217 | ColorType.GRADIENT = "gradient"; 218 | 219 | /** Null color type. */ 220 | ColorType.NONE = "none"; 221 | 222 | /** 223 | * @class RGBColor 224 | * Stores an RGB color with red, green, blue, and alpha values. 225 | * All values are in the range [0.0 to 255.0]. Invalid numeric values are 226 | * converted to numbers within this range. 227 | * 228 | * @param red The red value, in the range [0.0 to 255.0]. 229 | * @param green The green value, in the range [0.0 to 255.0]. 230 | * @param blue The blue value, in the range [0.0 to 255.0]. 231 | * @param alpha The alpha (transparency) value, in the range [0.0 to 255.0]. 232 | * The default, 255.0, means that the color is fully opaque. 233 | * 234 | * @return A new RGBColor object. 235 | */ 236 | function RGBColor(red, green, blue, alpha) 237 | { 238 | this.red = red; 239 | this.green = green; 240 | this.blue = blue; 241 | this.alpha = alpha; 242 | }; 243 | 244 | /** 245 | * @class Direction 246 | * A point value in which the y component is 0 and the x component 247 | * is positive or negative for a right or left direction, 248 | * or the x component is 0 and the y component is positive or negative for 249 | * an up or down direction. 250 | * 251 | * @param x The horizontal component of the point. 252 | * @param y The vertical component of the point. 253 | * 254 | * @return A new \c Direction object. 255 | */ 256 | function Direction(x, y) 257 | { 258 | this.x = x; 259 | this.y = y; 260 | }; 261 | 262 | /** 263 | * @class GradientStop 264 | * Stores gradient stop information. 265 | * 266 | * @param offset The offset of the gradient stop, in the range [0.0 to 1.0]. 267 | * @param rgbColor The color of the gradient at this point, an \c #RGBColor object. 268 | * 269 | * @return GradientStop object. 270 | */ 271 | function GradientStop(offset, rgbColor) 272 | { 273 | this.offset = offset; 274 | this.rgbColor = rgbColor; 275 | }; 276 | 277 | /** 278 | * @class GradientColor 279 | * Stores gradient color information. 280 | * 281 | * @param type The gradient type, must be "linear". 282 | * @param direction A \c #Direction object for the direction of the gradient 283 | (up, down, right, or left). 284 | * @param numStops The number of stops in the gradient. 285 | * @param gradientStopList An array of \c #GradientStop objects. 286 | * 287 | * @return A new \c GradientColor object. 288 | */ 289 | function GradientColor(type, direction, numStops, arrGradientStop) 290 | { 291 | this.type = type; 292 | this.direction = direction; 293 | this.numStops = numStops; 294 | this.arrGradientStop = arrGradientStop; 295 | }; 296 | 297 | /** 298 | * @class UIColor 299 | * Stores color information, including the type, anti-alias level, and specific color 300 | * values in a color object of an appropriate type. 301 | * 302 | * @param type The color type, 1 for "rgb" and 2 for "gradient". 303 | The supplied color object must correspond to this type. 304 | * @param antialiasLevel The anti-alias level constant. 305 | * @param color A \c #RGBColor or \c #GradientColor object containing specific color information. 306 | * 307 | * @return A new \c UIColor object. 308 | */ 309 | function UIColor(type, antialiasLevel, color) 310 | { 311 | this.type = type; 312 | this.antialiasLevel = antialiasLevel; 313 | this.color = color; 314 | }; 315 | 316 | /** 317 | * @class AppSkinInfo 318 | * Stores window-skin properties, such as color and font. All color parameter values are \c #UIColor objects except that systemHighlightColor is \c #RGBColor object. 319 | * 320 | * @param baseFontFamily The base font family of the application. 321 | * @param baseFontSize The base font size of the application. 322 | * @param appBarBackgroundColor The application bar background color. 323 | * @param panelBackgroundColor The background color of the extension panel. 324 | * @param appBarBackgroundColorSRGB The application bar background color, as sRGB. 325 | * @param panelBackgroundColorSRGB The background color of the extension panel, as sRGB. 326 | * @param systemHighlightColor The operating-system highlight color, as sRGB. 327 | * 328 | * @return AppSkinInfo object. 329 | */ 330 | function AppSkinInfo(baseFontFamily, baseFontSize, appBarBackgroundColor, panelBackgroundColor, appBarBackgroundColorSRGB, panelBackgroundColorSRGB, systemHighlightColor) 331 | { 332 | this.baseFontFamily = baseFontFamily; 333 | this.baseFontSize = baseFontSize; 334 | this.appBarBackgroundColor = appBarBackgroundColor; 335 | this.panelBackgroundColor = panelBackgroundColor; 336 | this.appBarBackgroundColorSRGB = appBarBackgroundColorSRGB; 337 | this.panelBackgroundColorSRGB = panelBackgroundColorSRGB; 338 | this.systemHighlightColor = systemHighlightColor; 339 | }; 340 | 341 | /** 342 | * @class HostEnvironment 343 | * Stores information about the environment in which the extension is loaded. 344 | * 345 | * @param appName The application's name. 346 | * @param appVersion The application's version. 347 | * @param appLocale The application's current license locale. 348 | * @param appUILocale The application's current UI locale. 349 | * @param appId The application's unique identifier. 350 | * @param isAppOnline True if the application is currently online. 351 | * @param appSkinInfo An \c #AppSkinInfo object containing the application's default color and font styles. 352 | * 353 | * @return A new \c HostEnvironment object. 354 | */ 355 | function HostEnvironment(appName, appVersion, appLocale, appUILocale, appId, isAppOnline, appSkinInfo) 356 | { 357 | this.appName = appName; 358 | this.appVersion = appVersion; 359 | this.appLocale = appLocale; 360 | this.appUILocale = appUILocale; 361 | this.appId = appId; 362 | this.isAppOnline = isAppOnline; 363 | this.appSkinInfo = appSkinInfo; 364 | }; 365 | 366 | /** 367 | * @class HostCapabilities 368 | * Stores information about the host capabilities. 369 | * 370 | * @param EXTENDED_PANEL_MENU True if the application supports panel menu. 371 | * @param EXTENDED_PANEL_ICONS True if the application supports panel icon. 372 | * @param DELEGATE_APE_ENGINE True if the application supports delegated APE engine. 373 | * @param SUPPORT_HTML_EXTENSIONS True if the application supports HTML extensions. 374 | * @param DISABLE_FLASH_EXTENSIONS True if the application disables FLASH extensions. 375 | * 376 | * @return A new \c HostCapabilities object. 377 | */ 378 | function HostCapabilities(EXTENDED_PANEL_MENU, EXTENDED_PANEL_ICONS, DELEGATE_APE_ENGINE, SUPPORT_HTML_EXTENSIONS, DISABLE_FLASH_EXTENSIONS) 379 | { 380 | this.EXTENDED_PANEL_MENU = EXTENDED_PANEL_MENU; 381 | this.EXTENDED_PANEL_ICONS = EXTENDED_PANEL_ICONS; 382 | this.DELEGATE_APE_ENGINE = DELEGATE_APE_ENGINE; 383 | this.SUPPORT_HTML_EXTENSIONS = SUPPORT_HTML_EXTENSIONS; 384 | this.DISABLE_FLASH_EXTENSIONS = DISABLE_FLASH_EXTENSIONS; // Since 5.0.0 385 | }; 386 | 387 | /** 388 | * @class ApiVersion 389 | * Stores current api version. 390 | * 391 | * Since 4.2.0 392 | * 393 | * @param major The major version 394 | * @param minor The minor version. 395 | * @param micro The micro version. 396 | * 397 | * @return ApiVersion object. 398 | */ 399 | function ApiVersion(major, minor, micro) 400 | { 401 | this.major = major; 402 | this.minor = minor; 403 | this.micro = micro; 404 | }; 405 | 406 | /** 407 | * @class MenuItemStatus 408 | * Stores flyout menu item status 409 | * 410 | * Since 5.2.0 411 | * 412 | * @param menuItemLabel The menu item label. 413 | * @param enabled True if user wants to enable the menu item. 414 | * @param checked True if user wants to check the menu item. 415 | * 416 | * @return MenuItemStatus object. 417 | */ 418 | function MenuItemStatus(menuItemLabel, enabled, checked) 419 | { 420 | this.menuItemLabel = menuItemLabel; 421 | this.enabled = enabled; 422 | this.checked = checked; 423 | }; 424 | 425 | /** 426 | * @class ContextMenuItemStatus 427 | * Stores the status of the context menu item. 428 | * 429 | * Since 5.2.0 430 | * 431 | * @param menuItemID The menu item id. 432 | * @param enabled True if user wants to enable the menu item. 433 | * @param checked True if user wants to check the menu item. 434 | * 435 | * @return MenuItemStatus object. 436 | */ 437 | function ContextMenuItemStatus(menuItemID, enabled, checked) 438 | { 439 | this.menuItemID = menuItemID; 440 | this.enabled = enabled; 441 | this.checked = checked; 442 | }; 443 | //------------------------------ CSInterface ---------------------------------- 444 | 445 | /** 446 | * @class CSInterface 447 | * This is the entry point to the CEP extensibility infrastructure. 448 | * Instantiate this object and use it to: 449 | * 454 | * 455 | * @return A new \c CSInterface object 456 | */ 457 | function CSInterface() 458 | { 459 | }; 460 | 461 | /** 462 | * User can add this event listener to handle native application theme color changes. 463 | * Callback function gives extensions ability to fine-tune their theme color after the 464 | * global theme color has been changed. 465 | * The callback function should be like below: 466 | * 467 | * @example 468 | * // event is a CSEvent object, but user can ignore it. 469 | * function OnAppThemeColorChanged(event) 470 | * { 471 | * // Should get a latest HostEnvironment object from application. 472 | * var skinInfo = JSON.parse(window.__adobe_cep__.getHostEnvironment()).appSkinInfo; 473 | * // Gets the style information such as color info from the skinInfo, 474 | * // and redraw all UI controls of your extension according to the style info. 475 | * } 476 | */ 477 | CSInterface.THEME_COLOR_CHANGED_EVENT = "com.adobe.csxs.events.ThemeColorChanged"; 478 | 479 | /** The host environment data object. */ 480 | CSInterface.prototype.hostEnvironment = JSON.parse(window.__adobe_cep__.getHostEnvironment()); 481 | 482 | /** Retrieves information about the host environment in which the 483 | * extension is currently running. 484 | * 485 | * @return A \c #HostEnvironment object. 486 | */ 487 | CSInterface.prototype.getHostEnvironment = function() 488 | { 489 | this.hostEnvironment = JSON.parse(window.__adobe_cep__.getHostEnvironment()); 490 | return this.hostEnvironment; 491 | }; 492 | 493 | /** Closes this extension. */ 494 | CSInterface.prototype.closeExtension = function() 495 | { 496 | window.__adobe_cep__.closeExtension(); 497 | }; 498 | 499 | /** 500 | * Retrieves a path for which a constant is defined in the system. 501 | * 502 | * @param pathType The path-type constant defined in \c #SystemPath , 503 | * 504 | * @return The platform-specific system path string. 505 | */ 506 | CSInterface.prototype.getSystemPath = function(pathType) 507 | { 508 | var path = decodeURI(window.__adobe_cep__.getSystemPath(pathType)); 509 | var OSVersion = this.getOSInformation(); 510 | if (OSVersion.indexOf("Windows") >= 0) 511 | { 512 | path = path.replace("file:///", ""); 513 | } 514 | else if (OSVersion.indexOf("Mac") >= 0) 515 | { 516 | path = path.replace("file://", ""); 517 | } 518 | return path; 519 | }; 520 | 521 | /** 522 | * Evaluates a JavaScript script, which can use the JavaScript DOM 523 | * of the host application. 524 | * 525 | * @param script The JavaScript script. 526 | * @param callback Optional. A callback function that receives the result of execution. 527 | * If execution fails, the callback function receives the error message \c EvalScript_ErrMessage. 528 | */ 529 | CSInterface.prototype.evalScript = function(script, callback) 530 | { 531 | if(callback == null || callback == undefined) 532 | { 533 | callback = function(result){}; 534 | } 535 | window.__adobe_cep__.evalScript(script, callback); 536 | }; 537 | 538 | /** 539 | * Retrieves the unique identifier of the application. 540 | * in which the extension is currently running. 541 | * 542 | * @return The unique ID string. 543 | */ 544 | CSInterface.prototype.getApplicationID = function() 545 | { 546 | var appId = this.hostEnvironment.appId; 547 | return appId; 548 | }; 549 | 550 | /** 551 | * Retrieves host capability information for the application 552 | * in which the extension is currently running. 553 | * 554 | * @return A \c #HostCapabilities object. 555 | */ 556 | CSInterface.prototype.getHostCapabilities = function() 557 | { 558 | var hostCapabilities = JSON.parse(window.__adobe_cep__.getHostCapabilities() ); 559 | return hostCapabilities; 560 | }; 561 | 562 | /** 563 | * Triggers a CEP event programmatically. Yoy can use it to dispatch 564 | * an event of a predefined type, or of a type you have defined. 565 | * 566 | * @param event A \c CSEvent object. 567 | */ 568 | CSInterface.prototype.dispatchEvent = function(event) 569 | { 570 | if (typeof event.data == "object") 571 | { 572 | event.data = JSON.stringify(event.data); 573 | } 574 | 575 | window.__adobe_cep__.dispatchEvent(event); 576 | }; 577 | 578 | /** 579 | * Registers an interest in a CEP event of a particular type, and 580 | * assigns an event handler. 581 | * The event infrastructure notifies your extension when events of this type occur, 582 | * passing the event object to the registered handler function. 583 | * 584 | * @param type The name of the event type of interest. 585 | * @param listener The JavaScript handler function or method. 586 | * @param obj Optional, the object containing the handler method, if any. 587 | * Default is null. 588 | */ 589 | CSInterface.prototype.addEventListener = function(type, listener, obj) 590 | { 591 | window.__adobe_cep__.addEventListener(type, listener, obj); 592 | }; 593 | 594 | /** 595 | * Removes a registered event listener. 596 | * 597 | * @param type The name of the event type of interest. 598 | * @param listener The JavaScript handler function or method that was registered. 599 | * @param obj Optional, the object containing the handler method, if any. 600 | * Default is null. 601 | */ 602 | CSInterface.prototype.removeEventListener = function(type, listener, obj) 603 | { 604 | window.__adobe_cep__.removeEventListener(type, listener, obj); 605 | }; 606 | 607 | /** 608 | * Loads and launches another extension, or activates the extension if it is already loaded. 609 | * 610 | * @param extensionId The extension's unique identifier. 611 | * @param startupParams Not currently used, pass "". 612 | * 613 | * @example 614 | * To launch the extension "help" with ID "HLP" from this extension, call: 615 | * requestOpenExtension("HLP", ""); 616 | * 617 | */ 618 | CSInterface.prototype.requestOpenExtension = function(extensionId, params) 619 | { 620 | window.__adobe_cep__.requestOpenExtension(extensionId, params); 621 | }; 622 | 623 | /** 624 | * Retrieves the list of extensions currently loaded in the current host application. 625 | * The extension list is initialized once, and remains the same during the lifetime 626 | * of the CEP session. 627 | * 628 | * @param extensionIds Optional, an array of unique identifiers for extensions of interest. 629 | * If omitted, retrieves data for all extensions. 630 | * 631 | * @return Zero or more \c #Extension objects. 632 | */ 633 | CSInterface.prototype.getExtensions = function(extensionIds) 634 | { 635 | var extensionIdsStr = JSON.stringify(extensionIds); 636 | var extensionsStr = window.__adobe_cep__.getExtensions(extensionIdsStr); 637 | 638 | var extensions = JSON.parse(extensionsStr); 639 | return extensions; 640 | }; 641 | 642 | /** 643 | * Retrieves network-related preferences. 644 | * 645 | * @return A JavaScript object containing network preferences. 646 | */ 647 | CSInterface.prototype.getNetworkPreferences = function() 648 | { 649 | var result = window.__adobe_cep__.getNetworkPreferences(); 650 | var networkPre = JSON.parse(result); 651 | 652 | return networkPre; 653 | }; 654 | 655 | /** 656 | * Initializes the resource bundle for this extension with property values 657 | * for the current application and locale. 658 | * To support multiple locales, you must define a property file for each locale, 659 | * containing keyed display-string values for that locale. 660 | * See localization documentation for Extension Builder and related products. 661 | * 662 | * Keys can be in the 663 | * form key.value="localized string", for use in HTML text elements. 664 | * For example, in this input element, the localized \c key.value string is displayed 665 | * instead of the empty \c value string: 666 | * 667 | * 668 | * 669 | * @return An object containing the resource bundle information. 670 | */ 671 | CSInterface.prototype.initResourceBundle = function() 672 | { 673 | var resourceBundle = JSON.parse(window.__adobe_cep__.initResourceBundle()); 674 | var resElms = document.querySelectorAll('[data-locale]'); 675 | for (var n = 0; n < resElms.length; n++) 676 | { 677 | var resEl = resElms[n]; 678 | // Get the resource key from the element. 679 | var resKey = resEl.getAttribute('data-locale'); 680 | if (resKey) 681 | { 682 | // Get all the resources that start with the key. 683 | for (var key in resourceBundle) 684 | { 685 | if (key.indexOf(resKey) == 0) 686 | { 687 | var resValue = resourceBundle[key]; 688 | if (key.length == resKey.length) 689 | { 690 | resEl.innerHTML = resValue; 691 | } 692 | else if ('.' == key.charAt(resKey.length)) 693 | { 694 | var attrKey = key.substring(resKey.length + 1); 695 | resEl[attrKey] = resValue; 696 | } 697 | } 698 | } 699 | } 700 | } 701 | return resourceBundle; 702 | }; 703 | 704 | /** 705 | * Writes installation information to a file. 706 | * 707 | * @return The file path. 708 | */ 709 | CSInterface.prototype.dumpInstallationInfo = function() 710 | { 711 | return window.__adobe_cep__.dumpInstallationInfo(); 712 | }; 713 | 714 | /** 715 | * Retrieves version information for the current Operating System, 716 | * See http://www.useragentstring.com/pages/Chrome/ for Chrome \c navigator.userAgent values. 717 | * 718 | * @return A string containing the OS version, or "unknown Operation System". 719 | * If user customizes the User Agent by setting CEF command parameter "--user-agent", only 720 | * "Mac OS X" or "Windows" will be returned. 721 | */ 722 | CSInterface.prototype.getOSInformation = function() 723 | { 724 | var userAgent = navigator.userAgent; 725 | 726 | if ((navigator.platform == "Win32") || (navigator.platform == "Windows")) 727 | { 728 | var winVersion = "Windows"; 729 | var winBit = ""; 730 | if (userAgent.indexOf("Windows") > -1) 731 | { 732 | if (userAgent.indexOf("Windows NT 5.0") > -1) 733 | { 734 | winVersion = "Windows 2000 "; 735 | } 736 | else if (userAgent.indexOf("Windows NT 5.1") > -1) 737 | { 738 | winVersion = "Windows XP "; 739 | } 740 | else if (userAgent.indexOf("Windows NT 5.2") > -1) 741 | { 742 | winVersion = "Windows Server 2003 "; 743 | } 744 | else if (userAgent.indexOf("Windows NT 6.0") > -1) 745 | { 746 | winVersion = "Windows Vista "; 747 | } 748 | else if (userAgent.indexOf("Windows NT 6.1") > -1) 749 | { 750 | winVersion = "Windows 7 "; 751 | } 752 | else if (userAgent.indexOf("Windows NT 6.2") > -1) 753 | { 754 | winVersion = "Windows 8 "; 755 | } 756 | 757 | if (userAgent.indexOf("WOW64") > -1) 758 | { 759 | winBit = "64-bit"; 760 | } 761 | else 762 | { 763 | winBit = "32-bit"; 764 | } 765 | } 766 | 767 | return winVersion + winBit; 768 | } 769 | else if ((navigator.platform == "MacIntel") || (navigator.platform == "Macintosh")) 770 | { 771 | var result = "Mac OS X"; 772 | var agentStr = new String(); 773 | agentStr = userAgent; 774 | if (agentStr.indexOf("Mac OS X") > -1) 775 | { 776 | var verLength = agentStr.indexOf(")") - agentStr.indexOf("Mac OS X"); 777 | var verStr = agentStr.substr(agentStr.indexOf("Mac OS X"), verLength); 778 | result = verStr.replace("_", "."); 779 | result = result.replace("_", "."); 780 | } 781 | 782 | return result; 783 | } 784 | 785 | return "Unknown Operation System"; 786 | }; 787 | 788 | /** 789 | * Opens a page in the default system browser. 790 | * 791 | * Since 4.2.0 792 | * 793 | * @param url The URL of the page/file to open, or the email address. 794 | * Must use HTTP/HTTPS/file/mailto protocol. For example: 795 | * "http://www.adobe.com" 796 | * "https://github.com" 797 | * "file:///C:/log.txt" 798 | * "mailto:test@adobe.com" 799 | * 800 | * @return One of these error codes:\n 801 | * \n 807 | */ 808 | CSInterface.prototype.openURLInDefaultBrowser = function(url) 809 | { 810 | return cep.util.openURLInDefaultBrowser(url); 811 | }; 812 | 813 | /** 814 | * Retrieves extension ID. 815 | * 816 | * Since 4.2.0 817 | * 818 | * @return extension ID. 819 | */ 820 | CSInterface.prototype.getExtensionID = function() 821 | { 822 | return window.__adobe_cep__.getExtensionId(); 823 | }; 824 | 825 | /** 826 | * Retrieves the scale factor of screen. 827 | * On Windows platform, the value of scale factor might be different from operating system's scale factor, 828 | * since host application may use its self-defined scale factor. 829 | * 830 | * Since 4.2.0 831 | * 832 | * @return One of the following integer. 833 | * \n 838 | */ 839 | CSInterface.prototype.getScaleFactor = function() 840 | { 841 | return window.__adobe_cep__.getScaleFactor(); 842 | }; 843 | 844 | /** 845 | * Set a handler to detect any changes of scale factor. This only works on Mac. 846 | * 847 | * Since 4.2.0 848 | * 849 | * @param handler The function to be called when scale factor is changed. 850 | * 851 | */ 852 | CSInterface.prototype.setScaleFactorChangedHandler = function(handler) 853 | { 854 | window.__adobe_cep__.setScaleFactorChangedHandler(handler); 855 | }; 856 | 857 | /** 858 | * Retrieves current API version. 859 | * 860 | * Since 4.2.0 861 | * 862 | * @return ApiVersion object. 863 | * 864 | */ 865 | CSInterface.prototype.getCurrentApiVersion = function() 866 | { 867 | var apiVersion = JSON.parse(window.__adobe_cep__.getCurrentApiVersion()); 868 | return apiVersion; 869 | }; 870 | 871 | /** 872 | * Set panel flyout menu by an XML. 873 | * 874 | * Since 5.2.0 875 | * 876 | * If user wants to be noticed when clicking an menu item, user needs to register "com.adobe.csxs.events.flyoutMenuClicked" Event by calling AddEventListener. 877 | * When an menu item is clicked, the event callback function will be called. 878 | * The "data" attribute of event is an object which contains "menuId" and "menuName" attributes. 879 | * 880 | * @param menu A XML string which describes menu structure. 881 | * An example menu XML: 882 | * 883 | * 884 | * 885 | * 886 | * 887 | * 888 | * 889 | * 890 | * 891 | * 892 | * 893 | * 894 | */ 895 | CSInterface.prototype.setPanelFlyoutMenu = function(menu) 896 | { 897 | if ("string" != typeof menu) 898 | { 899 | return; 900 | } 901 | 902 | window.__adobe_cep__.invokeSync("setPanelFlyoutMenu", menu); 903 | }; 904 | 905 | /** 906 | * Updates a menu item in the extension window's flyout menu, by setting the enabled 907 | * and selection status. 908 | * 909 | * Since 5.2.0 910 | * 911 | * @param menuItemLabel The menu item label. 912 | * @param enabled True to enable the item, false to disable it (gray it out). 913 | * @param checked True to select the item, false to deselect it. 914 | * 915 | * @return false when the host application does not support this functionality (HostCapabilities.EXTENDED_PANEL_MENU is false). 916 | * Fails silently if menu label is invalid. 917 | * 918 | * @see HostCapabilities.EXTENDED_PANEL_MENU 919 | */ 920 | CSInterface.prototype.updatePanelMenuItem = function(menuItemLabel, enabled, checked) 921 | { 922 | var ret = false; 923 | if (this.getHostCapabilities().EXTENDED_PANEL_MENU) 924 | { 925 | var itemStatus = new MenuItemStatus(menuItemLabel, enabled, checked); 926 | ret = window.__adobe_cep__.invokeSync("updatePanelMenuItem", JSON.stringify(itemStatus)); 927 | } 928 | return ret; 929 | }; 930 | 931 | 932 | /** 933 | * Set context menu by XML string. 934 | * 935 | * Since 5.2.0 936 | * 937 | * There are a number of conventions used to communicate what type of menu item to create and how it should be handled. 938 | * - an item without menu ID or menu name is disabled and is not shown. 939 | * - if the item name is "---" (three hyphens) then it is treated as a separator. The menu ID in this case will always be NULL. 940 | * - Checkable attribute takes precedence over Checked attribute. 941 | * 942 | * @param menu A XML string which describes menu structure. 943 | * @param callback The callback function which is called when a menu item is clicked. The only parameter is the returned ID of clicked menu item. 944 | * 945 | * An example menu XML: 946 | * 947 | * 948 | * 949 | * 950 | * 951 | * 952 | * 953 | * 954 | * 955 | * 956 | * 957 | */ 958 | CSInterface.prototype.setContextMenu = function(menu, callback) 959 | { 960 | if ("string" != typeof menu) 961 | { 962 | return; 963 | } 964 | 965 | window.__adobe_cep__.invokeAsync("setContextMenu", menu, callback); 966 | }; 967 | 968 | /** 969 | * Updates a context menu item by setting the enabled and selection status. 970 | * 971 | * Since 5.2.0 972 | * 973 | * @param menuItemID The menu item ID. 974 | * @param enabled True to enable the item, false to disable it (gray it out). 975 | * @param checked True to select the item, false to deselect it. 976 | */ 977 | CSInterface.prototype.updateContextMenuItem = function(menuItemID, enabled, checked) 978 | { 979 | var itemStatus = new ContextMenuItemStatus(menuItemID, enabled, checked); 980 | ret = window.__adobe_cep__.invokeSync("updateContextMenuItem", JSON.stringify(itemStatus)); 981 | }; -------------------------------------------------------------------------------- /com.shspage.csxs.plaincanvas/js/libs/jquery-3.7.1.slim.min.js: -------------------------------------------------------------------------------- 1 | /*! jQuery v3.7.1 -ajax,-ajax/jsonp,-ajax/load,-ajax/script,-ajax/var/location,-ajax/var/nonce,-ajax/var/rquery,-ajax/xhr,-manipulation/_evalUrl,-deprecated/ajax-event-alias,-effects,-effects/animatedSelector,-effects/Tween | (c) OpenJS Foundation and other contributors | jquery.org/license */ 2 | !function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(ie,e){"use strict";var oe=[],r=Object.getPrototypeOf,ae=oe.slice,g=oe.flat?function(e){return oe.flat.call(e)}:function(e){return oe.concat.apply([],e)},s=oe.push,se=oe.indexOf,n={},i=n.toString,ue=n.hasOwnProperty,o=ue.toString,a=o.call(Object),le={},v=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},y=function(e){return null!=e&&e===e.window},m=ie.document,u={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||m).createElement("script");if(o.text=e,t)for(r in u)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function x(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[i.call(e)]||"object":typeof e}var t="3.7.1 -ajax,-ajax/jsonp,-ajax/load,-ajax/script,-ajax/var/location,-ajax/var/nonce,-ajax/var/rquery,-ajax/xhr,-manipulation/_evalUrl,-deprecated/ajax-event-alias,-effects,-effects/animatedSelector,-effects/Tween",l=/HTML$/i,ce=function(e,t){return new ce.fn.init(e,t)};function c(e){var t=!!e&&"length"in e&&e.length,n=x(e);return!v(e)&&!y(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+ge+")"+ge+"*"),b=new RegExp(ge+"|>"),A=new RegExp(g),D=new RegExp("^"+t+"$"),N={ID:new RegExp("^#("+t+")"),CLASS:new RegExp("^\\.("+t+")"),TAG:new RegExp("^("+t+"|[*])"),ATTR:new RegExp("^"+d),PSEUDO:new RegExp("^"+g),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+ge+"*(even|odd|(([+-]|)(\\d*)n|)"+ge+"*(?:([+-]|)"+ge+"*(\\d+)|))"+ge+"*\\)|)","i"),bool:new RegExp("^(?:"+f+")$","i"),needsContext:new RegExp("^"+ge+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+ge+"*((?:-\\d)?\\d*)"+ge+"*\\)|)(?=[^-]|$)","i")},L=/^(?:input|select|textarea|button)$/i,j=/^h\d$/i,O=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,P=/[+~]/,H=new RegExp("\\\\[\\da-fA-F]{1,6}"+ge+"?|\\\\([^\\r\\n\\f])","g"),q=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},R=function(){V()},M=K(function(e){return!0===e.disabled&&fe(e,"fieldset")},{dir:"parentNode",next:"legend"});try{E.apply(oe=ae.call(ye.childNodes),ye.childNodes),oe[ye.childNodes.length].nodeType}catch(e){E={apply:function(e,t){me.apply(e,ae.call(t))},call:function(e){me.apply(e,ae.call(arguments,1))}}}function I(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,d=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==d&&9!==d&&11!==d)return n;if(!r&&(V(e),e=e||C,T)){if(11!==d&&(u=O.exec(t)))if(i=u[1]){if(9===d){if(!(a=e.getElementById(i)))return n;if(a.id===i)return E.call(n,a),n}else if(f&&(a=f.getElementById(i))&&I.contains(e,a)&&a.id===i)return E.call(n,a),n}else{if(u[2])return E.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&e.getElementsByClassName)return E.apply(n,e.getElementsByClassName(i)),n}if(!(h[t+" "]||p&&p.test(t))){if(c=t,f=e,1===d&&(b.test(t)||m.test(t))){(f=P.test(t)&&X(e.parentNode)||e)==e&&le.scope||((s=e.getAttribute("id"))?s=ce.escapeSelector(s):e.setAttribute("id",s=k)),o=(l=Y(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+G(l[o]);c=l.join(",")}try{return E.apply(n,f.querySelectorAll(c)),n}catch(e){h(t,!0)}finally{s===k&&e.removeAttribute("id")}}}return re(t.replace(ve,"$1"),e,n,r)}function W(){var r=[];return function e(t,n){return r.push(t+" ")>x.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function B(e){return e[k]=!0,e}function F(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function $(t){return function(e){return fe(e,"input")&&e.type===t}}function _(t){return function(e){return(fe(e,"input")||fe(e,"button"))&&e.type===t}}function z(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&M(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function U(a){return B(function(o){return o=+o,B(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function X(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}function V(e){var t,n=e?e.ownerDocument||e:ye;return n!=C&&9===n.nodeType&&n.documentElement&&(r=(C=n).documentElement,T=!ce.isXMLDoc(C),i=r.matches||r.webkitMatchesSelector||r.msMatchesSelector,r.msMatchesSelector&&ye!=C&&(t=C.defaultView)&&t.top!==t&&t.addEventListener("unload",R),le.getById=F(function(e){return r.appendChild(e).id=ce.expando,!C.getElementsByName||!C.getElementsByName(ce.expando).length}),le.disconnectedMatch=F(function(e){return i.call(e,"*")}),le.scope=F(function(){return C.querySelectorAll(":scope")}),le.cssHas=F(function(){try{return C.querySelector(":has(*,:jqfake)"),!1}catch(e){return!0}}),le.getById?(x.filter.ID=function(e){var t=e.replace(H,q);return function(e){return e.getAttribute("id")===t}},x.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&T){var n=t.getElementById(e);return n?[n]:[]}}):(x.filter.ID=function(e){var n=e.replace(H,q);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},x.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&T){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),x.find.TAG=function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):t.querySelectorAll(e)},x.find.CLASS=function(e,t){if("undefined"!=typeof t.getElementsByClassName&&T)return t.getElementsByClassName(e)},p=[],F(function(e){var t;r.appendChild(e).innerHTML="",e.querySelectorAll("[selected]").length||p.push("\\["+ge+"*(?:value|"+f+")"),e.querySelectorAll("[id~="+k+"-]").length||p.push("~="),e.querySelectorAll("a#"+k+"+*").length||p.push(".#.+[+~]"),e.querySelectorAll(":checked").length||p.push(":checked"),(t=C.createElement("input")).setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),r.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&p.push(":enabled",":disabled"),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||p.push("\\["+ge+"*name"+ge+"*="+ge+"*(?:''|\"\")")}),le.cssHas||p.push(":has"),p=p.length&&new RegExp(p.join("|")),l=function(e,t){if(e===t)return a=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!le.sortDetached&&t.compareDocumentPosition(e)===n?e===C||e.ownerDocument==ye&&I.contains(ye,e)?-1:t===C||t.ownerDocument==ye&&I.contains(ye,t)?1:o?se.call(o,e)-se.call(o,t):0:4&n?-1:1)}),C}for(e in I.matches=function(e,t){return I(e,null,null,t)},I.matchesSelector=function(e,t){if(V(e),T&&!h[t+" "]&&(!p||!p.test(t)))try{var n=i.call(e,t);if(n||le.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){h(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(H,q),e[3]=(e[3]||e[4]||e[5]||"").replace(H,q),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||I.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&I.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return N.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&A.test(n)&&(t=Y(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(H,q).toLowerCase();return"*"===e?function(){return!0}:function(e){return fe(e,t)}},CLASS:function(e){var t=s[e+" "];return t||(t=new RegExp("(^|"+ge+")"+e+"("+ge+"|$)"))&&s(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=I.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function T(e,n,r){return v(n)?ce.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?ce.grep(e,function(e){return e===n!==r}):"string"!=typeof n?ce.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(ce.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||E,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:k.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof ce?t[0]:t,ce.merge(this,ce.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:m,!0)),C.test(r[1])&&ce.isPlainObject(t))for(r in t)v(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=m.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):v(e)?void 0!==n.ready?n.ready(e):e(ce):ce.makeArray(e,this)}).prototype=ce.fn,E=ce(m);var S=/^(?:parents|prev(?:Until|All))/,A={children:!0,contents:!0,next:!0,prev:!0};function D(e,t){while((e=e[t])&&1!==e.nodeType);return e}ce.fn.extend({has:function(e){var t=ce(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,Ce=/^$|^module$|\/(?:java|ecma)script/i;re=m.createDocumentFragment().appendChild(m.createElement("div")),(be=m.createElement("input")).setAttribute("type","radio"),be.setAttribute("checked","checked"),be.setAttribute("name","t"),re.appendChild(be),le.checkClone=re.cloneNode(!0).cloneNode(!0).lastChild.checked,re.innerHTML="",le.noCloneChecked=!!re.cloneNode(!0).lastChild.defaultValue,re.innerHTML="",le.option=!!re.lastChild;var Te={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function Ee(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&fe(e,t)?ce.merge([e],n):n}function ke(e,t){for(var n=0,r=e.length;n",""]);var Se=/<|&#?\w+;/;function Ae(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),d=[],p=0,h=e.length;p\s*$/g;function Re(e,t){return fe(e,"table")&&fe(11!==t.nodeType?t:t.firstChild,"tr")&&ce(e).children("tbody")[0]||e}function Me(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function Ie(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function We(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(_.hasData(e)&&(s=_.get(e).events))for(i in _.remove(t,"handle events"),s)for(n=0,r=s[i].length;n
",2===yt.childNodes.length),ce.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(le.createHTMLDocument?((r=(t=m.implementation.createHTMLDocument("")).createElement("base")).href=m.location.href,t.head.appendChild(r)):t=m),o=!n&&[],(i=C.exec(e))?[t.createElement(i[1])]:(i=Ae([e],t,o),o&&o.length&&ce(o).remove(),ce.merge([],i.childNodes)));var r,i,o},ce.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=ce.css(e,"position"),c=ce(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=ce.css(e,"top"),u=ce.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),v(t)&&(t=t.call(e,n,ce.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},ce.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){ce.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===ce.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===ce.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=ce(e).offset()).top+=ce.css(e,"borderTopWidth",!0),i.left+=ce.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-ce.css(r,"marginTop",!0),left:t.left-i.left-ce.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===ce.css(e,"position"))e=e.offsetParent;return e||K})}}),ce.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;ce.fn[t]=function(e){return R(this,function(e,t,n){var r;if(y(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),ce.each(["top","left"],function(e,n){ce.cssHooks[n]=Qe(le.pixelPosition,function(e,t){if(t)return t=Ve(e,n),$e.test(t)?ce(e).position()[n]+"px":t})}),ce.each({Height:"height",Width:"width"},function(a,s){ce.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){ce.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return R(this,function(e,t,n){var r;return y(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?ce.css(e,t,i):ce.style(e,t,n,i)},s,n?e:void 0,n)}})}),ce.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.on("mouseenter",e).on("mouseleave",t||e)}}),ce.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){ce.fn[n]=function(e,t){return 0