GitHub Viewer
/*
|I|d| |B|a|r|c|o|d|e|
An InDesign script for creating EAN-13 barcodes
https://github.com/GitBruno/id_barcode
Copyright (c) 2016 - 2017 Bruno Herfst, http://brunoherfst.com
Copyright (c) 2011 Nick Morgan, http://skilldrick.co.uk
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#targetengine 'EAN13_Barcode_Creator';
$.localize = false; // enable ExtendScript localisation engine
var version = 0.5;
var debug = true;
var Barcode_Settings_Schema = {
"type": "object",
"$schema": "http://json-schema.org/draft-06/schema#",
"properties": {
"name": {
"$id": "/properties/name",
"type": "string",
"title": "Name",
"description": "The name of the preset, this will show in UI drop-down.",
"default": "New Preset",
"examples": [
"My Barcode Preset"
]
},
"version": {
"$id": "/properties/version",
"type": "number",
"minimum": 0.1,
"title": "Version",
"description": "Script version that generated the preset.",
"default": version,
"examples": [
1.2
]
},
"pageIndex": {
"$id": "/properties/pageIndex",
"type": "integer",
"minimum": -1,
"title": "Pageindex",
"description": "An explanation about the purpose of this instance.",
"default": 0,
"examples": [
5
]
},
"ean": {
"$id": "/properties/ean",
"type": "string",
"title": "Ean",
"description": "The EAN number including checkdigit (Can contain X)",
"default": "",
"examples": [
"5901234123457"
]
},
"addon": {
"$id": "/properties/addon",
"type": "string",
"title": "Addon",
"description": "2-digit EAN-2, or 5-digit EAN-5 supplemental code.",
"default": "",
"examples": [
"12"
]
},
"codeFont": {
"$id": "/properties/codeFont",
"type": "string",
"title": "Codefont",
"description": "The font name and style to be used by for the machine readable numbers.",
"default": "",
"examples": [
"OCR-B\tRegular"
]
},
"readFont": {
"$id": "/properties/readFont",
"type": "string",
"title": "Readfont",
"description": "The font name and style to be used by for the human readable numbers.",
"default": "",
"examples": [
"OCR-B\tRegular"
]
},
"readFontTracking": {
"$id": "/properties/readFontTracking",
"type": "integer",
"title": "Readfonttracking",
"description": "The tracking to be aplied to the human readable font",
"default": 0,
"examples": [
-120
]
},
"whiteBox": {
"$id": "/properties/whiteBox",
"type": "boolean",
"title": "Whitebox",
"description": "Should the barcode have a white/paper coloured background.",
"default": false,
"examples": [
true
]
},
"humanReadable": {
"$id": "/properties/humanReadable",
"type": "boolean",
"title": "Humanreadable",
"description": "Add the human readable string to the barcode?",
"default": false,
"examples": [
true
]
},
"alignTo": {
"$id": "/properties/alignTo",
"type": "string",
"title": "Alignto",
"description": "Align barcode to something?",
"default": "",
"examples": [
"Page",
"Page Margins",
"selection"
]
},
"selectionBounds": {
"$id": "/properties/selectionBounds",
"type": "array",
"description": "Array of Measurement Units in format [y1, x1, y2, x2]",
"maxItems": 4,
"minItems": 4,
"items": {
"$id": "/properties/selectionBounds/items",
"type": "number",
"title": "geometricBounds",
"description": "coordinate value",
"default": 0,
"examples": [
135.456, -20.34, 15
]
}
},
"refPoint": {
"$id": "/properties/refPoint",
"type": "string",
"title": "Refpoint",
"description": "A reference point for barcode alignment.",
"default": "",
"examples": [
"BOTTOM_RIGHT_ANCHOR"
]
},
"offset": {
"$id": "/properties/offset",
"type": "object",
"description": "A offset used when drawing the barcode.",
"properties": {
"x": {
"$id": "/properties/offset/properties/x",
"type": "number",
"title": "X",
"default": 0,
"examples": [
-20.255
]
},
"y": {
"$id": "/properties/offset/properties/y",
"type": "number",
"title": "Y",
"default": 0,
"examples": [
12
]
}
}
},
"humanReadableStr": {
"$id": "/properties/humanReadableStr",
"type": "string",
"title": "Humanreadablestr",
"description": "The human readable string to be used.",
"default": "",
"examples": [
"ISSN: 0123-460"
]
},
"dpi": {
"$id": "/properties/dpi",
"type": "integer",
"title": "Dpi",
"description": "The DPI of output device.",
"default": 0,
"examples": [
300
]
},
"bwr": {
"$id": "/properties/bwr",
"type": "object",
"description": "Bar Width Reduction value",
"properties": {
"value": {
"$id": "/properties/bwr/properties/value",
"type": "number",
"title": "Value",
"default": 0,
"examples": [
0, -0.002, 0.0125
]
},
"unit": {
"$id": "/properties/bwr/properties/unit",
"type": "string",
"title": "Unit",
"description": "Measure Unit",
"default": "",
"examples": [
"inch"
]
}
}
},
"createOulines": {
"$id": "/properties/createOulines",
"type": "boolean",
"title": "Createoulines",
"description": "Convert text to outlines?",
"default": true
},
"heightPercent": {
"$id": "/properties/heightPercent",
"type": "integer",
"title": "Heightpercent",
"description": "Adjust the height of the barcode/",
"default": 100
},
"scalePercent": {
"$id": "/properties/scalePercent",
"type": "integer",
"title": "Scalepercent",
"description": "Adjust scale of barcode.",
"default": 100
},
"qZoneIndicator": {
"$id": "/properties/qZoneIndicator",
"type": "boolean",
"title": "Qzoneindicator",
"description": "Add light margin indicator",
"default": true
},
"addQuietZoneMargin": {
"$id": "/properties/addQuietZoneMargin",
"type": "integer", // Change to array [top, right, bottom, left]
"title": "Addquietzonemargin",
"description": "Add extra quite zone or margins to the barcode.",
"default": 0,
"examples": [
10
]
}
}
}
// Template presets
var standardPresets = [ { name : "Penguin Books",
version : version,
pageIndex : -1,
ean : "",
addon : "",
codeFont : "OCR BARCODE\tRegular",
readFont : "OCR BARCODE\tRegular",
readFontTracking : 0,
whiteBox : true,
humanReadable : true,
alignTo : "Page Margins",
selectionBounds : [0,0,0,0],
refPoint : "BOTTOM_RIGHT_ANCHOR",
offset : { x: 0, y: 0 },
humanReadableStr : "",
dpi : 1200,
bwr : { value: 0.00125, unit: "inch" },
createOulines : true,
heightPercent : 60,
scalePercent : 95,
qZoneIndicator : false,
addQuietZoneMargin : 0
},
{ name : "Standard",
version : version,
pageIndex : -1,
ean : "",
addon : "",
codeFont : "OCR BARCODE\tRegular",
readFont : "OCR BARCODE\tRegular",
readFontTracking : 0,
whiteBox : true,
humanReadable : true,
alignTo : "Page Margins",
selectionBounds : [0,0,0,0],
refPoint : "BOTTOM_RIGHT_ANCHOR",
offset : { x: 0, y: 0 },
humanReadableStr : "",
dpi : 1200,
bwr : { value: 0, unit: "inch" },
createOulines : true,
heightPercent : 100,
scalePercent : 80,
qZoneIndicator : true,
addQuietZoneMargin : 0
}
];
// ------------------------
// END of barcode_header.js
/* ____ __ ____ __ __ __
/ __ \____ / /_ __ / __ \/ /___ / /_/ /____ _____
/ /_/ / __ \/ / / / // /_/ / / __ \/ __/ __/ _ \/ ___/
/ ____/ /_/ / / /_/ // ____/ / /_/ / /_/ /_/ __/ /
/_/ \____/_/\__, //_/ /_/\____/\__/\__/\___/_/
/____/
An ExtendScript module to help draw paths in InDesign.
Version 0.6
Bruno Herfst 2017
MIT license (MIT)
https://github.com/GitBruno/PolyPlotter
*/
#target indesign
var polyPlotter = function( options ) {
// ref to self
var P = this;
// curent position
var currX = currY = 0;
var pathsHolder = [];
// Used when drawing paths
var scale = 100; // Percentage
var offset = [0, 0]; // X,Y
var objectStyleName = "";
function transformNumberArr( numArr, scale, offset ) {
var arr = numArr.slice(0);
var len = arr.length;
if( len < 1 ) {
// Array is empty
return arr;
}
if( arr[0].constructor === Array ) {
for (var i = 0; i < len; i++) {
arr[i] = transformNumberArr(arr[i], scale, offset);
}
} else { // arr is point
// Transform
arr = [ arr[0]/100 * scale + offset[0] ,
arr[1]/100 * scale + offset[1] ]
}
return arr;
}
function transformPath( pathArray ) {
return transformNumberArr( pathArray, scale, offset );
}
function transformAll( pathsHolder ) {
var transformedPaths = pathsHolder.slice(0);
var len = transformedPaths.length;
for (var p = 0; p < len; p++) {
transformedPaths[p].path = transformPath( transformedPaths[p].path );
}
return transformedPaths;
}
function drawPath( page, paths ) {
var pl = paths.length;
var pathType;
var newShape = page.rectangles.add();
try {
newShape.appliedObjectStyle = page.parent.parent.objectStyles.itemByName( objectStyleName, true );
} catch ( err ) {
newShape.appliedObjectStyle = page.parent.parent.objectStyles.item(0);
}
for (var p = 0; p < pl; p++) {
if( paths[p].open ) {
pathType = PathType.OPEN_PATH;
} else {
pathType = PathType.CLOSED_PATH;
}
var s = newShape.paths.add();
s.entirePath = paths[p].path;
s.pathType = pathType;
}
newShape.paths[0].remove();
}
// Set preferences
// ---------------
P.drawOffset = function ( x, y ) {
offset = [ parseFloat( x ), parseFloat( y ) ];
}
P.drawScale = function ( scalePercent ) {
scale = parseFloat( scalePercent );
}
P.setStyle = function ( styleName ) {
objectStyleName = String( styleName );
}
// Plot functions
// -------------
function updateCurr( x, y ) {
currX = parseFloat( x );
currY = parseFloat( y );
}
// New path object
function plotPath( path, open ) {
var pp = this;
pp.path = path || [];
pp.open = (open==null || open); // Standard true
// Is the first point already drawn
pp.startPoint = false;
pp.add = function ( points ) {
pp.path.push( points );
pp.startPoint = true;
}
}
// New plotter path holder
var currPath = new plotPath();
// Copy given path
P.copyShape = function( shape, options ) {
var myOffset = [0,0]; // X, Y Offset
var myScale = 100; // Percent
var resetBounds = false;
if( currPath.path.length > 0) {
pathsHolder.push( currPath );
}
currPath = new plotPath();
if( options ) {
if(options.hasOwnProperty('scale')) {
myScale = parseFloat(options.scale);
}
if(options.hasOwnProperty('offset')) {
myOffset = [parseFloat(options.offset[0]),parseFloat(options.offset[1])];
}
if(options.hasOwnProperty('resetBounds')) {
resetBounds = Boolean( options.resetBounds );
}
if(!options.hasOwnProperty('ignoreStyle') ) {
if(!Boolean( options.ignoreStyle )) {
objectStyleName = shape.appliedObjectStyle.name;
}
}
}
if(resetBounds) {
// Get shape offset
var sBounds = shape.geometricBounds;
myOffset[0] += -sBounds[1];
myOffset[1] += -sBounds[0];
}
var pathLen = shape.paths.length;
for(var p = 0; p < pathLen; p++){
currPath.path = transformNumberArr( shape.paths[p].entirePath, myScale, myOffset );
currPath.open = false;
if( shape.paths[p].pathType == PathType.OPEN_PATH ) {
currPath.open = true;
}
pathsHolder.push( currPath );
currPath = new plotPath();
}
}
// start a new path
P.newPath = function() {
if( currPath.path.length > 0) {
pathsHolder.push( currPath );
}
currPath = new plotPath();
}
// Move to new location
P.moveTo = function ( x, y ) {
currPath.startPoint = false;
updateCurr( x, y );
}
P.lineTo = function ( x, y ) {
if(!currPath.startPoint) {
currPath.add( [currX, currY] );
}
currPath.add( [parseFloat( x ), parseFloat( y )] );
updateCurr( x, y );
}
P.curveTo = function ( outx, outy, inx, iny, x, y) {
if(!currPath.startPoint) {
currPath.add( [currX, currY] );
}
var lastPoint = currPath.path[currPath.path.length-1];
if( lastPoint[0].constructor === Array ) {
// Curve point
lastPoint[2] = [parseFloat(outx), parseFloat(outy)];
} else {
// Normal point // Convert to curve point
currPath.path[currPath.path.length-1] = [ [lastPoint[0],lastPoint[1]],[lastPoint[0],lastPoint[1]],[parseFloat(outx), parseFloat(outy)] ]
}
currPath.add( [[parseFloat(inx), parseFloat(iny)],[parseFloat(x), parseFloat(y)],[parseFloat(x), parseFloat(y)]] );
}
// close a path
P.closePath = function() {
currPath.open = false;
P.newPath();
}
P.clear = function () {
// New Drawing
// Clears old data
// Reset
currPath = new plotPath();
pathsHolder = [];
}
// Adding points
// -------------
P.addRect = function ( x, y, w, h) {
// Adds a rectangle
pathsHolder.push( new plotPath( [ [x,y],[x+w,y],[x+w,y+h],[x,y+h] ], false) );
}
P.addOval = function ( x, y, w, h) {
// Adds an oval
var hw = w * 0.5; // Half width
var hh = h * 0.5; // Half height
var magic = 0.5522848;
var mx = x + hw; // Mid X
var my = y + hh; // Mid Y
var qh = hh * magic;
var qw = hw * magic;
pathsHolder.push( new plotPath( [ [ [mx-qw , y ], [mx , y ], [mx+qw , y ] ],
[ [x+w , my-qh], [x+w , my ], [x+w , my+qh] ],
[ [mx+qw , y+h ], [mx , y+h], [mx-qw , y+h ] ],
[ [x , my+qh], [x , my ], [x , my-qh] ]], false) );
}
// Get functions
// -------------
P.getCurrentLocation = function() {
return [currX, currY];
}
P.getPaths = function( options ) {
return transformAll( pathsHolder );
}
P.drawToPage = function( page, options ) {
P.newPath();
if( options ) {
if(options.hasOwnProperty('scale')) {
scale = parseInt(options.scale);
}
if(options.hasOwnProperty('x')) {
offset[0] = parseFloat( options.x );
}
if(options.hasOwnProperty('y')) {
offset[1] = parseFloat( options.y );
}
if(options.hasOwnProperty('style')) {
objectStyleName = String( options.style );
}
}
if( pathsHolder.length > 0) {
drawPath( page, transformAll( pathsHolder ) );
} else {
alert("No paths to draw, did you close the path?")
}
}
}
// End polyPlotter.js
/*
jaxon.js
A array based preset manager for extendscript
Bruno Herfst 2017
Version 2.3
MIT license (MIT)
https://github.com/GitBruno/Jaxon
*/
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Start ExtendScript Poly fills v1.1
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// ARRAY
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
if (!Array.isArray) {
Array.isArray = function(arg) {
return Object.prototype.toString.call(arg) === '[object Array]';
};
}
// Production steps of ECMA-262, Edition 5, 15.4.4.18
// Reference: http://es5.github.io/#x15.4.4.18
if (!Array.prototype.forEach) {
Array.prototype.forEach = function(callback/*, thisArg*/) {
var T, k;
if (this == null) {
throw new TypeError('this is null or not defined');
}
var O = Object(this);
var len = O.length >>> 0;
if (typeof callback !== 'function') {
throw new TypeError(callback + ' is not a function');
}
if (arguments.length > 1) {
T = arguments[1];
}
k = 0;
while (k < len) {
var kValue;
if (k in O) {
kValue = O[k];
callback.call(T, kValue, k, O);
}
k++;
}
};
}
if (!Array.prototype.indexOf) {
Array.prototype.indexOf = function (vMember, nStartFrom) {
if (this == null) {
throw new TypeError("Array.prototype.indexOf() - can't convert `" + this + "` to object");
}
var
nIdx = isFinite(nStartFrom) ? Math.floor(nStartFrom) : 0,
oThis = this instanceof Object ? this : new Object(this),
nLen = isFinite(oThis.length) ? Math.floor(oThis.length) : 0;
if (nIdx >= nLen) {
return -1;
}
if (nIdx < 0) {
nIdx = Math.max(nLen + nIdx, 0);
}
if (vMember === undefined) {
do {
if (nIdx in oThis && oThis[nIdx] === undefined) {
return nIdx;
}
} while (++nIdx < nLen);
} else {
do {
if (oThis[nIdx] === vMember) {
return nIdx;
}
} while (++nIdx < nLen);
}
return -1;
};
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// OBJECT
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/**
* Polyfill for Object.keys
* @see: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/keys
*/
if (!Object.keys) {
Object.keys = (function () {
var hasOwnProperty = Object.prototype.hasOwnProperty,
hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'),
dontEnums = [
'toString',
'toLocaleString',
'valueOf',
'hasOwnProperty',
'isPrototypeOf',
'propertyIsEnumerable',
'constructor'
],
dontEnumsLength = dontEnums.length;
return function (obj) {
if (typeof obj !== 'object' && typeof obj !== 'function' || obj === null) throw new TypeError('Object.keys called on non-object');
var result = [];
for (var prop in obj) {
if (hasOwnProperty.call(obj, prop)) result.push(prop);
}
if (hasDontEnumBug) {
for (var i=0; i < dontEnumsLength; i++) {
if (hasOwnProperty.call(obj, dontEnums[i])) result.push(dontEnums[i]);
}
}
return result;
}
})()
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// JSON
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// json2.js -> json-es.js
// 2016-10-28
// Public Domain.
// NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
// See http://www.JSON.org/js.html
// This is a reference implementation. You are free to copy, modify, or
// redistribute.
// Adjusted by Bruno Herfst 2017
// 1. Make it run in ExtendScript
// 2. Add JSON.clone() function
// 3. Add JSON.saveFile() function
// 4. Add JSON.openFile() function
// 5. Add JSON.ask2Safe() function
// Create a JSON object only if one does not already exist. We create the
// methods in a closure to avoid creating global variables.
if (typeof JSON !== "object") {
JSON = {};
}
(function () {
"use strict";
var rx_one = /^[\],:{}\s]*$/;
var rx_two = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g;
var rx_three = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g;
var rx_four = /(?:^|:|,)(?:\s*\[)+/g;
var rx_escapable = /[\\"\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
var rx_dangerous = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
function f(n) {
// Format integers to have at least two digits.
return n < 10
? "0" + n
: n;
}
function this_value() {
return this.valueOf();
}
if (typeof Date.prototype.toJSON !== "function") {
Date.prototype.toJSON = function () {
return isFinite(this.valueOf())
? this.getUTCFullYear() + "-" +
f(this.getUTCMonth() + 1) + "-" +
f(this.getUTCDate()) + "T" +
f(this.getUTCHours()) + ":" +
f(this.getUTCMinutes()) + ":" +
f(this.getUTCSeconds()) + "Z"
: null;
};
Boolean.prototype.toJSON = this_value;
Number.prototype.toJSON = this_value;
String.prototype.toJSON = this_value;
}
var gap;
var indent;
var meta;
var rep;
function quote(string) {
// If the string contains no control characters, no quote characters, and no
// backslash characters, then we can safely slap some quotes around it.
// Otherwise we must also replace the offending characters with safe escape
// sequences.
rx_escapable.lastIndex = 0;
return rx_escapable.test(string)
? "\"" + string.replace(rx_escapable, function (a) {
var c = meta[a];
return typeof c === "string"
? c
: "\\u" + ("0000" + a.charCodeAt(0).toString(16)).slice(-4);
}) + "\""
: "\"" + string + "\"";
}
function str(key, holder) {
// Produce a string from holder[key].
var i; // The loop counter.
var k; // The member key.
var v; // The member value.
var length;
var mind = gap;
var partial;
var value = holder[key];
// If the value has a toJSON method, call it to obtain a replacement value.
if (value && typeof value === "object" &&
typeof value.toJSON === "function") {
value = value.toJSON(key);
}
// If we were called with a replacer function, then call the replacer to
// obtain a replacement value.
if (typeof rep === "function") {
value = rep.call(holder, key, value);
}
// What happens next depends on the value's type.
switch (typeof value) {
case "string":
return quote(value);
case "number":
// JSON numbers must be finite. Encode non-finite numbers as null.
return isFinite(value)
? String(value)
: "null";
case "boolean":
case "null":
// If the value is a boolean or null, convert it to a string. Note:
// typeof null does not produce "null". The case is included here in
// the remote chance that this gets fixed someday.
return String(value);
// If the type is "object", we might be dealing with an object or an array or
// null.
case "object":
// Due to a specification blunder in ECMAScript, typeof null is "object",
// so watch out for that case.
if (!value) {
return "null";
}
// Make an array to hold the partial results of stringifying this object value.
gap += indent;
partial = [];
// Is the value an array?
if (Object.prototype.toString.apply(value) === "[object Array]") {
// The value is an array. Stringify every element. Use null as a placeholder
// for non-JSON values.
length = value.length;
for (i = 0; i < length; i += 1) {
partial[i] = str(i, value) || "null";
}
// Join all of the elements together, separated with commas, and wrap them in
// brackets.
v = partial.length === 0
? "[]"
: gap
? "[\n" + gap + partial.join(",\n" + gap) + "\n" + mind + "]"
: "[" + partial.join(",") + "]";
gap = mind;
return v;
}
// If the replacer is an array, use it to select the members to be stringified.
if (rep && typeof rep === "object") {
length = rep.length;
for (i = 0; i < length; i += 1) {
if (typeof rep[i] === "string") {
k = rep[i];
v = str(k, value);
if (v) {
partial.push(quote(k) + (
gap
? ": "
: ":"
) + v);
}
}
}
} else {
// Otherwise, iterate through all of the keys in the object.
for (k in value) {
if (Object.prototype.hasOwnProperty.call(value, k)) {
v = str(k, value);
if (v) {
partial.push(quote(k) + (
gap
? ": "
: ":"
) + v);
}
}
}
}
// Join all of the member texts together, separated with commas,
// and wrap them in braces.
v = partial.length === 0
? "{}"
: gap
? "{\n" + gap + partial.join(",\n" + gap) + "\n" + mind + "}"
: "{" + partial.join(",") + "}";
gap = mind;
return v;
}
}
// If the JSON object does not yet have a stringify method, give it one.
if (typeof JSON.stringify !== "function") {
meta = { // table of character substitutions
"\b": "\\b",
"\t": "\\t",
"\n": "\\n",
"\f": "\\f",
"\r": "\\r",
"\"": "\\\"",
"\\": "\\\\"
};
JSON.stringify = function (value, replacer, space) {
// The stringify method takes a value and an optional replacer, and an optional
// space parameter, and returns a JSON text. The replacer can be a function
// that can replace values, or an array of strings that will select the keys.
// A default replacer method can be provided. Use of the space parameter can
// produce text that is more easily readable.
var i;
gap = "";
indent = "";
// If the space parameter is a number, make an indent string containing that
// many spaces.
if (typeof space === "number") {
for (i = 0; i < space; i += 1) {
indent += " ";
}
// If the space parameter is a string, it will be used as the indent string.
} else if (typeof space === "string") {
indent = space;
}
// If there is a replacer, it must be a function or an array.
// Otherwise, throw an error.
rep = replacer;
if (replacer && typeof replacer !== "function" &&
(typeof replacer !== "object" ||
typeof replacer.length !== "number")) {
throw new Error("JSON.stringify");
}
// Make a fake root object containing our value under the key of "".
// Return the result of stringifying the value.
return str("", {"": value});
};
}
// If the JSON object does not yet have a parse method, give it one.
if (typeof JSON.parse !== "function") {
JSON.parse = function (text, reviver) {
// The parse method takes a text and an optional reviver function, and returns
// a JavaScript value if the text is a valid JSON text.
var j;
function walk(holder, key) {
// The walk method is used to recursively walk the resulting structure so
// that modifications can be made.
var k;
var v;
var value = holder[key];
if (value && typeof value === "object") {
for (k in value) {
if (Object.prototype.hasOwnProperty.call(value, k)) {
v = walk(value, k);
if (v !== undefined) {
value[k] = v;
} else {
delete value[k];
}
}
}
}
return reviver.call(holder, key, value);
}
// Parsing happens in four stages. In the first stage, we replace certain
// Unicode characters with escape sequences. JavaScript handles many characters
// incorrectly, either silently deleting them, or treating them as line endings.
text = String(text);
rx_dangerous.lastIndex = 0;
if (rx_dangerous.test(text)) {
text = text.replace(rx_dangerous, function (a) {
return "\\u" +
("0000" + a.charCodeAt(0).toString(16)).slice(-4);
});
}
// In the second stage, we run the text against regular expressions that look
// for non-JSON patterns. We are especially concerned with "()" and "new"
// because they can cause invocation, and "=" because it can cause mutation.
// But just to be safe, we want to reject all unexpected forms.
// We split the second stage into 4 regexp operations in order to work around
// crippling inefficiencies in IE's and Safari's regexp engines. First we
// replace the JSON backslash pairs with "@" (a non-JSON character). Second, we
// replace all simple value tokens with "]" characters. Third, we delete all
// open brackets that follow a colon or comma or that begin the text. Finally,
// we look to see that the remaining characters are only whitespace or "]" or
// "," or ":" or "{" or "}". If that is so, then the text is safe for eval.
if (
rx_one.test(
text
.replace(rx_two, "@")
.replace(rx_three, "]")
.replace(rx_four, "")
)
) {
// In the third stage we use the eval function to compile the text into a
// JavaScript structure. The "{" operator is subject to a syntactic ambiguity
// in JavaScript: it can begin a block or an object literal. We wrap the text
// in parens to eliminate the ambiguity.
j = eval("(" + text + ")");
// In the optional fourth stage, we recursively walk the new structure, passing
// each name/value pair to a reviver function for possible transformation.
return (typeof reviver === "function")
? walk({"": j}, "")
: j;
}
// If the text is not JSON parseable, then a SyntaxError is thrown.
throw new SyntaxError("JSON.parse");
};
};
if (typeof JSON.clone !== "function") {
// The clone method takes a JSON object and returns a clone of the JSON object.
JSON.clone = function ( value ) {
if (typeof value === undefined) {
return undefined;
}
return JSON.parse(JSON.stringify(value));
}
};
if (typeof JSON.saveFile !== "function") {
// The saveFile method takes an ExtendScript File object and any instance and saves it the the given File.
JSON.saveFile = function (File, Obj){
var objStr = JSON.stringify(Obj);
File.open('w');
var ok = File.write(objStr);
if (ok) {
ok = File.close();
}
if (!ok) {
alert("JSON: Error saving file. \n" + File.error);
File.close();
}
return Obj;
}
};
if (typeof JSON.openFile !== "function") {
// The saveFile method takes an ExtendScript File object and any instance and saves it the the given File.
JSON.openFile = function (File){
var obj = {};
if(File !== false){
File.open('r');
content = File.read();
obj = JSON.parse(content);
File.close();
}else{
alert("JSON: Could not open file."); // if something went wrong
}
return obj;
}
};
if (typeof JSON.ask2Safe !== "function") {
// The ask2Safe method is similar to saveFile method. Except that it will ask the user first
JSON.ask2Safe = function (question, File, Obj){
var save = confirm(question);
if(save){
JSON.saveFile(File, Obj);
}
return save;
}
};
}());
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// End ExtendScript Poly fills
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/*
JSON Schema Instantiator
https://github.com/tomarad/JSON-Schema-Instantiator
The MIT License (MIT)
Copyright (c) 2015 Tom Arad
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
and associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies
or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
var Instantiator = function() {
//////////////
// privates //
//////////////
'use strict';
// The JSON Object that defines the default values of certain types.
var typesInstantiator = {
'string': '',
'number': 0,
'integer': 0,
'null': null,
'boolean': false, // Always stay positive?
'object': { }
};
/**
* Checks whether a variable is a primitive.
* @param obj - an object.
* @returns {boolean}
*/
function isPrimitive(obj) {
var type = obj.type;
return typesInstantiator[type] !== undefined;
}
/**
* Checks whether a property is on required array.
* @param property - the property to check.
* @param requiredArray - the required array
* @returns {boolean}
*/
function isPropertyRequired(property, requiredArray) {
var found = false;
requiredArray = requiredArray || [];
requiredArray.forEach(function(requiredProperty) {
if (requiredProperty === property) {
found = true;
}
});
return found;
}
function shouldVisit(property, obj, options) {
return (!options.requiredPropertiesOnly) || (options.requiredPropertiesOnly && isPropertyRequired(property, obj.required));
}
/**
* Instantiate a primitive.
* @param val - The object that represents the primitive.
* @returns {*}
*/
function instantiatePrimitive(val) {
var type = val.type;
// Support for default values in the JSON Schema.
if (val.default) {
return val.default;
}
return typesInstantiator[type];
}
/**
* Checks whether a variable is an enum.
* @param obj - an object.
* @returns {boolean}
*/
function isEnum(obj) {
return Object.prototype.toString.call(obj.enum) === '[object Array]';
}
/**
* Checks whether a variable is an array.
* @param obj - an object.
* @returns {boolean}
*/
function isArray(obj) {
return Array.isArray(obj);
}
/**
* Extracts the type of the object.
* If the type is an array, set type to first in list of types.
* If obj.type is not overridden, it will fail the isPrimitive check.
* Which internally also checks obj.type.
* @param obj - An object.
*/
function getObjectType(obj) {
// Check if type is array of types.
if (isArray(obj.type)) {
obj.type = obj.type[0];
}
return obj.type;
}
/**
* Instantiate an enum.
* @param val - The object that represents the primitive.
* @returns {*}
*/
function instantiateEnum(val) {
// Support for default values in the JSON Schema.
if (val.default) {
return val.default;
}
if (!val.enum.length) {
return undefined;
}
return val.enum[0];
}
/**
* The main function.
* Calls sub-objects recursively, depth first, using the sub-function 'visit'.
* @param schema - The schema to instantiate.
* @returns {*}
*/
function instantiate(schema, options) {
options = options || {};
// Set requiredPropertiesOnly to true if not defined
if ( typeof options.requiredPropertiesOnly === 'undefined') options.requiredPropertiesOnly = true;
/**
* Visits each sub-object using recursion.
* If it reaches a primitive, instantiate it.
* @param obj - The object that represents the schema.
* @param name - The name of the current object.
* @param data - The instance data that represents the current object.
*/
function visit(obj, name, data) {
if (!obj) {
return;
}
var i;
var type = getObjectType(obj);
// We want non-primitives objects (primitive === object w/o properties).
if (type === 'object' && obj.properties) {
data[name] = data[name] || { };
// Visit each property.
for (var property in obj.properties) {
if (obj.properties.hasOwnProperty(property)) {
if (shouldVisit(property, obj, options)) {
visit(obj.properties[property], property, data[name]);
}
}
}
} else if (obj.allOf) {
for (i = 0; i < obj.allOf.length; i++) {
visit(obj.allOf[i], name, data);
}
} else if (type === 'array') {
data[name] = [];
var len = 0;
if (obj.minItems || obj.minItems > 0) {
len = obj.minItems;
}
// Instantiate 'len' items.
for (i = 0; i < len; i++) {
visit(obj.items, i, data[name]);
}
} else if (isEnum(obj)) {
data[name] = instantiateEnum(obj);
} else if (isPrimitive(obj)) {
data[name] = instantiatePrimitive(obj);
}
}
var data = {};
visit(schema, 'kek', data);
return data['kek'];
}
////////////
// expose //
////////////
return {
instantiate : instantiate
};
}();
/*
* Jassi v0.1.2
* https://github.com/iclanzan/jassi
*
* Copyright (c) 2014 Sorin Iclanzan
* License: https://github.com/iclanzan/jassi
*/
var Validator = function() {
//////////////
// privates //
//////////////
'use strict';
var isArray = Array.isArray;
var keys = Object.keys;
/**
* Check if a given value is an instance of a JSON object.
* This means that arrays and the null object are not considered objects.
*
* @param {any} value Any value to be checked
* @return {Boolean} Returns true if the value is an instance of a JSON object, false otherwise.
*/
function isObject(value) {
return null !== value && typeof value == 'object' && !isArray(value);
}
/**
* Get the type of a value.
*
* JSON primitive types:
* Array, Boolean, Number, null, Object, String
*
* @param {any} value Any value
* @return {String} One of the JSON primitive types.
*/
function getType(value) {
if( isObject(value) ) return 'object';
if( isArray (value) ) return 'array';
if( null === value ) return 'null';
return typeof value;
}
/**
* Check if two items are equal as per the JSON Schema spec.
*
* @param {any} item1 The first item
* @param {any} item2 The second item
* @return {Boolean} Returns true if the items are equal.
*/
function areEqual(item1, item2) {
var type1 = getType(item1);
var type2 = getType(item2);
var i, l, keys1, keys2, key;
if (type1 != type2) return false;
if ('array' == type1) {
if (item1.length !== item2.length) return false;
for (i = 0, l = item1.length; i < l; i ++)
if (!areEqual(item1[i], item2[i])) return false;
return true;
}
if ('object' == type1) {
keys1 = keys(item1);
keys2 = keys(item2);
if (keys1.length !== keys2.length) return false;
for (i = 0, l = keys1.length; i < l; i ++) {
key = keys1[i];
if (!item2.hasOwnProperty(key) || !areEqual(item1[key], item2[key])) return false;
}
return true;
}
return item1 === item2;
}
function or(item1, item2) {
return undefined !== item1 ? item1 : item2;
}
/**
* Validate a JSON instance against a schema.
*
* The function returns an empty array if validation is successful.
*
* @param {any} instance An instance of a JSON data that needs to be validated
* @param {Object} schema The schema to validate the instance against
* @param {String} path Optional. The path to the property that is being validated.
* @return {Array} An array of objects describing validation errors.
*/
var validate = function(instance, schema, path) {
var errors = [], type, l, i, j, items, itemsIsArray, additional, additionalIsObject, found, properties, pattern, pp;
function addError(message) {
errors.push({property:path, message: message});
return errors;
}
if (undefined === path) path = '';
if (!isObject(schema)) return addError('Invalid schema.');
type = getType(instance);
if (schema.type) {
items = isArray(schema.type) ? schema.type : [schema.type];
if (!~items.indexOf(type) && (type != 'number' || !~items.indexOf('integer') || instance % 1 != 0)) {
addError('Invalid type. Was expecting ' + schema.type + ' but found ' + type + '.');
}
}
if ('array' == type) {
l = instance.length;
if (schema.items || schema.additionalItems) {
items = schema.items || {};
itemsIsArray = isArray(schema.items);
additional = schema.additionalItems;
additionalIsObject = isObject(schema.additionalItems);
if (itemsIsArray && false === additional && l > (j = items.length))
addError('The instance can only have up to ' + j + ' items.');
else for (i = 0; i < l; i ++)
errors = errors.concat(validate(
instance[i],
itemsIsArray ? items[i] || additionalIsObject && additional || {} : items,
path + '[' + i + ']'
));
}
if (schema.maxItems && l > schema.maxItems)
addError('There must be a maximum of ' + schema.maxItems + ' item(s) in the array.');
if (schema.minItems && l < schema.minItems)
addError('There must be a minimum of ' + schema.minItems + ' item(s) in the array.');
if (schema.uniqueItems) {
dance: for (i = 0; i < l; i ++) {
for (j = i + 1; j < l; j ++) {
if (areEqual(instance[i], instance[j])) {
addError("The items in the array must be unique.");
break dance;
}
}
}
}
}
if ('object' == type) {
if (schema.maxProperties && keys(instance).length > schema.maxProperties)
addError('The instance must have at most ' + schema.maxProperties + ' members.');
if (schema.minProperties && keys(instance).length < schema.minProperties)
addError('The instance must have at least ' + schema.minProperties + ' members.');
if (schema.required)
schema.required.forEach(function(requiredProperty) {
if (!instance.hasOwnProperty(requiredProperty))
addError('Required property "' + requiredProperty + '" is missing.');
});
if (schema.properties || schema.additionalProperties || schema.patternProperties) {
properties = or(schema.properties, {});
pattern = or(schema.patternProperties, {});
additional = or(schema.additionalProperties, {});
pp = keys(pattern);
}
keys(instance).forEach(function(key) {
var schemas, dependency;
if (schema.dependencies && (dependency = schema.dependencies[key])) {
if (isArray(dependency)) {
dependency.forEach(function (prop) {
if (!instance.hasOwnProperty(prop)) {
addError('Property "' + key + '" requires "' + prop + '" to also be present.');
}
});
}
else {
errors = errors.concat(validate(instance, dependency, path));
}
}
if (
properties &&
false === additional &&
!properties.hasOwnProperty(key) &&
!(pp && pp.some(function(regex) { return key.match(regex); }))
)
addError('The key "' + key + '" is not allowed to be set.');
else {
schemas = [];
if (properties && properties.hasOwnProperty(key))
schemas.push(properties[key]);
pp && pp.forEach(function(regex) {
if (key.match(regex) && pattern[regex]) {
schemas.push(pattern[regex]);
}
});
if (!schemas.length && additional)
schemas.push(additional);
schemas.forEach(function(schema) {
errors = errors.concat(validate(instance[key], schema, path ? path + '.' + key : key));
});
}
});
}
if ('string' == type) {
if (schema.maxLength && instance.length > schema.maxLength)
addError('The instance must not be more than ' + schema.maxLength + ' character(s) long.');
if (schema.minLength && instance.length < schema.minLength)
addError('The instance must be at least ' + schema.minLength + ' character(s) long.');
if (schema.pattern && !instance.match(schema.pattern))
addError('Regex pattern /' + schema.pattern + '/ is a mismatch.');
}
if ('number' == type) {
if (schema.multipleOf !== undefined && instance / schema.multipleOf % 1 != 0)
addError('The instance is required to be a multiple of ' + schema.multipleOf + '.');
if (schema.maximum !== undefined) {
if (!schema.exclusiveMaximum && schema.maximum < instance)
addError('The instance must have a maximum value of ' + schema.maximum + '.');
if (schema.exclusiveMaximum && schema.maximum instance)
addError('The instance must have a minimum value of ' + schema.minimum + '.');
if (schema.exclusiveMinimum && schema.minimum >= instance)
addError('The instance must be greater than ' + schema.minimum + '.');
}
}
if (schema['enum']) {
items = schema['enum'];
l = items.length;
for (i = 0, found = 0; i < l && !found; i++)
if (areEqual(items[i], instance))
found = 1;
if (!found) addError('The instance must have one of the following values: ' + items.join(', ') + '.');
}
if (schema.allOf) {
schema.allOf.forEach(function(schema) {
errors = errors.concat(validate(instance, schema, path));
});
}
if (schema.anyOf) {
items = schema.anyOf;
l = items.length;
for(i = 0, found = 0; i < l && !found; i++)
if (!validate(instance, items[i], path).length)
found = 1;
if (!found) addError('The instance must validate against at least one schema defined by the "anyOf" keyword.');
}
if (schema.oneOf) {
items = schema.oneOf;
l = items.length;
for (i = 0, found = 0; i < l; i++)
if (!validate(instance, items[i], path).length) {
if (found) {
addError('The instance must validate against exactly one schema defined by the "oneOf" keyword.');
break;
}
found = 1;
}
if (!found) {
addError('The instance must validate against one schema defined by the "oneOf" keyword.');
}
}
if (schema.not && !validate(instance, schema.not, path).length)
addError('The instance must not validate against the schema defined by the "not" keyword.');
return errors;
};
////////////
// expose //
////////////
return {
validate : validate
};
}();
/*
Copyright (c) 2012 Dmitry Poklonskiy
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the 'Software'),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
/* Adjusted by Bruno Herfst 2017 to run in ExtendScript */
/**
* Create the ObjectManager instance.
* @class Provide methods for reaching into objects and insert the missing parts
* using dot notation mongodb-style query string.
* @name ObjectManager
* @param {Object|Array} [ctx] Object which we want to resolve.
* @param {String} [delim="."] Delimiter for the query string.
*/
var ObjectManager = function (ctx, delim) {
"string" === typeof ctx && (delim = ctx, ctx = {}); // Shift params.
this.ctx = ctx || {};
this.delim = delim || ".";
/**
* Resolve query through context object.
* @private
* @function
* @name manage
* @param {Object|Array} obj Object which we want to resolve, it will always be this.ctx value.
* @param {String[]} path Keys/indexes from query.
* @param {Number} depth How deep do we go.
* @param {Function} callback Will be called on resolving complete(fail).
* @param {Boolean} upsert If requested object(s)/array(s) do not exist, insert one.
* @returns {Object|Array} Link on the last but one object in query path.
*/
this.manage = function (obj, path, depth, callback, upsert) {
var err = null, i, key;
for (i = 0; i < depth; i++) {
key = path[i];
if(null != obj) {
"undefined" === typeof obj[key] && upsert && (obj[key] = isNaN(path[i + 1]) && {} || []); // If next key is an integer - create an array, else create an object.
if("undefined" === typeof (obj = obj[key])) {
break;
}
} else {
err = new TypeError("Cannot read property '%s' of ".replace('%s', key) + (null === obj && 'null' || typeof obj));
break;
}
}
if(callback) {
//async(function () {
callback(err && String(err), !err && obj);
//});
} else {
return err || obj;
}
};
/**
* Getter method of the ObjectManager.
* @function
* @name ObjectManager.find
* @param {String} [query] Query string. If is not specified or an empty string - return resolved object.
* @param {Function} [callback] Will be called with 2 params when resolving complete(fail):
* 1. null or error description string
* 2. value of the certain object[key] or undefined/false
* @returns {ObjectManager|Object} If callback is specified return 'this' for chaining calls,
* else return resolved value (context object if path is empty string or not specified).
*/
this.find = function (query, callback) {
"function" === typeof query && (callback = query, query = false); // Shift params if path not specified.
var path = query && query.split(this.delim) || [],
result = this.manage(this.ctx, path, path.length, callback);
if(result instanceof Error) {
throw result;
}
return callback && this || result;
};
/**
* Setter method of the ObjectManager.
* @function
* @name ObjectManager.update
* @param {String} query Query string.
* @param value What we want to assign.
* @param {Function} [callback] Will be called with 2 params when assigning complete(fail):
* 1. null or error description string
* 2. updated object or false
* @param {Boolean} [upsert=true] If requested object(s)/array(s) do not exist, insert one.
* @returns {ObjectManager} For chaining calls.
*/
this.update = function (query, value, callback, upsert) {
"boolean" === typeof callback && (upsert = callback, callback = null); // Shift params if callback not specified.
var path = query && query.split(this.delim) || [],
depth = path.length - 1,
lastKey = path[depth],
upsert = "boolean" === typeof upsert ? upsert : true,
ctx = this.ctx,
result = callback || this.manage(ctx, path, depth, callback, upsert),
set = function (obj, key, val) {
return null != obj && key ? obj[key] = val :
new TypeError("Cannot set property '%s' of ".replace('%s', key) + (null === obj && 'null' || typeof obj));
};
if(callback) {
this.manage(ctx, path, depth, function (err, obj) {
err || (result = set(obj, lastKey, value)) instanceof Error && (err = String(result));
callback(err, !err && ctx);
}, upsert);
} else {
if(result instanceof Error || (result = set(result, lastKey, value)) instanceof Error) {
throw result;
}
}
return this;
};
/**
* Apply function with object as context.
* @function
* @name ObjectManager.apply
* @param {String} query Query string.
* @param {Function} fn Will be called with this = object, resolved through the query.
* @param {Array} args Arguments for function call.
*/
this.apply = function (query, fn, args) {
return fn.apply(this.find(query), args);
};
/**
* Create a copy of the resolved object.
* @function
* @name ObjectManager.copy
* @param {String} query Query string.
* @returns {Object|Boolean} Resolved copy or false.
*/
this.copy = function (query) {
var result = this.find(query);
return "object" === typeof result && JSON.parse(JSON.stringify(result));
};
/**
* Create a mixin
* @function
* @name ObjectManager.mixin
* @param {String} query Query string.
* @returns {Object} Mixin of the resolved
*/
this.mixin = function () {
var query = arguments[0],
ctx = this.find(query),
result = {},
hasOwn = Object.prototype.hasOwnProperty,
extend = function (o1, o2) {
for (var prop in o2) {
hasOwn.call(o2, prop) && (o1[prop] = o2[prop]);
}
return o1;
};
for (var arg = 1; arg < arguments.length; arg++) {
result = extend(result, arguments[arg]);
}
return extend(result, ctx);
};
// Self-invoking constructor
if(!(this instanceof ObjectManager)) {
return new ObjectManager(delim);
}
};
var jaw = function( Schema, instance ) {
// ref to self
var Jaw = this;
var manager = new ObjectManager({});
var _Schema = {};
var _isValid = {
schema : true ,
managed : true ,
all : function(){
return (this.schema && this.managed);
}
};
var errors = [];
function setSchema( Schema ){
// Validate given schema
_Schema = JSON.clone( Schema );
// Shema is object, let's make sure it has a type property as well
errors = Validator.validate( Jaw.getSchema(), {"type": "object","required": ["type"]} );
if( errors.length > 0 ) {
_isValid.schema = false;
errors.unshift("Schema not valid (Missing type property).");
return;
}
// Validating against a fresh instance from schema should always work
// If not, there is something wrong with the schema
errors = Validator.validate( Jaw.getTemplate( true ), Jaw.getSchema() );
if( errors.length > 0 ) {
errors.unshift("Schema not valid (Could not generate valid instance from shema).");
_isValid.schema = false;
}
};
function userException(message) {
this.message = message;
this.name = 'Error';
};
function setObj( newObj ) {
if(_isValid.schema) {
errors = Validator.validate( newObj, Jaw.getSchema() );
if( errors.length === 0 ) {
manager = new ObjectManager(newObj);
_isValid.managed = true;
}
}
return Jaw;
};
function copyKeys(fromObj, toObj) {
if( (typeof fromObj !== 'object') ||
(typeof toObj !== 'object') ) {
throw new userException('copyKeys needs to be given objects');
}
Object.keys(fromObj).forEach(function(key) {
toObj[key] = fromObj[key];
});
};
function validateManager(){
var result = Validator.validate( manager.find(), Jaw.getSchema() );
if( result.length > 0 ) {
errors.push(result);
_isValid.managed = false;
}
};
//-----------------
// Public funcions
//-----------------
Jaw.isValid = function() {
return _isValid.all();
};
Jaw.errors = function() {
if(Array.isArray(errors)) {
return errors;
} else {
return [errors];
}
};
Jaw.wrap = function( givenObj ) {
var newObj = Instantiator.instantiate( Jaw.getSchema() );
if(typeof newObj === 'object') {
// Copy all keys from given object to new object
copyKeys(givenObj, newObj);
}
setObj( newObj );
return Jaw;
};
Jaw.getTemplate = function( allProperties ) {
// allProperties = undefined = false = {requiredPropertiesOnly: true}
if(typeof allProperties !== 'boolean') {
var requiredPropertiesOnly = true; // allProperties == false
} else {
var requiredPropertiesOnly = !allProperties;
}
return Instantiator.instantiate( Jaw.getSchema(), {requiredPropertiesOnly: requiredPropertiesOnly} );
};
Jaw.getSchema = function() {
return JSON.clone(_Schema);
};
Jaw.get = function( path ) {
return manager.find( path );
};
Jaw.set = function( path, to ) {
var check = new ObjectManager( JSON.clone( Jaw.get() ) );
var result = check.update( path, to, function (resultErr) {
errors.push(resultErr);
});
var err = Validator.validate( check.find(), Jaw.getSchema() );
var errHandler = function(err, obj) {
//err: null or string with error description "TypeError: cannot set property 'undefined' of number"
//obj: updated object { a : { b : [{ c : 10 }] } }
if( typeof err === "string") {
errors.push(resultErr);
}
}
if ( err.length > 0 ) {
errors.push( err );
} else {
manager.update( path, to, errHandler);
validateManager();
}
return Jaw;
};
//-----------------
// Initialise
//-----------------
setSchema( Schema );
if( errors.length === 0 ) {
// Start managing something
manager = new ObjectManager( Jaw.getTemplate( false ) );
};
if(Jaw.isValid() && instance) {
if(typeof instance !== 'object') {
_valid.managed = false;
errors.unshift("Initialisation Error: Can't get Jaw arround non-object");
} else {
Jaw.wrap(instance);
}
};
};
/* -------------------------------------------------------------------------------
@param fileName : String
Name of file to be saved in user data folder
@param Schema : Object
A schema to validate against. Also used to generate defaults
@param standardPresets : Array
Initial presets that are loaded if no presetsFile is found at filePath
------------------------------------------------------------------------------- */
var presetManager = function( fileName, Schema, standardPresets ) {
// ref to self
var Jaxon = this;
// standard file path
var filePath = Folder.userData + "/" + String(fileName);
var valid = true;
var errors = [];
function userException(message) {
this.message = message;
this.name = 'Error';
}
// S C H E M A S
//-------------------------
// Load Jaw for preset and validate preset Schema
var presetJaw = new jaw( Schema );
if(!presetJaw.isValid()) {
throw presetJaw.errors()[0];
}
// Create Schema for standardPresets
// This preset manager works on the premise
// that presets are objects collected in an array
var PresetsSchema = { "type": "array", "items": Schema };
var presetsJaws = new jaw( PresetsSchema );
if(!presetsJaws.isValid()) {
throw userException(presetsJaws.errors());
}
// Validate standardPresets
//-------------------------
if ( typeof standardPresets === 'undefined') standardPresets = [Jaws.getTemplate(true)];
if ( Array.isArray( standardPresets ) ) {
standardPresets = JSON.clone( standardPresets );
} else {
throw new userException("Param standardPresets needs to be type of array but is " + String(typeof standardPresets));
}
if(!presetsJaws.wrap(standardPresets).isValid()) {
throw userException(presetsJaws.errors());
}
//-------------------------------------------------
// P R I V A T E F U N C T I O N S
//-------------------------------------------------
function createMsg ( bool, comment ) {
// Standard return obj
return {success: Boolean(bool), comment: String( comment ) };
}
function not_in_array ( arr, element ) {
for(var i=0; i 0) {
alert("Could not load preset.\n" + JSON.stringify(_Preset.errors()) );
}
return _Preset.get();
}
// Get and set preset properties
PresetController.getProp = function( propName ) {
return _Preset.get( propName );
}
PresetController.setProp = function( propName, val ) {
var prop = String(propName);
if( _hasProp( prop ) ) {
_Preset.set(prop, val);
return JSON.clone( _Preset.get(prop) );
}
alert("Could not set preset property.\nProperty " + prop + " does not exist.");
return undefined;
}
// init
PresetController.load( Preset );
} // End of presetController
// P R E S E T S C O N T R O L L E R
//-------------------------------------------------
function presetsController( presets ) {
// The presets controller handles the presets array
var PresetsController = this;
function infuse( presets ) {
var holder = new Array();
var len = presets.length;
for (var i = 0; i < len; i++) {
holder[i] = new presetController( presets[i] );
}
return holder;
}
var _Presets = infuse( presets );
function clean() {
var holder = new Array();
var len = _Presets.length;
for (var i = 0; i < len; i++) {
holder[i] = _Presets[i].get();
}
return holder;
}
function cleanSave_presets(){
// This function removes any temporary preset before saving to disk
var holder = new Array();
var len = _Presets.length;
for (var i = 0; i < len; i++) {
if(! _Presets[i].getTemporaryState() ) {
holder.push( _Presets[i].get() );
}
}
return holder;
}
function presetExist( key, val ) {
var len = _Presets.length;
for (var i = len-1; i >= 0; i--) {
if (_Presets[i].getProp(key) == val) {
return true;
}
}
return false;
}
function calcIndex( pos, len ) {
// Calculate actual index
var i = pos;
if ( pos < 0 ) {
i = len - Math.abs(pos);
}
return Math.abs(i);
}
function outOfRange( pos, len ) {
var pos = parseInt(pos);
var len = parseInt(len);
if( len == 0 ) {
// Everything is out of range :)
return true;
}
if(pos > len) {
return true;
}
if( pos < -1-len ) {
return true;
}
return false;
}
//------------------------------------------
// Public access
PresetsController.get = function () {
return clean();
}
PresetsController.getTemplate = function() {
return presetJaw.getTemplate( true );
}
PresetsController.getByKey = function ( key, val ) {
// Sample usage: Jaxon.Presets.getByKey('id',3);
// Please note that this function returns the first
// preset it can find
var len = _Presets.length;
for (var i = len-1; i >= 0; i--) {
if (_Presets[i].getProp(key) === val) {
return _Presets[i].get();
}
}
return false;
}
PresetsController.getIndex = function ( key, val ) {
// Sample usage: Jaxon.Presets.getIndex('name','this');
// returns array with matches
var matches = new Array();
var len = _Presets.length;
for (var i = len-1; i >= 0; i--) {
if (_Presets[i].getProp(key) == val) {
matches.unshift(i);
}
}
return matches;
}
PresetsController.getByIndex = function ( position ) {
// Sample usage: Jaxon.getPresetByIndex( 3 );
var len = _Presets.length;
if( outOfRange( position, len ) ) {
alert("Preset Manager\nThere is no preset at index " + position);
return false;
}
var i = calcIndex( parseInt(position), len );
return _Presets[i].get();
}
PresetsController.getPropList = function ( key ) {
if( !Jaxon.UiPreset.get().hasOwnProperty( key ) ) {
alert("Preset Manager\nCan't create propertylist with key " + key);
return [];
}
var len = _Presets.length;
var propList = new Array();
for (var i = 0; i < len; i++) {
propList[i] = _Presets[i].getProp(key);
}
return propList;
}
PresetsController.reset = function () {
_Presets = infuse( standardPresets );
}
PresetsController.load = function ( presets ) {
_Presets = infuse( presets );
return clean();
}
PresetsController.add = function ( preset, options ) {
// options { position: integer, temporary preset: boolean }
// para position; index that can handle negative numbers
// that are calculated from the back -1 == last
var len = _Presets.length;
var pos = len;
if(options && options.hasOwnProperty('position')) {
pos = options.position;
if ( isNaN(pos) ) {
pos = len;
}
if( outOfRange(pos, len) ) {
pos = len;
}
}
var i = calcIndex( pos, len+1 );
var infusedPreset = new presetController( preset );
if(options && options.hasOwnProperty('temporary')) {
infusedPreset.setTemporaryState( options.temporary == true );
}
_Presets.splice(i, 0, infusedPreset);
return clean();
}
PresetsController.addUnique = function ( Preset, key, options ) {
// Sample usage: PresetManager.Presets.addUnique( Preset, 'name' );
var silently = false;
var position = -1;
if(options && options.hasOwnProperty('position')) {
if( !isNaN(options.position) ) position = parseInt(options.position);
}
if(options && options.hasOwnProperty('silently')) {
silently = options.silently == true;
}
var exist = presetExist(key, Preset[key]);
if(exist){
if(silently) {
var overwrite = true;
} else {
var overwrite = confirm("Do you want to overwrite the existing preset?");
}
if (overwrite) {
PresetsController.removeWhere( key, Preset[key] );
} else {
return false;
}
}
var newLen = _Presets.length+1;
PresetsController.add( Preset, {position: position} );
return _Presets.length == newLen;
}
PresetsController.remove = function ( position ) {
var len = _Presets.length;
// Check for outside range
if( outOfRange(position, len) ) {
alert("Could not remove preset\nOut of range: presets length: " + len + " index to be removed: " + position);
return false;
}
var i = calcIndex( parseInt(position), len );
_Presets.splice( i, 1 );
return true;
}
PresetsController.overwriteIndex = function ( position, Preset ) {
PresetsController.remove( position );
PresetsController.add( Preset, {position: position} );
return clean();
}
PresetsController.removeWhere = function ( key, val ) {
// Sample usage: Jaxon.Presets.removeWhere('id',3);
// This function removes any preset that contains key - val match
// It returns true if any presets have been removed
var success = false;
var len = _Presets.length;
for (var i = len-1; i >= 0; i--) {
if (_Presets[i].getProp(key) === val) {
_Presets.splice( i, 1 );
success = true;
}
}
return success;
}
PresetsController.saveToDisk = function ( ) {
var presetStr = JSON.stringify( cleanSave_presets() );
return writeFile(filePath, presetStr);
}
PresetsController.loadFromDisk = function () {
if( !fileExist(filePath) ){
alert("Cannot load presets.\nNo preset file found at " + filePath);
return false;
}
var PresetsFile = File(filePath);
PresetsFile.open('r');
var content = PresetsFile.read();
PresetsFile.close();
try {
var NewPresets = JSON.parse(content);
_Presets = infuse( NewPresets );
return true;
} catch(e) {
alert("Error reading JSON\n" + e.description);
return false;
}
}
PresetsController.removeFromDisk = function () {
if( fileExist(filePath) ){
var PresetsFile = File(filePath);
PresetsFile.remove();
return true;
}
return false;
}
} // End of presetsController
// W I D G E T
//-------------------------------------------------
function widgetCreator( SUI_Group ) {
var WidgetCreator = this;
var DataPort = { getData: undefined, renderUiPreset: undefined };
WidgetCreator.get = function () {
if(DataPort) {
return DataPort.getData();
} else {
return createMsg ( false, "No dataport defined" );
}
}
// Any preset that starts with a locking character can't be deleted by the user
var lockChars = ['[',']'];
WidgetCreator.getLockChars = function () {
return lockChars;
}
var ButtonText = {save: "Save Preset", clear: "Clear Preset"};
WidgetCreator.getButtonText = function () {
return ButtonText;
}
var newName = "New Preset";
WidgetCreator.getNewPresetName = function () {
return newName;
}
var lastUsedName = "Last Used";
WidgetCreator.getLastUsedPresetName = function () {
return lastUsedName;
}
// Keep track of which preset this preset is based on
// This makes it easy to over-ride an existing preset
var basedOnPresetName = newName;
var newPresetName = "";
var lastUsedPresetName = "";
function updatePresetNames() {
newPresetName = String(lockChars[0] + " " + newName + " " + lockChars[1]);
lastUsedPresetName = String(lockChars[0] + " " + lastUsedName + " " + lockChars[1]);
}
// This makes it possible to update UI everytime UiPreset is changed
// Even when the widget is not loaded
var presetsDrop = { selection: 0 };
var presetBut = { text: "" };
var presetDropList = [];
var updateUI = true;
var listKey = "";
function getDropDownIndex( index, len ) {
var i = parseInt( index );
if (i == 0) {
return i;
}
if (i < 0) {
i += len;
}
if (i > len ) {
i = len;
}
return i;
}
function createDropDownList(){
// Check listKey and load dropDown content
presetDropList = Jaxon.Presets.getPropList( listKey );
// Add new (clear) preset to dropdown list
presetDropList.unshift( newPresetName );
}
WidgetCreator.activateNew = function () {
// This function resets the dropdown to first (New Preset)
updateUI = false;
presetsDrop.selection = 0;
presetBut.text = ButtonText.save;
updateUI = true;
return createMsg ( true, "Done" );
}
WidgetCreator.activateLastUsed = function () {
// This function resets the dropdown to last (Last Used)
presetsDrop.selection = Jaxon.Presets.getIndex( listKey, lastUsedPresetName )[0]+1;
presetBut.text = ButtonText.save;
return createMsg ( true, "Done" );
}
WidgetCreator.saveUiPreset = function () {
Jaxon.UiPreset.load( DataPort.getData() );
return createMsg ( true, "Done" );
}
WidgetCreator.savePreset = function ( options ) {
WidgetCreator.saveUiPreset();
// Process Options
if(options && options.hasOwnProperty('updateProps')) {
for ( var i = 0; i < options.updateProps.length; i++ ) {
Jaxon.UiPreset.setProp( options.updateProps[i].key, options.updateProps[i].value );
}
}
var position = -1;
if( options && options.hasOwnProperty('position') ) {
position = parseInt(options.position);
}
Jaxon.UiPreset.save( position );
Jaxon.Presets.saveToDisk();
return createMsg ( true, "Done" );
}
WidgetCreator.overwritePreset = function( key, val, options ) {
// Save SUI data
WidgetCreator.saveUiPreset();
Jaxon.UiPreset.setProp( key, val );
// Process Options
var index = -1;
if(options && options.hasOwnProperty('position')) {
index = parseInt(options.position);
} else {
index = Jaxon.Presets.getIndex( key, val );
}
Jaxon.Presets.addUnique( Jaxon.UiPreset.get(), key, {position: index, silently: true} );
Jaxon.Presets.saveToDisk();
return createMsg ( true, "Done" );
}
WidgetCreator.saveLastUsed = function() {
try {
var originalName = Jaxon.UiPreset.get()[listKey];
WidgetCreator.overwritePreset( listKey, lastUsedPresetName, {position: -1} );
Jaxon.UiPreset.setProp( listKey, originalName );
} catch ( err ) {
alert(err)
}
return Jaxon.UiPreset.get();
}
WidgetCreator.reset = function() {
return createMsg( false, "Widget is not loaded.");
}
WidgetCreator.loadIndex = function( i ) {
// Load data in UiPreset
Jaxon.UiPreset.loadIndex( i );
// Update SUI
DataPort.renderUiPreset();
presetsDrop.selection = getDropDownIndex( i+1, presetDropList.length );
return true;
}
WidgetCreator.attachTo = function ( SUI_Group, listKeyID, Port, Options ) {
var onloadIndex = null;
listKey = String(listKeyID);
if(! (Port && Port.hasOwnProperty('renderData') && Port.hasOwnProperty('getData')) ) {
return createMsg( false, "Could not establish data port.");
}
DataPort.renderUiPreset = function () {
basedOnPresetName = String( Jaxon.UiPreset.getProp(listKey) );
Port.renderData( Jaxon.UiPreset.get() );
}
DataPort.getData = Port.getData;
// Process Options
if(Options && Options.hasOwnProperty('onloadIndex')) {
onloadIndex = parseInt(Options.onloadIndex);
}
if(Options && Options.hasOwnProperty('lockChars')) {
if(lockChars.length == 2) {
lockChars[0] = String(Options.lockChars[0]);
lockChars[1] = String(Options.lockChars[1]);
}
}
if(Options && Options.hasOwnProperty('newPresetName')) {
newName = String(Options.newPresetName);
}
if(Options && Options.hasOwnProperty('lastUsedPresetName')) {
lastUsedName = String(Options.lastUsedPresetName);
}
if(Options && Options.hasOwnProperty('buttonTextSave')) {
ButtonText.save = String(Options.buttonTextSave);
}
if(Options && Options.hasOwnProperty('buttonTextClear')) {
ButtonText.clear = String(Options.buttonTextClear);
}
function updatePresetData() {
// Update newPresetName
updatePresetNames();
createDropDownList( listKey );
}
updatePresetData();
// Attach new widget to SUI_Group
presetsDrop = SUI_Group.add('dropdownlist', undefined, presetDropList);
presetsDrop.alignment = 'fill';
presetsDrop.selection = getDropDownIndex( onloadIndex, presetDropList.length );
presetsDrop.onChange = function () {
if(updateUI) {
// Load data in UiPreset
if(this.selection.index == 0) {
Jaxon.UiPreset.reset();
} else {
Jaxon.UiPreset.loadIndex( this.selection.index-1 );
}
DataPort.renderUiPreset();
// Update button
if( this.selection.text.indexOf(lockChars[0]) == 0 ){
presetBut.text = ButtonText.save;
} else {
presetBut.text = ButtonText.clear;
}
}
}
WidgetCreator.updatePresetsDrop = function( selectIndex ) {
// This function will update the drop down without updating UI input values
updateUI = false;
updatePresetData();
presetsDrop.removeAll();
var len = presetDropList.length;
for (var i=0; i len-1) {
alert("Preset Manager\nLoad index is not a valid preset index: " + index);
return createMsg ( false, "Not a valid preset index." );
}
Jaxon.UiPreset.load( Jaxon.Presets.getByIndex( i ) );
return createMsg ( true, "Done" );
}
Jaxon.UiPreset.reset = function ( ) {
Jaxon.UiPreset.load( presetJaw.getTemplate( true ) );
}
Jaxon.reset = function( hard ) {
var hard = (hard == true);
if( hard ) {
Jaxon.Presets.reset();
Jaxon.Presets.saveToDisk();
} else {
Jaxon.Presets.loadFromDisk();
}
Jaxon.UiPreset.reset();
Jaxon.Widget.reset();
}
Jaxon.format = function ( preset ) {
return updatePreset ( preset );
}
//-------------------------------------------------
// E N D P U B L I C A P I
//-------------------------------------------------
// I N I T
//---------
// Save the standard presets if not allready exist
if(!fileExist( filePath ) ){
if( ! Jaxon.Presets.saveToDisk() ){
throw("Failed to start Jaxon\nUnable to save presets to " + filePath);
}
}
// Load the presets
Jaxon.Presets.loadFromDisk();
};
// Bruno Herfst 2018
// v1.2
var idUtil = new Object();
idUtil.getBoundsInfo = function (bounds){
// This functions receives bounds (y1, x1, y2, x2)
// and returns an object with bounds and info as below
var topLeftY = bounds[0];
var topLeftX = bounds[1];
var botRightY = bounds[2];
var botRightX = bounds[3];
var height = Math.abs(botRightY - topLeftY);
var width = Math.abs(botRightX - topLeftX);
return { bounds : bounds,
height : height,
width : width,
topLeft : {x: topLeftX , y: topLeftY } ,
topCenter : {x: topLeftX + (width/2) , y: topLeftY } ,
topRight : {x: botRightX , y: topLeftY } ,
midLeft : {x: topLeftX , y: topLeftY + (height/2) } ,
midCenter : {x: topLeftX + (width/2) , y: topLeftY + (height/2) } ,
midRight : {x: botRightX , y: topLeftY + (height/2) } ,
botLeft : {x: topLeftX , y: botRightY } ,
botCenter : {x: topLeftX + (width/2) , y: botRightY } ,
botRight : {x: botRightX , y: botRightY } };
}
idUtil.setRuler = function (doc, myNewUnits){
// This function sets the rulers to the disired measure units
// and returns the original preset that you can send back to
// this function to reset the rulers.
var myOldUnits = {xruler : doc.viewPreferences.horizontalMeasurementUnits, yruler: doc.viewPreferences.verticalMeasurementUnits, origin: doc.viewPreferences.rulerOrigin, zeroPoint: doc.zeroPoint };
if (myNewUnits.hasOwnProperty('xruler') && myNewUnits.hasOwnProperty('yruler')){
doc.viewPreferences.horizontalMeasurementUnits = myNewUnits.xruler;
doc.viewPreferences.verticalMeasurementUnits = myNewUnits.yruler;
} else if( myNewUnits.hasOwnProperty('units')) {
// Set both rulers to the sam unit
// We will cast everything to string so it can parse a wide variaty of input including the MeasurementUnits object
var stringUnits = String(myNewUnits.units).toLowerCase();
with(doc.viewPreferences){
switch(stringUnits) {
case "0":
case "millimeters":
case "mm":
case "millimeter":
case "zmms":
case "2053991795":
horizontalMeasurementUnits = MeasurementUnits.MILLIMETERS;
verticalMeasurementUnits = MeasurementUnits.MILLIMETERS;
break;
case "1":
case "inchesDecimal":
case "inch": // shorthand to decimal
case "zind":
case "2053729892":
horizontalMeasurementUnits = MeasurementUnits.INCHES_DECIMAL;
verticalMeasurementUnits = MeasurementUnits.INCHES_DECIMAL;
break;
case "inches":
case "zinc":
case "2053729891":
horizontalMeasurementUnits = MeasurementUnits.MeasurementUnits.INCHES;
verticalMeasurementUnits = MeasurementUnits.MeasurementUnits.INCHES;
break;
case "2":
case "points":
case "pt":
case "zpoi":
case "2054188905":
horizontalMeasurementUnits = MeasurementUnits.POINTS;
verticalMeasurementUnits = MeasurementUnits.POINTS;
break;
case "american_points":
case "apt":
case "zapt":
case "1514238068":
horizontalMeasurementUnits = MeasurementUnits.AMERICAN_POINTS;
verticalMeasurementUnits = MeasurementUnits.AMERICAN_POINTS;
break;
case "agates":
case "zagt":
case "2051106676":
horizontalMeasurementUnits = MeasurementUnits.AGATES;
verticalMeasurementUnits = MeasurementUnits.AGATES;
break;
case "bai":
case "zbai":
case "2051170665":
horizontalMeasurementUnits = MeasurementUnits.BAI;
verticalMeasurementUnits = MeasurementUnits.BAI;
break;
case "cm":
case "centimeter":
case "centimeters":
case "zcms":
case "2053336435":
horizontalMeasurementUnits = MeasurementUnits.CENTIMETERS;
verticalMeasurementUnits = MeasurementUnits.CENTIMETERS;
break;
case "ciceros":
case "c":
case "zcic":
case "2053335395":
horizontalMeasurementUnits = MeasurementUnits.CICEROS;
verticalMeasurementUnits = MeasurementUnits.CICEROS;
break;
case "custom":
case "cstm":
case "1131639917":
horizontalMeasurementUnits = MeasurementUnits.CUSTOM;
verticalMeasurementUnits = MeasurementUnits.CUSTOM;
break;
case "ha":
case "zha":
case "1516790048":
horizontalMeasurementUnits = MeasurementUnits.HA;
verticalMeasurementUnits = MeasurementUnits.HA;
break;
case "mils":
case "zmil":
case "2051893612":
horizontalMeasurementUnits = MeasurementUnits.MILS;
verticalMeasurementUnits = MeasurementUnits.MILS;
break;
case "picas":
case "p":
case "zpic":
case "2054187363":
horizontalMeasurementUnits = MeasurementUnits.PICAS;
verticalMeasurementUnits = MeasurementUnits.PICAS;
break;
case "pixels":
case "pixel":
case "px":
case "zpix":
case "2054187384":
horizontalMeasurementUnits = MeasurementUnits.PIXELS;
verticalMeasurementUnits = MeasurementUnits.PIXELS;
break;
case "q":
case "zque":
case "2054255973":
horizontalMeasurementUnits = MeasurementUnits.Q;
verticalMeasurementUnits = MeasurementUnits.Q;
break;
case "u":
case "zju":
case "2051691808":
horizontalMeasurementUnits = MeasurementUnits.U;
verticalMeasurementUnits = MeasurementUnits.U;
break;
default:
alert("idUtil setRuler:\nCould not parse MeasurementUnits: " + typeof(myNewUnits) + " " + myNewUnits );
break;
}
}
}
if(myNewUnits.hasOwnProperty('origin')){
doc.viewPreferences.rulerOrigin = myNewUnits.origin;
} else { // Use page origin if not defined
doc.viewPreferences.rulerOrigin = RulerOrigin.PAGE_ORIGIN;
}
if(myNewUnits.hasOwnProperty('zeroPoint')) {
doc.zeroPoint = myNewUnits.zeroPoint;
} else { // Use zero point if not defined
doc.zeroPoint = [0,0];
}
return myOldUnits;
}
idUtil.find = function (haystack, needle) {
for (var i = 0; i < haystack.length; i++) {
if(haystack[i] == needle) return i;
}
return 0; // Return the first element if nothing is found
}
idUtil.getItemsByName = function (DocPageSpread, myName){
// This funcion returns an array of all items found with given label
// If nothing is found this function returns an empty array
var allItems = new Array();
if(DocPageSpread.isValid){
var myElements = DocPageSpread.allPageItems;
var len = myElements.length;
for (var i = len-1; i >= 0; i--){
if(myElements[i].name == myName){
allItems.push(myElements[i]);
}
}
} else {
alert("ERROR 759403253473: Expected a valid doc, page or spread.");
}
return allItems;
}
idUtil.getItemsByLabel = function (DocPageSpread, myLabel){
// This funcion returns an array of all items found with given label
// If nothing is found this function returns an empty array
var allItems = new Array();
if(DocPageSpread.isValid){
var myElements = DocPageSpread.allPageItems;
var len = myElements.length;
for (var i = len-1; i >= 0; i--){
if(myElements[i].label == myLabel){
allItems.push(myElements[i]);
}
}
// Guides are not part of pageItems but they can have labels too!
var myGuides = DocPageSpread.guides;
var len = myGuides.length;
for (var i = len-1; i >= 0; i--){
if(myGuides[i].label == myLabel){
allItems.push(myGuides[i]);
}
}
} else {
alert("ERROR 759403253473: Expected a valid doc, page or spread.");
}
return allItems;
}
idUtil.getMaxBounds = function ( pageElementArray ){
if(pageElementArray.length == 0) {
alert("getMaxBounds received empty array :(");
return [0,0,0,0];
}
var maxBounds = pageElementArray[0].visibleBounds; //array [y1, x1, y2, x2], [top, left, bottom, right]
if(pageElementArray.length == 1) return maxBounds;
for(var i=1;i maxBounds[2]){ maxBounds[2] = itemBounds[2]; }
if(itemBounds[3] > maxBounds[3]){ maxBounds[3] = itemBounds[2]; }
break;
default:
alert("getMaxBounds() received " + pageElementArray[i].constructor.name);
break;
}
}
return maxBounds;
}
idUtil.calcOffset = function (itemBounds, page, preset){
//Note: This function needs a better name
var ib = idUtil.getBoundsInfo(itemBounds);
var pb = idUtil.getBoundsInfo(page.bounds);
if(preset.alignTo == "Barcode Box"){
// Add to offsets
preset.offset.x += preset.selectionBounds[1];
preset.offset.y += preset.selectionBounds[0];
pb = idUtil.getBoundsInfo(preset.selectionBounds);
} else if(preset.alignTo == "Selection"){
// Now lets add it to the offsets
preset.offset.x += preset.selectionBounds[1];
preset.offset.y += preset.selectionBounds[0];
pb = idUtil.getBoundsInfo(preset.selectionBounds);
}
function addToBounds(b, x, y) {
b[0] += y; //topLeftY
b[1] += x; //topLeftX
b[2] += y; //botRightY
b[3] += x; //botRightX
return b;
}
// Deal with page
switch (preset.refPoint) {
case "TOP_LEFT_ANCHOR":
//addToBounds(ib, 0, 0);
break;
case "TOP_CENTER_ANCHOR":
ib.bounds = addToBounds(ib.bounds, (pb.width/2)-(ib.width/2), 0);
break;
case "TOP_RIGHT_ANCHOR":
ib.bounds = addToBounds(ib.bounds, pb.width-ib.width, 0);
break;
case "LEFT_CENTER_ANCHOR":
ib.bounds = addToBounds(ib.bounds, 0, (pb.height/2)-(ib.height/2) );
break;
case "CENTER_ANCHOR":
ib.bounds = addToBounds(ib.bounds, (pb.width/2)-(ib.width/2), (pb.height/2)-(ib.height/2) );
break;
case "RIGHT_CENTER_ANCHOR":
ib.bounds = addToBounds(ib.bounds, pb.width-ib.width, (pb.height/2)-(ib.height/2));
break;
case "BOTTOM_LEFT_ANCHOR":
ib.bounds = addToBounds(ib.bounds, 0, pb.height-ib.height);
break;
case "BOTTOM_CENTER_ANCHOR":
ib.bounds = addToBounds(ib.bounds, (pb.width/2)-(ib.width/2), pb.height-ib.height);
break;
case "BOTTOM_RIGHT_ANCHOR":
ib.bounds = addToBounds(ib.bounds, pb.width-ib.width, pb.height-ib.height);
break;
default:
break;
}
// Deal with margin
if(preset.alignTo == "Page Margins"){
var mt = page.marginPreferences.top;
var mr = page.marginPreferences.right;
var ml = page.marginPreferences.left;
var mb = page.marginPreferences.bottom;
// Weight: 0 center, 1 top or left, 2 bottom or right
var marginInfo = { vertical: {diff : Math.abs(mt-mb), weight : 0}, horizontal: {diff : Math.abs(ml-mr), weight : 0} };
if(mt > mb){
marginInfo.vertical.weight = 1;
} else if (mt < mb) {
marginInfo.vertical.weight = 2;
}
if(ml > mr){
marginInfo.horizontal.weight = 1;
} else if (ml < mr) {
marginInfo.horizontal.weight = 2;
}
switch (preset.refPoint) {
case "TOP_LEFT_ANCHOR":
ib.bounds = addToBounds(ib.bounds, ml, mt); // X, Y
break;
case "TOP_CENTER_ANCHOR":
switch(marginInfo.horizontal.weight){
case 1: // Left
ib.bounds = addToBounds(ib.bounds, marginInfo.horizontal.diff/2, mt);
break;
case 2: // Right
ib.bounds = addToBounds(ib.bounds, -marginInfo.horizontal.diff/2, mt);
break;
default: // LR-CENTER
ib.bounds = addToBounds(ib.bounds, 0, mt);
break;
}
break;
case "TOP_RIGHT_ANCHOR":
ib.bounds = addToBounds(ib.bounds, -mr, mt);
break;
case "LEFT_CENTER_ANCHOR":
switch(marginInfo.vertical.weight){
case 1: // Top
ib.bounds = addToBounds(ib.bounds, ml, marginInfo.vertical.diff/2);
break;
case 2: // Bottom
ib.bounds = addToBounds(ib.bounds, ml, -marginInfo.vertical.diff/2);
break;
default:
ib.bounds = addToBounds(ib.bounds, ml, 0);
break;
}
break;
case "CENTER_ANCHOR":
switch(marginInfo.horizontal.weight){
case 1: // Left
ib.bounds = addToBounds(ib.bounds, marginInfo.horizontal.diff/2, 0);
break;
case 2: // Right
ib.bounds = addToBounds(ib.bounds, -marginInfo.horizontal.diff/2, 0);
break;
default: // LR-CENTER
break;
}
switch(marginInfo.vertical.weight){
case 1: // top
ib.bounds = addToBounds(ib.bounds, 0, marginInfo.vertical.diff/2);
break;
case 2: // bot
ib.bounds = addToBounds(ib.bounds, 0, -marginInfo.vertical.diff/2);
break;
default: // LR-CENTER
break;
}
break;
case "RIGHT_CENTER_ANCHOR":
switch(marginInfo.vertical.weight){
case 1: // Top
ib.bounds = addToBounds(ib.bounds, -mr, marginInfo.vertical.diff/2);
break;
case 2: // Bottom
ib.bounds = addToBounds(ib.bounds, -mr, -marginInfo.vertical.diff/2);
break;
default:
ib.bounds = addToBounds(ib.bounds, -mr, 0);
break;
}
break;
case "BOTTOM_LEFT_ANCHOR":
ib.bounds = addToBounds(ib.bounds, ml, -mb);
break;
case "BOTTOM_CENTER_ANCHOR":
switch(marginInfo.horizontal.weight){
case 1: // Left
ib.bounds = addToBounds(ib.bounds, marginInfo.horizontal.diff/2, -mb);
break;
case 2: // Right
ib.bounds = addToBounds(ib.bounds, -marginInfo.horizontal.diff/2, -mb);
break;
default: // LR-CENTER
ib.bounds = addToBounds(ib.bounds, 0, -mb);
break;
}
break;
case "BOTTOM_RIGHT_ANCHOR":
ib.bounds = addToBounds(ib.bounds, -mr, -mb);
break;
default:
break;
}
}
// Add UI bound offset
ib.bounds = addToBounds(ib.bounds, preset.offset.x, preset.offset.y);
return ib.bounds;
};
//-----------------------------------------------------------------------------------
// LAYER TOOLS
//-----------------------------------------------------------------------------------
function getSelectAndMoveLayer(doc, name, afterlayerNo){
return moveLayer(getAndSelectLayer(doc, name), afterlayerNo);
}
function getAndSelectLayer(doc, name) {
return selectLayer(doc, getLayer(doc, name));
}
function getLayer(doc, name) {
for (i=0; i= 0; i--) {
if(p >= this.companyPrefixes[i][0] && p 0 ) {
BD.xDimension = fitDPI( BD.xDimension, BD.dpi );
}
BD.quietZone = 7 * BD.xDimension; // Area of white space on either side of the bars. (X-dimension * 7 = Minimum)
// Width of all bars (including the width of the Left & Right Quiet Zones)
BD.digitWidth = 6 * BD.xDimension;
BD.guardWidth = 4 * BD.xDimension;
BD.width = (12 * BD.digitWidth) + (3 * BD.guardWidth); // Width of bars including guards
BD.humanReadableWidth = BD.width + (2 * BD.quietZone) + (2 * BD.digitWidth);
BD.minBoxWidth = BD.width + (2 * BD.quietZone) + (2 * BD.digitWidth) + (2 * BD.xDimension);
function addWidth( w ) {
BD.width += w;
BD.minBoxWidth += w;
}
BD.guardBarOvershoot = 5 * BD.xDimension; // Specification specifies that barHeight is extended downward 5X: barHeight + (X-dimension * 5)
BD.guardHeight = BD.barHeight + BD.guardBarOvershoot;
BD.addonHeight = BD.barHeight - BD.fontHeight;
BD.height = BD.guardHeight; // Also called symbolHeight or guardHeight;
BD.minBoxHeight = BD.barsYoffset + BD.barHeight + BD.fontHeight + (BD.xDimension * 2); // height incl. Machine Readable Numbers
BD.addonLen = 0; // How many digits in the addon code
BD.addonGap = BD.quietZone; // How much space bewteen the ean and addon code
if( options && options.hasOwnProperty('addonLen') ) {
BD.addonLen = parseInt(options.addonLen);
if( BD.addonLen > 0 ) {
// Add gap
addWidth( BD.addonGap );
// Start (5) + first digit (7)
addWidth( BD.xDimension * 12 );
// Seperator (2) + next digits (7)
for(var x = BD.addonLen; x > 1; x--) {
addWidth( BD.xDimension * 9 );
}
addWidth( BD.quietZone + BD.xDimension );
}
}
// Some positional markers that are handy to refer to
BD.yBottomBar = BD.barsYoffset + BD.barHeight;
BD.startingpos = BD.xDimension;
return BD;
}
function getNorm(bars) {
var curr = bars[0];
var counter = 1;
var norm = [];
for (var i = 1; i < bars.length; i++) {
if (curr !== bars[i]) {
norm.push(counter);
counter = 1;
curr = bars[i];
}
else {
counter++;
}
}
norm.push(counter);
return norm;
}
function stripAddon(str) {
return str.replace(/[^\d]+/g, '');
}
function stripEAN(str) {
return str.replace(/[^0-9X]/gi, '');
}
return {
init: function (preset) {
var eanStr = String(preset.ean);
var addonStr = String(preset.addon);
if (eanStr) {
barcode_string = eanStr;
stripped = stripEAN(barcode_string);
if ( !checkCheckDigit(stripped) ) {
throw "Check digit incorrect";
}
pattern = ean13_pattern[stripped[0]];
}
if (addonStr) {
addon_string = stripAddon(addonStr);
if(addon_string.length > 5) {
throw "Addon should be 5 digits or less.\nLength is: " + addon_string.length;
}
}
dimensions = getDimensions( { dpi : preset.dpi,
scale : preset.scalePercent,
heightAdjust : preset.heightPercent,
humanReadable : preset.humanReadable,
addonLen : preset.addon.length} );
return this;
},
getDimensions: function () {
return dimensions;
},
getStripped: function () {
return stripped;
},
getBarWidths: function () {
var barWidths = [];
for (var i = 1; i < stripped.length; i++) { //don't include first number of barcode
var encoding = pattern[i - 1];
var thisBarWidth = bar_widths[encoding][stripped[i]];
barWidths.push(thisBarWidth);
}
return barWidths;
},
getNormalisedWidths: function () {
var barWidths = this.getBarWidths();
var normalisedWidths = [];
var current = [];
for (var i = 0; i < barWidths.length; i++) {
current = [];
if (barWidths[i][0] === 0) {
current.push([0, 1, 0, 1]);
}
else {
current.push([1, 0, 1, 0]);
}
var norm = getNorm(barWidths[i]);
current.push(norm);
current.push(stripped[i+1]); //add ean digit
normalisedWidths.push(current);
}
return normalisedWidths;
},
getAddonWidths: function () {
if (! addon_string) {
return false;
}
else {
var checksum = this.getAddonChecksum();
var pattern = addon_pattern[checksum];
var widths = [];
for (var i = 0; i < addon_string.length; i++) {
//separators:
if (i === 0) {
widths.push([0, 1, 0, 1, 1]);
}
else {
widths.push([0, 1]);
}
var encoding = pattern[i];
widths.push(bar_widths[encoding][addon_string[i]]);
}
return widths;
}
},
getNormalisedAddon: function () {
var addonWidths = this.getAddonWidths();
if (! addonWidths) {
return false;
}
var normalisedAddon = [];
var current = [];
for (var i = 0; i < addonWidths.length; i++) {
current = [];
if (addonWidths[i].length == 2) {
current.push([0, 1])
}
else {
current.push([0, 1, 0, 1]);
}
current.push(getNorm(addonWidths[i]));
if (i % 2 == 1) {
current.push(addon_string[Math.floor(i / 2)]);
}
normalisedAddon.push(current);
}
return normalisedAddon;
},
getAddonChecksum: function () {
var total = 0;
for (var i = 0; i < addon_string.length; i++) {
if (i % 2 === 0) {
total += addon_string[i] * 3;
}
else {
total += addon_string[i] * 9;
}
}
return total % 10;
}
}
};
// END barcode_library.js
/*
Many parts of this code below are borrowed from IndiSnip
http://indisnip.wordpress.com/2010/08/24/findchange-missing-font-with-scripting/
*/
//get unique Array elements
Array.prototype.unique = function () {
var r = new Array();
o:for (var i = 0, n = this.length; i < n; i++) {
for (var x = 0, y = r.length; x < y; x++) {
if (r[x]==this[i]) {
continue o;
}
}
r[r.length] = this[i];
}
return r;
}
//search inside array
Array.prototype.findIn = function(search){
var r = Array();
for (var i=0; i 0){
var bData = JSON.parse(tempData);
if( typeof bData == 'object' && bData.hasOwnProperty('ean') ) {
return Pm.format( bData );
}
}
return false;
}
function checkActiveDoc( activeDoc ){
// Update pages info
list_of_pages = activeDoc.pages.everyItem().name;
currentPage = app.activeWindow.activePage.name;
function updatePageNumber( MyPreset ) {
// This function makes sure pagenumer is valid
if( (MyPreset.pageIndex < 0) || (MyPreset.pageIndex > list_of_pages.length-1) ) {
// Let’s see which page is selected
for (var j=0; j 0 ) {
var barcode_box = barcode_boxes[0];
// Save activeDocPreset.selectionBounds
var originalRulers = idUtil.setRuler(activeDoc, {units : "mm", origin : RulerOrigin.SPREAD_ORIGIN });
barcodeBoxDetails.bounds = barcode_box.geometricBounds;
idUtil.setRuler(activeDoc, originalRulers);
alignToOptions.push("Barcode Box");
Pm.UiPreset.setProp("alignTo", "Barcode Box");
var selectionParentPage = barcode_box.parentPage.name;
// Let’s see which page contains selection
for (var j=0; j 0 ) {
var validatedSelection = [];
for (var i = 0; i < app.selection.length; i++) {
switch (app.selection[i].constructor.name){
case "Rectangle":
case "TextFrame":
case "Oval":
case "Polygon":
case "GraphicLine":
case "Group":
case "PageItem":
// Don't process items that are on the pasteboard
if ( app.selection[0].parentPage ) {
validatedSelection.push(app.selection[i]);
}
break;
default:
break;
}
}
if( validatedSelection.length > 0 ) {
// Save activeDocPreset.selectionBounds
var originalRulers = idUtil.setRuler(activeDoc, {units : "mm", origin : RulerOrigin.SPREAD_ORIGIN });
selectionDetails.bounds = idUtil.getMaxBounds( validatedSelection );
idUtil.setRuler(activeDoc, originalRulers);
alignToOptions.push('Selection');
Pm.UiPreset.setProp("alignTo", "Selection");
// Let’s see which page contains selection
var selectionParentPage = app.selection[0].parentPage.name;
for (var j=0; j 0) {
//alignToOptions.push("Barcode Box");
for (i = 0; i < existingBarcodes.length; i++) {
var eBarcodePreset = getBarcodePreset(existingBarcodes[i]);
if( eBarcodePreset ) {
eBarcodePreset.name = "[ "+ eBarcodePreset.ean +" ]";
//eBarcodePreset.alignTo = "Barcode Box";
eBarcodePreset = updatePageNumber( eBarcodePreset );
// Save activeDocPreset.selectionBounds
var originalRulers = idUtil.setRuler(activeDoc, {units : "mm", origin : RulerOrigin.SPREAD_ORIGIN });
eBarcodePreset.bounds = idUtil.getMaxBounds( [existingBarcodes[i]] );
idUtil.setRuler(activeDoc, originalRulers);
// Temporary preset so it will not be saved to disk
Pm.Presets.add(eBarcodePreset, {position: 0, temporary: true} );
}
}
} else {
// Only go through this routine if there are no barcode settings found
var activeDocPreset = Pm.Presets.getTemplate();
activeDocPreset.name = "[ Active Document ]";
// Tag preset so it will not be saved to disk
activeDocPreset.temporaryPreset = true;
// Check if there is an entry for EAN
var tempData = activeDoc.extractLabel('EAN');
if( tempData.length > 0 ){
activeDocPreset.ean = tempData;
activeDocPreset = updatePageNumber( activeDocPreset );
}
// Save
Pm.Presets.add(activeDocPreset, {position: 0, temporary: true});
} // End existing barcodes
} //END checkActiveDoc
if ( activeDoc.isValid ) {
checkActiveDoc( activeDoc );
}
//-----------------------------------------------------------------------
// W I N D O W
//-----------------------------------------------------------------------
var dialog = new Window('dialog', 'EAN-13 Barcode Generator');
dialog.orientation = 'column';
dialog.alignChildren = 'left';
dialog.margins = [15,10,15,20];
function NaN20(num){
if(isNaN(num)){
return 0;
} else {
return num;
}
}
function createFresh() {
if(userChange) {
Pm.Widget.activateNew();
}
}
//-------------
// EAN-13 Input
//-------------
var input = dialog.add('panel', undefined, 'New Barcode: ');
function updateEANTypeTo( EAN13_type, details ){
userChange = false;
var t = String( EAN13_type );
if(t.toLowerCase() == "unknown") {
details = "Unknown";
t = "EAN-13";
}
if (typeof details === 'string' || details instanceof String) {
if( details.length > 0 ) {
t += " [ " + details + " ]";
}
}
input.text = t;
userChange = true;
}
input.margins = [10,20,10,20];
input.alignment = "fill";
input.alignChildren = "left";
input.orientation = 'row';
var eanInput = input.add('edittext');
eanInput.characters = 17;
eanInput.active = true;
eanInput.text = Pm.UiPreset.getProp('ean');
function checkEanInput() {
var digits = eanInput.text.replace(/[^\dXx]+/g, '');
if (digits.length == 8) {
// ISSN
eanInput.text = digits.substring(0, 4) + "-" + digits.substring(4, 8);
updateEANTypeTo("ISSN");
return;
} else if (digits.length == 10) {
// ISBN-10
try {
var ean = ISBN.parse(digits);
} catch (err) {
alert(err);
}
if ( ean && ean.isIsbn10() ) {
eanInput.text = ISBN.hyphenate(digits);
updateEANTypeTo("ISBN", ean.getGroupRecord(digits.substring(3, 13)).record.name );
return;
}
return;
} else if (digits.length == 13) {
if( digits.substring(0, 3) == "977") {
// ISSN
eanInput.text = "977-" + digits.substring(3, 7) + "-" + digits.substring(7, 10) + "-" + digits.substring(10, 12) + "-" + digits.substring(12, 13);
updateEANTypeTo("ISSN");
return;
} else if ( digits.substring(0, 4) == "9790" ) {
// ISMN
// All publisher elements must fit into the general number scheme:
/* 000 - 099
1000 - 3999
40000 - 69999
700000 - 899999
9000000 - 9999999 */
// http://www.ismn-international.org/tools.php
var pubStart = Number( digits.substring(4,5) );
var pubLen = 0;
if ( pubStart == 0 ) {
pubLen = 3;
} else if ( pubStart < 4) {
pubLen = 4;
} else if ( pubStart < 7) {
pubLen = 5;
} else if ( pubStart < 9) {
pubLen = 6;
} else if ( pubStart = 9) {
pubLen = 7;
}
if(pubLen != 0) {
eanInput.text = "979-0-" + digits.substring(4, 4+pubLen) + "-" + digits.substring(4+pubLen,12) + "-" + digits.substring(12,13);
updateEANTypeTo("ISMN");
return;
}
} else if ( digits.substring(0, 3) == "978") {
// ISBN
try {
var ean = ISBN.parse(digits);
} catch (err) {
alert(err);
}
if ( ean && ean.isIsbn13() ) {
eanInput.text = ISBN.hyphenate(digits);
updateEANTypeTo("ISBN", ean.getGroupRecord(digits.substring(3, 13)).record.name );
return;
}
} else {
// EAN-13
updateEANTypeTo("EAN-13", GS1_Prefixes.getPrefixInfo(digits.substring(0, 3)) );
return;
}
} // End digits length == 13
// note returned yet...
updateEANTypeTo("Unknown");
eanInput.text = eanInput.text.replace(/ +/g, "-");
eanInput.text = eanInput.text.replace(/[^\dxX-]*/g, "").toUpperCase();
}
eanInput.onChange = function () {
if(userChange) {
checkEanInput();
}
}
input.add('statictext', undefined, 'Addon (optional):');
var addonText = input.add('edittext');
addonText.characters = 5;
addonText.text = Pm.UiPreset.getProp('addon');
var pageSelectPrefix = input.add('statictext', undefined, 'Page:');
var pageSelect_dropDown = input.add('dropdownlist', undefined, list_of_pages);
pageSelect_dropDown.selection = pageSelect_dropDown.items[ Pm.UiPreset.getProp('pageIndex') ];
if( ! activeDoc.isValid ) {
// Don't show page select when there is no document open
pageSelect_dropDown.visible = false;
pageSelectPrefix.visible = false;
}
// ----------------------
// -- Start preset group
var presetPanel = dialog.add('group');
presetPanel.margins = [0,5,0,0];
//presetPanel.margins = [10,5,10,0];
presetPanel.orientation = 'row';
presetPanel.alignment = "right";
// -- End preset group
// ----------------------
// Add options
// -----------
var optionsPanel;
// START SETTINGS PANEL
optionsPanel = dialog.add('group');
optionsPanel.margins = 0;
optionsPanel.alignment = "fill";
optionsPanel.alignChildren = "left";
optionsPanel.orientation = 'column';
// Start Fonts Panel
// -----------------
var fontPanel = optionsPanel.add("panel", undefined, "Fonts");
fontPanel.margins = [10,15,10,20];
fontPanel.alignment = "fill";
fontPanel.alignChildren = "left";
fontPanel.orientation = 'column';
fontPanel.add('statictext', undefined, 'Machine-readable');
var codeFontRow = fontPanel.add('group');
var codeFontSelect = FontSelect(codeFontRow, Pm.UiPreset.getProp('codeFont'), createFresh );
fontPanel.add('statictext', undefined, 'Human-readable');
var readFontRow = fontPanel.add('group');
var readFontSelect = FontSelect(readFontRow, Pm.UiPreset.getProp('readFont'), createFresh );
// End Fonts Panel
// -----------------
var extraoptionsPanel = optionsPanel.add('group');
extraoptionsPanel.margins = 0;
extraoptionsPanel.alignment = "fill";
extraoptionsPanel.alignChildren = "fill";
extraoptionsPanel.orientation = 'row';
/////////////////////
// Start REF panel //
/////////////////////
var refPanel = extraoptionsPanel.add("panel", undefined, "Alignment");
refPanel.margins = 20;
refPanel.alignment = "top";
refPanel.alignChildren = "fill";
refPanel.orientation = 'row';
// START REF SQUARE GROUP //
var refSquare = refPanel.add("group");
refSquare.orientation = 'column';
var topRow = refSquare.add("group");
for(var i = 0; i < 3; i++){
topRow.add("radiobutton", undefined,"");
}
var midRow = refSquare.add("group");
for(var i = 0; i < 3; i++){
midRow.add("radiobutton", undefined,"");
}
var botRow = refSquare.add("group");
for(var i = 0; i < 3; i++){
botRow.add("radiobutton", undefined,"");
}
// Add event listeners
for(var i = 0; i < 3; i++){
topRow.children[i].onActivate = function(){
for(var i = 0; i < 3; i++){
midRow.children[i].value = false;
botRow.children[i].value = false;
}
createFresh();
}
midRow.children[i].onActivate = function(){
for(var i = 0; i < 3; i++){
topRow.children[i].value = false;
botRow.children[i].value = false;
}
createFresh();
}
botRow.children[i].onActivate = function(){
for(var i = 0; i < 3; i++){
topRow.children[i].value = false;
midRow.children[i].value = false;
}
createFresh();
}
}
// Reference panel functions
var clearSelectedReferencePoint = function(){
for(var i = 0; i < 3; i++){
topRow.children[i].value = false;
midRow.children[i].value = false;
botRow.children[i].value = false;
}
}
var setSelectedReferencePoint = function( ref ) {
// Deselct any active ref point
clearSelectedReferencePoint();
switch (ref) {
case "TOP_LEFT_ANCHOR":
topRow.children[0].value = true;
break;
case "TOP_CENTER_ANCHOR":
topRow.children[1].value = true;
break;
case "TOP_RIGHT_ANCHOR":
topRow.children[2].value = true;
break;
case "LEFT_CENTER_ANCHOR":
midRow.children[0].value = true;
break;
case "CENTER_ANCHOR":
midRow.children[1].value = true;
break;
case "RIGHT_CENTER_ANCHOR":
midRow.children[2].value = true;
break;
case "BOTTOM_LEFT_ANCHOR":
botRow.children[0].value = true;
break;
case "BOTTOM_CENTER_ANCHOR":
botRow.children[1].value = true;
break;
case "BOTTOM_RIGHT_ANCHOR":
botRow.children[2].value = true;
break;
default:
break;
}
}
var getSelectedReferencePoint = function(){
// Check top row
var topRowOptions = ["TOP_LEFT_ANCHOR", "TOP_CENTER_ANCHOR", "TOP_RIGHT_ANCHOR" ];
var midRowOptions = ["LEFT_CENTER_ANCHOR", "CENTER_ANCHOR", "RIGHT_CENTER_ANCHOR" ];
var botRowOptions = ["BOTTOM_LEFT_ANCHOR", "BOTTOM_CENTER_ANCHOR", "BOTTOM_RIGHT_ANCHOR" ];
for(var i = 0; i < 3; i++){
if(topRow.children[i].value == true){
return topRowOptions[i];
}
if(midRow.children[i].value == true){
return midRowOptions[i];
}
if(botRow.children[i].value == true){
return botRowOptions[i];
}
}
}
setSelectedReferencePoint( Pm.UiPreset.getProp('refPoint') );
var optionPanel = refPanel.add("group");
optionPanel.alignChildren = "top";
optionPanel.orientation = 'column';
var alignTo_dropDown = optionPanel.add("dropdownlist", undefined, alignToOptions);
alignTo_dropDown.selection = idUtil.find( alignToOptions, Pm.UiPreset.getProp('alignTo') );
alignTo_dropDown.onChange = function() {
createFresh();
}
var offsetXRow = optionPanel.add("group");
offsetXRow.alignChildren = "left";
offsetXRow.orientation = "row";
var offsetYRow = optionPanel.add("group");
offsetYRow.alignChildren = "left";
offsetYRow.orientation = "row";
var myOffset = Pm.UiPreset.getProp('offset');
var offX = String(myOffset.x) + " " + docunits;
offsetXRow.add("statictext", undefined,"Offset X: ");
var offsetX_editText = offsetXRow.add("edittext", undefined, offX );
offsetX_editText.characters=6;
offsetX_editText.onChange = function () {
offsetX_editText.text = parseFloat(offsetX_editText.text) + " " + docunits;
createFresh();
}
offsetYRow.add("statictext", undefined,"Offset Y: ");
var offsetY_editText = offsetYRow.add("edittext", undefined, String(myOffset.y) + " " + docunits );
offsetY_editText.characters=6;
offsetY_editText.onChange = function () {
offsetY_editText.text = parseFloat(offsetY_editText.text) + " " + docunits;
createFresh();
}
///////////////////
// END REF panel //
///////////////////
////////////////////////////
// Start Adjustment panel //
////////////////////////////
var tab = 50;
var adjustPanel = extraoptionsPanel.add("panel", undefined, "Adjustments");
adjustPanel.margins = 20;
adjustPanel.alignment = "fill";
adjustPanel.alignChildren = "left";
adjustPanel.orientation = 'column';
//-------------------
var heightAdjust = adjustPanel.add('group');
var heightLabel = heightAdjust.add('statictext', undefined, 'Height:');
heightLabel.minimumSize.width = tab;
var heightPercent_editText = heightAdjust.add('edittext', undefined, Pm.UiPreset.getProp('heightPercent') );
heightPercent_editText.characters = 7;
heightPercent_editText.onChange = function () {
heightPercent_editText.text = String(parseFloat(heightPercent_editText.text));
createFresh();
};
heightAdjust.add('statictext', undefined, '%');
//-------------------
var scaleAdjust = adjustPanel.add('group');
var scaleLabel = scaleAdjust.add('statictext', undefined, 'Scale:');
scaleLabel.minimumSize.width = tab;
var scalePercent_editText = scaleAdjust.add('edittext', undefined, Pm.UiPreset.getProp('scalePercent') );
scalePercent_editText.characters = 7;
scalePercent_editText.onChange = function () {
scalePercent_editText.text = NaN20(parseFloat(scalePercent_editText.text));
createFresh();
};
scaleAdjust.add('statictext', undefined, '%');
//-------------------
var dpiAdjust = adjustPanel.add('group');
var dpiLabel = dpiAdjust.add('statictext', undefined, 'Output:');
dpiLabel.minimumSize.width = tab;
var dpi_editText = dpiAdjust.add('edittext', undefined, Pm.UiPreset.getProp('dpi') );
dpi_editText.characters = 7;
dpi_editText.onChange = function () {
dpi_editText.text = NaN20(parseInt(dpi_editText.text));
createFresh();
};
dpiAdjust.add('statictext', undefined, 'DPI');
//-------------------
var bwrAdjust = adjustPanel.add('group');
var bwrLabel = bwrAdjust.add('statictext', undefined, 'BWR:');
bwrLabel.minimumSize.width = tab;
var bwr_editText = bwrAdjust.add('edittext', undefined, Pm.UiPreset.getProp('bwr') );
bwr_editText.characters = 7;
bwr_editText.onChange = function () {
bwr_editText.text = NaN20(parseFloat(bwr_editText.text));
createFresh();
};
var bwr_measureDrop = bwrAdjust.add("dropdownlist", undefined, bwrUnits);
bwr_measureDrop.selection = 3; // inch
//-------------------
var whiteBG_checkBox = adjustPanel.add ("checkbox", undefined, "White background");
whiteBG_checkBox.value = Pm.UiPreset.getProp('whiteBox');
whiteBG_checkBox.onClick = function () {
createFresh();
}
var quiet_checkBox = adjustPanel.add ("checkbox", undefined, "Quiet Zone Indicator");
quiet_checkBox.value = Pm.UiPreset.getProp('qZoneIndicator');
quiet_checkBox.onClick = function () {
createFresh();
}
/* We choose this automatically now based on type
ISSN, ISBN, ISMN will get human readable string above EAN code
var HumanRead_checkBox = adjustPanel.add ("checkbox", undefined, "Human-readable");
HumanRead_checkBox.value = Pm.UiPreset.getProp('humanReadable');
HumanRead_checkBox.onClick = function () {
createFresh();
}
*/
// End adjustment panel
// Add Buttons
//-------------
var presetDropGroup = presetPanel.add('group');
var cancelBut = presetPanel.add('button', undefined, 'Cancel', {name: 'cancel'});
var okBut = presetPanel.add('button', undefined, 'Generate', {name: 'OK'});
// Set Return/Enter key to OK window
okBut.shortcutKey = 'R';
okBut.onShortcutKey = okBut.onClick;
dialog.defaultElement = okBut;
// End buttons
//-------------
function humanReadBool( eanString ) {
// This function checks if EAN-13 barcode needs human readable string
// Returns True or False
var prefix = String(eanString).replace(/[^\dXx]+/g, '').substring(0, 3);
switch( prefix ) {
case "977":
case "978":
case "979":
return true;
break;
default:
return false;
break;
}
}
function getData(){
// This function creates a new preset from UI data
try {
var NewPreset = Pm.UiPreset.get();
}catch(err){
alert(err);
}
// update NewPreset with latest data
NewPreset.ean = eanInput.text.replace(/[^0-9X\-]/gi, ''); // Preserve human readable
NewPreset.addon = addonText.text.replace(/[^\d]+/g, '');
// Update Custom Settings
NewPreset.codeFont = codeFontSelect.getFont();
NewPreset.readFont = readFontSelect.getFont();
NewPreset.scalePercent = parseFloat(scalePercent_editText.text);
NewPreset.heightPercent = parseFloat(heightPercent_editText.text);
NewPreset.whiteBox = whiteBG_checkBox.value;
NewPreset.qZoneIndicator = quiet_checkBox.value;
NewPreset.humanReadable = humanReadBool(NewPreset.ean);
NewPreset.dpi = parseInt(dpi_editText.text);
NewPreset.bwr = {value: parseFloat(bwr_editText.text), unit: bwr_measureDrop.selection.text};
NewPreset.alignTo = alignTo_dropDown.selection.text;
NewPreset.refPoint = getSelectedReferencePoint();
NewPreset.offset = { x : parseFloat(offsetX_editText.text), y : parseFloat(offsetY_editText.text) };
if( pageSelect_dropDown.visible ) {
NewPreset.pageIndex = pageSelect_dropDown.selection.index;
}
return NewPreset;
}
function renderData( p ) {
userChange = false;
var startingLockChar = Pm.Widget.getLockChars()[0];
var re = new RegExp(escapeRegExp(startingLockChar) + " [0-9-]{8,}", "g");
if( String(p.name).match(re) ) {
// Update buton text to "Update"
okBut.text = "Update";
} else {
okBut.text = "Generate";
}
try {
// Set input
// Don’t update EAN if there is allready in dialog
// This should check wheter ean is valid?
if( eanInput.text.length < 8 ) {
eanInput.text = p.ean;
addonText.text = p.addon;
}
// Set Custom Settings
codeFontSelect.setFont(p.codeFont);
readFontSelect.setFont(p.readFont);
scalePercent_editText.text = String(p.scalePercent);
heightPercent_editText.text = String(p.heightPercent);
whiteBG_checkBox.value = p.whiteBox;
quiet_checkBox.value = p.qZoneIndicator;
// HumanRead_checkBox.value = p.humanReadable;
dpi_editText.text = p.dpi;
bwr_editText.text = p.bwr.value;
bwr_measureDrop.selection = idUtil.find(bwrUnits, p.bwr.unit);
alignTo_dropDown.selection = idUtil.find(alignToOptions, p.alignTo);
setSelectedReferencePoint(p.refPoint);
offsetX_editText.text = String(p.offset.x);
offsetY_editText.text = String(p.offset.y);
if( pageSelect_dropDown.visible ) {
pageSelect_dropDown.selection = p.pageIndex;
}
checkEanInput();
} catch (err) {
alert("Error loading presets: " + err);
}
userChange = true;
}
// Attach widget
Pm.Widget.attachTo( presetDropGroup, 'name', { getData:getData, renderData:renderData }, { onloadIndex:onloadIndex } );
if (dialog.show() === 1) {
// Save anf get user settings
var preset = Pm.Widget.saveLastUsed();
var pureEAN = preset.ean.replace(/[^\dXx]+/g, '');
// Check EAN
//----------
if( pureEAN.length == 0 ) {
alert("Please enter a valid EAN code.\n");
return showDialog(-1); // Restart
} else if(pureEAN.length == 13){
if(pureEAN.substring(0, 3) == "977"){
var ISSN = pureEAN.substring(3, 10);
preset.humanReadableStr = "ISSN" + String.fromCharCode(0x2007) + ISSN.substring(0, 4) + "-" + ISSN.substring(4, 7) + calculateCheckDigit(ISSN);
} else if(pureEAN.substring(0, 4) == "9790"){
preset.humanReadableStr = "ISMN" + String.fromCharCode(0x2007) + preset.ean;
} else if(pureEAN.substring(0, 3) == "978" || pureEAN.substring(0, 3) == "979" ){
preset.humanReadableStr = "ISBN" + String.fromCharCode(0x2007) + preset.ean;
} else {
preset.humanReadableStr = "EAN-13" + String.fromCharCode(0x2007) + preset.ean;
}
} else if(pureEAN.length == 10){
// ISBN-10
preset.humanReadableStr = "ISBN" + String.fromCharCode(0x2007) + preset.ean;
preset.ean = ISBN.asIsbn13(pureEAN, true);
} else if(pureEAN.length == 8){
// ISSN
preset.humanReadableStr = "ISSN" + String.fromCharCode(0x2007) + preset.ean;
preset.ean = "977" + pureEAN.substring(0, 7) + "00";
preset.ean = preset.ean + calculateCheckDigit(preset.ean+"X");
}
if( !checkCheckDigit(preset.ean) ) {
alert("Check digit does not match.\n" + preset.ean);
return showDialog(-1); // Restart
}
if( (preset.addon != "") && (preset.addon.length != 2) && (preset.addon.length != 5) ){
alert("Addon should be 2 or 5 digits long.\nLength is: " + preset.addon.length );
return showDialog(-1); // Restart
}
// Check Scale Percent
//--------------------
if(preset.scalePercent > 200 || preset.scalePercent < 80 ) {
alert("Scale is outside target range.\nThe target size is 100% but the standards allow a range between 80% and 200%." );
return showDialog(-1); // Restart
}
// Check DPI and BWR values
//-------------------------
// Todo: 2345678909876543
// Check Fonts
//------------
if( (preset.readFont == null) || (preset.codeFont == null) ){
if(preset.readFont == null) preset.readFont = "";
if(preset.codeFont == null) preset.codeFont = "";
alert("Please select your fonts first");
return showDialog(-1); // Restart
}
if(okBut.text === "Generate") {
if( preset.alignTo === "Selection" ) {
preset.selectionBounds = selectionDetails.bounds;
} else if( preset.alignTo === "Barcode Box" ) {
preset.selectionBounds = barcodeBoxDetails.bounds;
} else {
preset.selectionBounds = [0,0,0,0];
}
} else {
// remove barcode
// Get existing barcodes in document and add check their settings
var existingBarcodes = idUtil.getItemsByName(activeDoc, "Barcode_Settings");
if(existingBarcodes.length > 0) {
for (i = 0; i < existingBarcodes.length; i++) {
var eBarcodePreset = getBarcodePreset(existingBarcodes[i]);
if( preset.name === ("[ "+ eBarcodePreset.ean +" ]") ) {
var barcodeGroup = existingBarcodes[i].parent;
// Make sure we have the right parent, sorry mum!
if(barcodeGroup.label == "Barcode_Complete") {
barcodeGroup.remove();
}
}
}
}
}
return preset;
}
else {
// User pressed cancel
return false;
}
};
// END barcode_ui.js
// Start BarcodeDrawer
var BarcodeDrawer = (function () {
var doc;
var originalRulers;
var page;
var layer;
var BD;
var fontSize;
var reduce;
var hpos;
var presetString;
var vShape = new polyPlotter();
function getBWR_mm( bwrObj, DPI ) {
switch( bwrObj.unit ) {
case "dots":
return ((1 / parseInt(DPI)) * bwrObj.value ) * 25.4;
break;
case "mm":
return bwrObj.value;
break;
case "µm":
return bwrObj.value * 0.001
break;
case "inch":
return bwrObj.value * 25.4;
break;
case "mils":
return bwrObj.value * 0.0254
break;
default:
break;
}
// If we get here something went wrong
alert("Not a valid BWR unit: " + bwrObj.unit );
return 0;
}
function drawVbox( x, y, w, h ) {
vShape.addRect( x, y, w, h );
}
function drawBox(page, x, y, boxWidth, boxHeight, colour) {
var rect = page.rectangles.add();
rect.appliedObjectStyle = doc.objectStyles.item(0);
rect.strokeWeight = 0;
rect.strokeColor = "None";
rect.fillColor = colour || "Black";
rect.geometricBounds = [y, x, y + boxHeight, x + boxWidth];
return rect;
}
function getNewDocument(preset, size, hide){
var hiding = false === hide;
var originalMarginPreference = {
top : app.marginPreferences.top,
left : app.marginPreferences.left,
bottom : app.marginPreferences.bottom,
right : app.marginPreferences.right,
columnCount : app.marginPreferences.columnCount,
columnGutter : app.marginPreferences.columnGutter
};
app.marginPreferences.top = 0;
app.marginPreferences.left = 0;
app.marginPreferences.bottom = 0;
app.marginPreferences.right = 0;
app.marginPreferences.columnCount = 1;
app.marginPreferences.columnGutter = 0;
var d = app.documents.add( !hiding );
d.insertLabel('build_by_ean13barcodegenerator', 'true');
d.insertLabel('EAN-13', preset.ean);
d.viewPreferences.horizontalMeasurementUnits = MeasurementUnits.MILLIMETERS;
d.viewPreferences.verticalMeasurementUnits = MeasurementUnits.MILLIMETERS;
d.viewPreferences.rulerOrigin = RulerOrigin.pageOrigin;
d.documentPreferences.facingPages = false;
d.documentPreferences.pagesPerDocument = 1;
if (typeof size != "undefined") {
d.documentPreferences.pageWidth = size.width;
d.documentPreferences.pageHeight = size.height;
}
//Reset the application default margin preferences to their former state.
app.marginPreferences.top = originalMarginPreference.top ;
app.marginPreferences.left = originalMarginPreference.left ;
app.marginPreferences.bottom = originalMarginPreference.bottom;
app.marginPreferences.right = originalMarginPreference.right ;
app.marginPreferences.columnCount = originalMarginPreference.columnCount;
app.marginPreferences.columnGutter = originalMarginPreference.columnGutter;
return d;
}
function getCurrentOrNewDocument(preset, size) {
var d = app.documents[0];
if (!d.isValid) {
d = getNewDocument(preset, size);
} else {
d.insertLabel('EAN-13', preset.ean);
}
return d;
}
function drawVbar( w, h, y) {
if (! h) {
h = BD.barHeight;
}
if (! y) {
y = BD.barsYoffset;
}
drawVbox(hpos + (reduce/2), y, w - reduce, h);
}
function drawAddonBar( addonWidth ) {
drawVbar( addonWidth, BD.addonHeight, BD.barsYoffset + BD.fontHeight);
}
function drawGuard() {
drawVbar(BD.xDimension, BD.guardHeight);
}
function startGuards() {
drawGuard();
hpos += BD.xDimension*2; // Guard plus space
drawGuard();
hpos += BD.xDimension; // Guard
}
function midGuards() {
hpos += BD.xDimension;
drawGuard();
hpos += BD.xDimension*2; // Guard plus space
drawGuard();
hpos += BD.xDimension*2; // Guard plus space
}
function endGuards() {
drawGuard();
hpos += BD.xDimension*2; // Guard plus space
drawGuard();
hpos += BD.xDimension; // Guard
}
function outline(preset, textBox){
// returns array of page elements
if(preset.createOulines && textBox.constructor.name == "TextFrame") {
try{
var elements = textBox.createOutlines();
} catch (err) {
alert("Could not create outlines\n" + err.description);
preset.createOulines = false; // Don't show this message again :)
}
return elements;
}
return [textBox];
}
function drawMain(page, preset, barWidths) {
var pattern = null;
var widths = null;
var barWidth = null;
var digit = null;
for (var i = 0; i < barWidths.length; i++) {
pattern = barWidths[i][0];
widths = barWidths[i][1];
digit = barWidths[i][2];
outline( preset, drawChar(page, preset, hpos, digit, preset.codeFont, fontSize, true) );
for (var j = 0; j < 4; j++) {
barWidth = widths[j];
if (pattern[j] === 1) {
drawVbar(barWidth * BD.xDimension);
}
hpos += barWidth * BD.xDimension;
}
if (i == 5) {
midGuards();
}
}
return fontSize;
}
function drawAddon(page, preset, addonWidths) {
var pattern = null;
var widths = null;
var aWidth = null;
var digit = null;
hpos += BD.addonGap;
hpos += BD.addonGap;
for (var i = 0; i < addonWidths.length; i++) {
pattern = addonWidths[i][0];
widths = addonWidths[i][1];
digit = addonWidths[i][2]; //may be undefined
if (digit) {
var textBox = drawChar(page, preset, hpos, digit, preset.codeFont, preset.codeFontSize-1, true, -BD.addonHeight-BD.fontHeight-BD.xDimension);
textBox.textFramePreferences.verticalJustification = VerticalJustification.CENTER_ALIGN;
outline(preset, textBox);
}
for (var j = 0; j < widths.length; j++) {
aWidth = widths[j] * BD.xDimension;
if (pattern[j] === 1) {
drawAddonBar( aWidth );
}
hpos += aWidth;
}
}
}
function fitTextBox(textBox, fitText, fitBox){
var textStyle = textBox.textStyleRanges[0];
var fontSize = textStyle.pointSize;
if (fitText) {
// Fit type to box
textBox.parentStory.alignToBaseline = false;
var safetyCounter = 0;
//Keep reducing fontsize until no more overset text
while (textBox.overflows && safetyCounter < 100) {
safetyCounter++;
if(fontSize > 1) {
fontSize -= 0.25;
textBox.parentStory.pointSize = fontSize;
} else {
continue;
}
}
}
if (fitBox) {
try {
// Fit frame to type
textBox.textFramePreferences.autoSizingReferencePoint = AutoSizingReferenceEnum.TOP_LEFT_POINT;
textBox.textFramePreferences.autoSizingType = AutoSizingTypeEnum.WIDTH_ONLY;
} catch (err) {
alert("Barcode: fitTextBox: Could not fit text box." + err.description);
}
}
return fontSize;
}
function drawText(page, x, y, boxWidth, boxHeight, text, font, fontSize, textAlign, frameAlign) {
try {
var textBox = page.textFrames.add();
textBox.appliedObjectStyle = doc.objectStyles.item(0);
textBox.contents = text;
textBox.textFramePreferences.verticalJustification = frameAlign;
var textStyle = textBox.textStyleRanges[0];
textStyle.appliedFont = font;
textStyle.pointSize = fontSize;
textStyle.justification = textAlign;
textBox.geometricBounds = [y, x, y + boxHeight, x + boxWidth];
// We don't want the numbers to hang outside the textframe!
textBox.parentStory.storyPreferences.opticalMarginAlignment = false;
// Always return the textbox
return textBox;
} catch (err) {
alert("Barcode: drawText: " + err);
return null;
}
}
function drawChar(page, preset, x, character, font, fontSize, fitBox, yOffset) {
var yOffset = yOffset || 0;
var y = yOffset + BD.yBottomBar;
var boxWidth = BD.digitWidth;
var boxHeight = BD.fontHeight;
var textBox = drawText(page, x, y, boxWidth, boxHeight, character, font, fontSize, Justification.LEFT_ALIGN, VerticalJustification.CENTER_ALIGN);
textBox.parentStory.alignToBaseline = false;
// We don't want lining figures!
try {
textBox.parentStory.otfFigureStyle = OTFFigureStyle.TABULAR_LINING;
} catch (e) {
// Not OTF
}
if(fitBox) {
var fitText = false;
fitTextBox(textBox, fitText, fitBox);
}
return textBox;
}
function savePresets(page) {
var savePresetBox = drawBox(page, hpos - startX, 0, BD.minBoxWidth, BD.minBoxHeight, 'None');
savePresetBox.label = presetString;
savePresetBox.name = "Barcode_Settings";
return savePresetBox;
}
function drawWhiteBox(page) {
var whiteBox = drawBox(page, 0, 0, BD.minBoxWidth, BD.minBoxHeight, bgSwatchName);
whiteBox.label = "barcode_whiteBox";
return whiteBox;
}
function drawBarcode( preset ) {
var barcode = Barcode().init( preset ); // barcode_library.js
var barWidths = barcode.getNormalisedWidths();
var addonWidths = barcode.getNormalisedAddon();
var barcodeFillSwatchName = "Barcode Bar Fill";
BD = barcode.getDimensions();
startX = BD.xDimension;
hpos = startX;
// Gain control: Dependent on paper properties and dot distribution.
reduce = getBWR_mm( preset.bwr, preset.dpi ); // 10% dotgain == 0.1
presetString = JSON.stringify( preset );
var BarcodeSize = { width : BD.minBoxWidth, height : BD.minBoxHeight };
var targetDoc = getCurrentOrNewDocument(preset, BarcodeSize);
var targetID = targetDoc.id;
// Create a temp doc to draw the barcode in
doc = getNewDocument(preset, BarcodeSize, false);
page = doc.pages[0];
var layer = doc.layers.add({name: 'barcode'});
var barStyle = {
name : barcodeFillSwatchName,
enableFill : true,
enableStroke : true,
fillColor : doc.swatches.itemByName('Black'),
strokeColor : doc.swatches.itemByName('None'),
}
var barsObjectStyle = doc.objectStyles.item(barcodeFillSwatchName);
if(! barsObjectStyle.isValid ) {
barsObjectStyle = doc.objectStyles.add( barStyle );
}
bgSwatchName = 'None';
if(preset.whiteBox){
bgSwatchName = 'Paper';
}
var barcodeElements = new Array();
drawWhiteBox(page);
savePresets(page);
// calculate the initial fontsize
// and use this size to draw the other characters
// this makes sure all numbers are the same size
var textBox = drawChar(page, preset, hpos, preset.ean[0], preset.codeFont, 20, false); //initial '9'
fontSize = fitTextBox(textBox, true, true); // Fit type size
outline(preset, textBox);
hpos += BD.digitWidth + BD.xDimension;
startX += BD.digitWidth + BD.xDimension;
startGuards();
preset.codeFontSize = drawMain(page, preset, barWidths);
endGuards();
if(preset.qZoneIndicator) {
var textBox = drawChar(page, preset, hpos, '>', preset.codeFont, preset.codeFontSize, true); //quiet zone indicator '>'
var elements = outline(preset, textBox);
}
if(preset.humanReadable && preset.humanReadableStr.length > 0) {
var textBox = drawText(page, BD.startingpos, 0, BD.humanReadableWidth, BD.barsYoffset,
preset.humanReadableStr, preset.readFont, 20, Justification.FULLY_JUSTIFIED, VerticalJustification.CENTER_ALIGN);
try {
textBox.parentStory.otfFigureStyle = OTFFigureStyle.PROPORTIONAL_LINING;
textBox.parentStory.kerningMethod = "$ID/Optical"; // Most fonts have bad kerning for all caps characters
textBox.parentStory.tracking = preset.readFontTracking;
} catch (e) {
alert("Warning drawBarcode(): Could not set story preference.\n" + e);
}
fitTextBox(textBox, true, false);
outline(preset, textBox);
}
if (addonWidths) {
drawAddon(page, preset, addonWidths);
}
vShape.drawToPage( doc.pages[0], {x: 0, y: 0, scale: 100, style: barcodeFillSwatchName } );
var BarcodeGroup = page.groups.add(layer.allPageItems);
BarcodeGroup.label = "Barcode_Complete";
// Now we have finished drawing we can move and position barcode in targetDoc
var targetDoc = app.documents.itemByID(targetID);
selectTopLayer(targetDoc);
var targetLayer = getAndSelectLayer(app.documents.itemByID(targetID), 'barcode');
var targetLayerLock = layerLocked(app.documents.itemByID(targetID).layers.item('barcode'), false);
// Duplicate barcodegroup to target document before we can move
var dupGroup = BarcodeGroup.duplicate(targetDoc.pages[0]);
doc.close(SaveOptions.NO); // We don't need the doc anymore
var targetPage = targetDoc.pages[0];
if( (preset.pageIndex > 0) && (preset.pageIndex < targetDoc.pages.length) ) {
targetPage = targetDoc.pages[preset.pageIndex];
}
originalTargetRulers = idUtil.setRuler(targetDoc, {units : "mm", origin : RulerOrigin.SPREAD_ORIGIN });
// Let's position the barcode now
dupGroup.move(targetPage.parent.pages[0]); // Move to first page on spread then move to spread position
dupGroup.visibleBounds = idUtil.calcOffset(dupGroup.visibleBounds, targetPage, preset);
//reset rulers and layer locks
idUtil.setRuler(targetDoc, originalTargetRulers);
layerLocked(targetDoc.layers.item('barcode'), targetLayerLock);
}
return {
drawBarcode: drawBarcode
}
})();
// END barcode_drawer.js
function main(){
// Get preset from user
var userPreset = showDialog();
if( userPreset ) {
BarcodeDrawer.drawBarcode( userPreset );
} // else: user pressed cancel
}
try {
// Run script with single undo if supported
if (parseFloat(app.version) < 6 || debug) {
main();
} else {
app.doScript(main, ScriptLanguage.JAVASCRIPT, undefined, UndoModes.ENTIRE_SCRIPT, "Expand State Abbreviations");
}
// Global error reporting
} catch ( error ) {
alert("I'm having trouble creating a quality barcode:\n" + error + " (Line " + error.line + " in file " + error.fileName + ")");
};
// END barcode_main.js