Last active
March 5, 2026 15:24
-
-
Save elmimmo/940d2039ebb9b8c77bbf01f45f674cc5 to your computer and use it in GitHub Desktop.
InDesign script to place pages from an InDesign document into a grid.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| //DESCRIPTION:Place pages from an InDesign document into a grid. | |
| /* | |
| Goal: | |
| - Select one or more source INDD files. | |
| - Calculate and preview a grid on the active page. | |
| - Place source pages at 100% (no rotation), creating destination pages as needed. | |
| - Draw overlay frames on the trim area of each placed page. | |
| Main behavior: | |
| - Uses slug area for imported page placement. | |
| - Uses trim area to calculate and draw overlay frames. | |
| - Lets you define gaps, usable margins, and stroke weight from the UI. | |
| - Shows live preview in a persistent palette. | |
| Notes: | |
| - UI values accept comma or dot as decimal separator. | |
| - If a number is entered without units, it is interpreted in the field's current unit. | |
| - Includes one extra preview row and column to indicate cells outside the usable area. | |
| by Jorge Hernández Valiñani (@Estudio Fénix) + Codex (GPT-5). | |
| */ | |
| #target "InDesign" | |
| #targetengine "gridImportPreview" | |
| (function () { | |
| var L = { | |
| openDocFirst: "Abre un documento antes de ejecutar el script.", | |
| selectInddFiles: "Selecciona uno o varios archivos INDD para colocar", | |
| firstFileNoPages: "El primer archivo no tiene paginas.", | |
| cannotMeasureFirstSlug: "No se pudo medir el area de anotacion del primer archivo.", | |
| cannotUseSlugCrop: "Tu version de InDesign no permite recortar INDD al area de anotacion (Slug).", | |
| fileSlugSizeMismatch: "El archivo '{0}' tiene paginas con tamanos de area de anotacion diferentes.", | |
| swatchNoneMissing: "No existe la muestra 'None' en el documento.", | |
| swatchBlackMissing: "No existe la muestra 'Black' en el documento.", | |
| previewSwatchesMissing: "No existen las muestras necesarias para la previsualizacion.", | |
| dialogTitle: "Importar a cuadricula", | |
| panelGrid: "Cuadricula", | |
| panelSpacing: "Espaciado", | |
| panelMargins: "Margenes", | |
| labelColumns: "Columnas:", | |
| labelRows: "Filas:", | |
| labelBorder: "Borde:", | |
| labelHorizontal: "Horizontal:", | |
| labelVertical: "Vertical:", | |
| labelSideMargins: "Laterales:", | |
| labelVerticalMargins: "Verticales:", | |
| labelCross: "x", | |
| labelRemainderDefault: "(+ 0,99)", | |
| labelCounterDefault: "99", | |
| defaultMarginText: "0 mm", | |
| labelRemainderPattern: "(+ {0})", | |
| buttonCancel: "Cancelar", | |
| buttonOk: "OK", | |
| noFitInPage: "Con esos valores no cabe ningun elemento en la pagina.", | |
| undoLabel: "Colocar INDD en rejilla", | |
| overlayLayerBaseName: "Marcos recorte", | |
| noFitForFile: "No cabe ninguna pagina de '{0}' con los parametros actuales.", | |
| noFitInTargetPage: "No cabe ninguna pagina en la pagina destino '{0}'.", | |
| errorPrefix: "Error: ", | |
| doneMessage: "Colocacion completada. Paginas colocadas: {0}." | |
| }; | |
| if (app.documents.length === 0) { | |
| alert(L.openDocFirst); | |
| return; | |
| } | |
| var targetDoc = app.activeDocument; | |
| var targetPage = app.activeWindow.activePage; | |
| var LOCALE_DECIMAL = getLocaleDecimalSeparator(); | |
| var DEBUG_GRID = true; | |
| var DOC_UNIT_X = measurementUnitToUnitValueUnit(targetDoc.viewPreferences.horizontalMeasurementUnits); | |
| var DOC_UNIT_Y = measurementUnitToUnitValueUnit(targetDoc.viewPreferences.verticalMeasurementUnits); | |
| var DEBUG_FORCE_SETTINGS = null; | |
| // Example for debugging without the palette: | |
| // DEBUG_FORCE_SETTINGS = { | |
| // horGapPt: new UnitValue(0, "mm").as("pt"), | |
| // verGapPt: new UnitValue(0, "mm").as("pt"), | |
| // strokePt: new UnitValue(1, "mm").as("pt"), | |
| // horMarPt: 0, | |
| // verMarPt: 0, | |
| // autoHorMargin: true, | |
| // autoVerMargin: true | |
| // }; | |
| var files = File.openDialog( | |
| L.selectInddFiles, | |
| function (f) { return f instanceof Folder || /\.indd$/i.test(f.name); }, | |
| true | |
| ); | |
| if (!files || files.length === 0) { | |
| return; | |
| } | |
| var originalPageNumber = app.importedPageAttributes.pageNumber; | |
| var originalCrop = app.importedPageAttributes.importedPageCrop; | |
| var placementCrop = resolveImportedPageCrop(); | |
| var sourceInfoCache = {}; | |
| var firstSource = getSourceInfo(files[0], sourceInfoCache); | |
| if (firstSource.pageCount < 1) { | |
| alert(L.firstFileNoPages); | |
| return; | |
| } | |
| var firstSlugSize = measurePlacedSlugSize(targetPage, targetDoc, files[0], placementCrop, 1, originalPageNumber, originalCrop); | |
| if (!firstSlugSize) { | |
| alert(L.cannotMeasureFirstSlug); | |
| return; | |
| } | |
| var pageBounds = targetPage.bounds; | |
| var pageWidth = pageBounds[3] - pageBounds[1]; | |
| var pageHeight = pageBounds[2] - pageBounds[0]; | |
| if (DEBUG_FORCE_SETTINGS) { | |
| executePlacement(DEBUG_FORCE_SETTINGS); | |
| return; | |
| } | |
| showGridDialog(targetDoc, targetPage, pageWidth, pageHeight, firstSlugSize.width, firstSlugSize.height, firstSource.pageCount, executePlacement); | |
| function resolveImportedPageCrop() { | |
| var slug = getImportedCropOption("CROP_SLUG"); | |
| if (slug !== null) { | |
| return slug; | |
| } | |
| throw new Error(L.cannotUseSlugCrop); | |
| } | |
| function getImportedCropOption(name) { | |
| try { | |
| if (typeof ImportedPageCropOptions === "undefined") { | |
| return null; | |
| } | |
| var value = ImportedPageCropOptions[name]; | |
| if (value === undefined || value === null) { | |
| return null; | |
| } | |
| return value; | |
| } catch (_) { | |
| return null; | |
| } | |
| } | |
| function getSourceInfo(file, cache) { | |
| var key = file.fsName; | |
| if (cache[key]) { | |
| return cache[key]; | |
| } | |
| var src = app.open(file, false); | |
| var info; | |
| try { | |
| info = buildSourceInfo(src); | |
| } finally { | |
| src.close(SaveOptions.NO); | |
| } | |
| cache[key] = info; | |
| return info; | |
| } | |
| function buildSourceInfo(srcDoc) { | |
| var dp = srcDoc.documentPreferences; | |
| var facing = dp.facingPages; | |
| var slugTop = dp.slugTopOffset; | |
| var slugBottom = dp.slugBottomOffset; | |
| var slugInsideOrLeft = dp.slugInsideOrLeftOffset; | |
| var slugOutsideOrRight = dp.slugRightOrOutsideOffset; | |
| var pageCount = srcDoc.pages.length; | |
| var metricsByPage = {}; | |
| for (var i = 0; i < pageCount; i++) { | |
| var p = srcDoc.pages[i]; | |
| var pb = p.bounds; | |
| var trimWidth = pb[3] - pb[1]; | |
| var trimHeight = pb[2] - pb[0]; | |
| var slugLeft = slugInsideOrLeft; | |
| var slugRight = slugOutsideOrRight; | |
| if (facing && p.side === PageSideOptions.LEFT_HAND) { | |
| slugLeft = slugOutsideOrRight; | |
| slugRight = slugInsideOrLeft; | |
| } | |
| metricsByPage[i + 1] = { | |
| slugWidth: trimWidth + slugLeft + slugRight, | |
| slugHeight: trimHeight + slugTop + slugBottom, | |
| trimWidth: trimWidth, | |
| trimHeight: trimHeight, | |
| trimLeftFromSlugLeft: slugLeft, | |
| trimTopFromSlugTop: slugTop | |
| }; | |
| } | |
| return { | |
| pageCount: pageCount, | |
| metricsByPage: metricsByPage | |
| }; | |
| } | |
| function validateUniformSlugSize(file, srcInfo) { | |
| if (srcInfo.pageCount < 2) { | |
| return; | |
| } | |
| var first = srcInfo.metricsByPage[1]; | |
| for (var i = 2; i <= srcInfo.pageCount; i++) { | |
| var m = srcInfo.metricsByPage[i]; | |
| if (Math.abs(m.slugWidth - first.slugWidth) > 0.01 || Math.abs(m.slugHeight - first.slugHeight) > 0.01) { | |
| throw new Error(lfmt(L.fileSlugSizeMismatch, file.name)); | |
| } | |
| } | |
| } | |
| function buildGridPlan(page, itemWidth, itemHeight, settings) { | |
| var pb = page.bounds; | |
| var pageLeft = pb[1]; | |
| var pageTop = pb[0]; | |
| var pageWidth = pb[3] - pb[1]; | |
| var pageHeight = pb[2] - pb[0]; | |
| var strokeX = ptToDocX(settings.strokePt); | |
| var strokeY = ptToDocY(settings.strokePt); | |
| var gapX = ptToDocX(settings.horGapPt); | |
| var gapY = ptToDocY(settings.verGapPt); | |
| var marginX = ptToDocX(settings.horMarPt); | |
| var marginY = ptToDocY(settings.verMarPt); | |
| var calcX = calcAxis(pageWidth, itemWidth, gapX, strokeX, marginX, settings.autoHorMargin); | |
| var calcY = calcAxis(pageHeight, itemHeight, gapY, strokeY, marginY, settings.autoVerMargin); | |
| return { | |
| pageLeft: pageLeft, | |
| pageTop: pageTop, | |
| itemWidth: itemWidth, | |
| itemHeight: itemHeight, | |
| strokeX: strokeX, | |
| strokeY: strokeY, | |
| gapX: gapX, | |
| gapY: gapY, | |
| cols: calcX.total, | |
| rows: calcY.total, | |
| marginX: calcX.margin, | |
| marginY: calcY.margin, | |
| capacity: calcX.total * calcY.total, | |
| slotIndex: 0 | |
| }; | |
| } | |
| function gridPlanKey(plan) { | |
| return [ | |
| round4(plan.itemWidth), | |
| round4(plan.itemHeight), | |
| round4(plan.strokeX), | |
| round4(plan.strokeY), | |
| round4(plan.gapX), | |
| round4(plan.gapY), | |
| plan.cols, | |
| plan.rows, | |
| round4(plan.marginX), | |
| round4(plan.marginY) | |
| ].join("|"); | |
| } | |
| function slotFrameBounds(plan, index) { | |
| var col = index % plan.cols; | |
| var row = Math.floor(index / plan.cols); | |
| var stepX = plan.itemWidth + (2 * plan.strokeX) + plan.gapX; | |
| var stepY = plan.itemHeight + (2 * plan.strokeY) + plan.gapY; | |
| var outerLeft = plan.pageLeft + plan.marginX + (col * stepX); | |
| var outerTop = plan.pageTop + plan.marginY + (row * stepY); | |
| var frameLeft = outerLeft + plan.strokeX; | |
| var frameTop = outerTop + plan.strokeY; | |
| return [frameTop, frameLeft, frameTop + plan.itemHeight, frameLeft + plan.itemWidth]; | |
| } | |
| function getOverlayBoundsFromSourceMetrics(placedFrame, metrics) { | |
| if (!metrics || metrics.slugWidth <= 0 || metrics.slugHeight <= 0) { | |
| return placedFrame.geometricBounds; | |
| } | |
| var pb = placedFrame.geometricBounds; | |
| var frameTop = pb[0]; | |
| var frameLeft = pb[1]; | |
| var frameWidth = pb[3] - pb[1]; | |
| var frameHeight = pb[2] - pb[0]; | |
| var scaleX = frameWidth / metrics.slugWidth; | |
| var scaleY = frameHeight / metrics.slugHeight; | |
| var left = frameLeft + (metrics.trimLeftFromSlugLeft * scaleX); | |
| var top = frameTop + (metrics.trimTopFromSlugTop * scaleY); | |
| var right = left + (metrics.trimWidth * scaleX); | |
| var bottom = top + (metrics.trimHeight * scaleY); | |
| return [top, left, bottom, right]; | |
| } | |
| function createOverlayFrame(doc, page, layer, bounds, weight, tint) { | |
| var noneSwatch = doc.swatches.itemByName("None"); | |
| if (!noneSwatch.isValid) { | |
| throw new Error(L.swatchNoneMissing); | |
| } | |
| var blackSwatch = doc.swatches.itemByName("Black"); | |
| if (!blackSwatch.isValid) { | |
| throw new Error(L.swatchBlackMissing); | |
| } | |
| var rect = page.rectangles.add({ | |
| geometricBounds: bounds, | |
| itemLayer: layer, | |
| fillColor: noneSwatch, | |
| strokeColor: blackSwatch, | |
| strokeTint: tint, | |
| strokeWeight: weight | |
| }); | |
| enforceOutsideOrCompensate(rect, weight); | |
| return rect; | |
| } | |
| function getOrCreateOverlayLayer(doc, baseName) { | |
| var existing = doc.layers.itemByName(baseName); | |
| if (existing.isValid) { | |
| if (existing.allPageItems.length === 0) { | |
| return existing; | |
| } | |
| var n = 2; | |
| while (doc.layers.itemByName(baseName + " " + n).isValid) { | |
| n++; | |
| } | |
| return doc.layers.add({ name: baseName + " " + n }); | |
| } | |
| return doc.layers.add({ name: baseName }); | |
| } | |
| function moveLayerToTop(layer) { | |
| try { layer.move(LocationOptions.AT_BEGINNING); } catch (_) {} | |
| } | |
| function showGridDialog(doc, page, pageWidth, pageHeight, itemWidth, itemHeight, previewPageCount, onAccept) { | |
| var defaultGapPt = new UnitValue(5, "mm").as("pt"); | |
| var defaultStrokePt = 2; | |
| var previewItems = []; | |
| var previewLayer = null; | |
| var blackSwatch = doc.swatches.itemByName("Black"); | |
| var blueSwatch = getOrCreatePreviewBlueSwatch(doc); | |
| var noneSwatch = doc.swatches.itemByName("None"); | |
| var redSwatch = getOrCreatePreviewRedSwatch(doc); | |
| if (!blackSwatch.isValid || !blueSwatch.isValid || !noneSwatch.isValid || !redSwatch.isValid) { | |
| throw new Error(L.previewSwatchesMissing); | |
| } | |
| previewLayer = doc.layers.add({ name: "__preview_rejilla_tmp__" + (new Date().getTime()) }); | |
| moveLayerToTop(previewLayer); | |
| var state = { | |
| horGapPt: defaultGapPt, | |
| verGapPt: defaultGapPt, | |
| strokePt: defaultStrokePt, | |
| horMarPt: 0, | |
| verMarPt: 0, | |
| horGapUnit: "mm", | |
| verGapUnit: "mm", | |
| strokeUnit: "pt", | |
| horMarUnit: "mm", | |
| verMarUnit: "mm", | |
| autoHorMargin: true, | |
| autoVerMargin: true, | |
| horTot: 0, | |
| verTot: 0 | |
| }; | |
| var dialog = new Window("palette"); | |
| dialog.text = L.dialogTitle; | |
| dialog.orientation = "column"; | |
| dialog.alignChildren = ["left", "top"]; | |
| dialog.spacing = 10; | |
| dialog.margins = 16; | |
| var panel1 = dialog.add("panel", undefined, undefined, {name: "panel1"}); | |
| panel1.text = L.panelGrid; | |
| panel1.orientation = "column"; | |
| panel1.alignChildren = ["left", "top"]; | |
| panel1.spacing = 10; | |
| panel1.margins = 10; | |
| panel1.alignment = ["fill", "top"]; | |
| var group1 = panel1.add("group", undefined, {name: "group1"}); | |
| group1.orientation = "row"; | |
| group1.alignChildren = ["left", "center"]; | |
| group1.spacing = 10; | |
| group1.margins = 0; | |
| var group2 = group1.add("group", undefined, {name: "group2"}); | |
| group2.orientation = "row"; | |
| group2.alignChildren = ["left", "center"]; | |
| group2.spacing = 10; | |
| group2.margins = 0; | |
| var statictext1 = group2.add("statictext", undefined, undefined, {name: "statictext1"}); | |
| statictext1.text = L.labelColumns; | |
| var horTot = group2.add("statictext", undefined, undefined, {name: "horTot"}); | |
| horTot.text = L.labelCounterDefault; | |
| horTot.preferredSize.width = 15; | |
| var horTotRem = group2.add("statictext", undefined, undefined, {name: "horTotRem"}); | |
| horTotRem.text = L.labelRemainderDefault; | |
| var group3 = group1.add("group", undefined, {name: "group3"}); | |
| group3.orientation = "column"; | |
| group3.alignChildren = ["left", "center"]; | |
| group3.spacing = 10; | |
| group3.margins = 0; | |
| var statictext2 = group3.add("statictext", undefined, undefined, {name: "statictext2"}); | |
| statictext2.text = L.labelCross; | |
| var group4 = group1.add("group", undefined, {name: "group4"}); | |
| group4.orientation = "row"; | |
| group4.alignChildren = ["left", "center"]; | |
| group4.spacing = 10; | |
| group4.margins = 0; | |
| var statictext3 = group4.add("statictext", undefined, undefined, {name: "statictext3"}); | |
| statictext3.text = L.labelRows; | |
| var verTot = group4.add("statictext", undefined, undefined, {name: "verTot"}); | |
| verTot.text = L.labelCounterDefault; | |
| verTot.preferredSize.width = 15; | |
| var verTotRem = group4.add("statictext", undefined, undefined, {name: "verTotRem"}); | |
| verTotRem.text = L.labelRemainderDefault; | |
| var group5 = panel1.add("group", undefined, {name: "group5"}); | |
| group5.orientation = "row"; | |
| group5.alignChildren = ["left", "center"]; | |
| group5.spacing = 10; | |
| group5.margins = 0; | |
| var statictext4 = group5.add("statictext", undefined, undefined, {name: "statictext4"}); | |
| statictext4.text = L.labelBorder; | |
| var stroke = group5.add('edittext {justify: "right", properties: {name: "stroke"}}'); | |
| stroke.text = formatPtAsUnit(defaultStrokePt, "pt"); | |
| stroke.preferredSize.width = 63; | |
| var group6 = dialog.add("group", undefined, {name: "group6"}); | |
| group6.orientation = "row"; | |
| group6.alignChildren = ["left", "center"]; | |
| group6.spacing = 10; | |
| group6.margins = 0; | |
| var panel2 = group6.add("panel", undefined, undefined, {name: "panel2"}); | |
| panel2.text = L.panelSpacing; | |
| panel2.orientation = "column"; | |
| panel2.alignChildren = ["left", "top"]; | |
| panel2.spacing = 10; | |
| panel2.margins = 10; | |
| var group7 = panel2.add("group", undefined, {name: "group7"}); | |
| group7.orientation = "row"; | |
| group7.alignChildren = ["left", "center"]; | |
| group7.spacing = 10; | |
| group7.margins = 0; | |
| var statictext5 = group7.add("statictext", undefined, undefined, {name: "statictext5"}); | |
| statictext5.text = L.labelHorizontal; | |
| statictext5.preferredSize.width = 70; | |
| var horGap = group7.add('edittext {justify: "right", properties: {name: "horGap"}}'); | |
| horGap.text = formatPtAsMm(defaultGapPt); | |
| horGap.preferredSize.width = 63; | |
| var group8 = panel2.add("group", undefined, {name: "group8"}); | |
| group8.orientation = "row"; | |
| group8.alignChildren = ["left", "center"]; | |
| group8.spacing = 10; | |
| group8.margins = 0; | |
| var statictext6 = group8.add("statictext", undefined, undefined, {name: "statictext6"}); | |
| statictext6.text = L.labelVertical; | |
| statictext6.preferredSize.width = 70; | |
| var verGap = group8.add('edittext {justify: "right", properties: {name: "verGap"}}'); | |
| verGap.text = formatPtAsMm(defaultGapPt); | |
| verGap.preferredSize.width = 63; | |
| var panel3 = group6.add("panel", undefined, undefined, {name: "panel3"}); | |
| panel3.text = L.panelMargins; | |
| panel3.orientation = "column"; | |
| panel3.alignChildren = ["left", "center"]; | |
| panel3.spacing = 10; | |
| panel3.margins = 10; | |
| var group9 = panel3.add("group", undefined, {name: "group9"}); | |
| group9.orientation = "column"; | |
| group9.alignChildren = ["left", "center"]; | |
| group9.spacing = 10; | |
| group9.margins = 0; | |
| var group10 = group9.add("group", undefined, {name: "group10"}); | |
| group10.orientation = "row"; | |
| group10.alignChildren = ["left", "center"]; | |
| group10.spacing = 10; | |
| group10.margins = 0; | |
| var statictext7 = group10.add("statictext", undefined, undefined, {name: "statictext7"}); | |
| statictext7.text = L.labelSideMargins; | |
| var horMar = group10.add('edittext {justify: "right", properties: {name: "horMar"}}'); | |
| horMar.text = L.defaultMarginText; | |
| horMar.preferredSize.width = 63; | |
| var group11 = panel3.add("group", undefined, {name: "group11"}); | |
| group11.orientation = "column"; | |
| group11.alignChildren = ["left", "center"]; | |
| group11.spacing = 10; | |
| group11.margins = 0; | |
| var group12 = group11.add("group", undefined, {name: "group12"}); | |
| group12.orientation = "row"; | |
| group12.alignChildren = ["left", "center"]; | |
| group12.spacing = 10; | |
| group12.margins = 0; | |
| var statictext8 = group12.add("statictext", undefined, undefined, {name: "statictext8"}); | |
| statictext8.text = L.labelVerticalMargins; | |
| var verMar = group12.add('edittext {justify: "right", properties: {name: "verMar"}}'); | |
| verMar.text = L.defaultMarginText; | |
| verMar.preferredSize.width = 63; | |
| var group13 = dialog.add("group", undefined, {name: "group13"}); | |
| group13.orientation = "row"; | |
| group13.alignChildren = ["right", "center"]; | |
| group13.spacing = 10; | |
| group13.margins = [0, 11, 0, 0]; | |
| group13.alignment = ["fill", "top"]; | |
| var button1 = group13.add("button", undefined, undefined, {name: "button1"}); | |
| button1.text = L.buttonCancel; | |
| button1.preferredSize.width = 90; | |
| var ok = group13.add("button", undefined, undefined, {name: "ok"}); | |
| ok.text = L.buttonOk; | |
| ok.preferredSize.width = 90; | |
| function recalc() { | |
| var parsedGapX = parseMeasureToPtInCurrentUnit(horGap.text, state.horGapPt, state.horGapUnit); | |
| var parsedGapY = parseMeasureToPtInCurrentUnit(verGap.text, state.verGapPt, state.verGapUnit); | |
| var parsedStroke = parseMeasureToPtInCurrentUnit(stroke.text, state.strokePt, state.strokeUnit); | |
| state.horGapPt = Math.max(0, parsedGapX.valuePt); | |
| state.verGapPt = Math.max(0, parsedGapY.valuePt); | |
| state.strokePt = Math.max(0, parsedStroke.valuePt); | |
| state.horGapUnit = parsedGapX.unit; | |
| state.verGapUnit = parsedGapY.unit; | |
| state.strokeUnit = parsedStroke.unit; | |
| var parsedHorMar = parseMeasureToPtInCurrentUnit(horMar.text, state.horMarPt, state.horMarUnit); | |
| var parsedVerMar = parseMeasureToPtInCurrentUnit(verMar.text, state.verMarPt, state.verMarUnit); | |
| state.horMarPt = Math.max(0, parsedHorMar.valuePt); | |
| state.verMarPt = Math.max(0, parsedVerMar.valuePt); | |
| state.horMarUnit = parsedHorMar.unit; | |
| state.verMarUnit = parsedVerMar.unit; | |
| var gapX = ptToDocX(state.horGapPt); | |
| var gapY = ptToDocY(state.verGapPt); | |
| var strokeX = ptToDocX(state.strokePt); | |
| var strokeY = ptToDocY(state.strokePt); | |
| var marginX = ptToDocX(state.horMarPt); | |
| var marginY = ptToDocY(state.verMarPt); | |
| var ax = calcAxis(pageWidth, itemWidth, gapX, strokeX, marginX, state.autoHorMargin); | |
| var ay = calcAxis(pageHeight, itemHeight, gapY, strokeY, marginY, state.autoVerMargin); | |
| state.horTot = ax.total; | |
| state.verTot = ay.total; | |
| state.horMarPt = docXToPt(ax.outerMargin); | |
| state.verMarPt = docYToPt(ay.outerMargin); | |
| horTot.text = String(ax.total); | |
| verTot.text = String(ay.total); | |
| if (state.autoHorMargin) { | |
| horMar.text = formatPtAsUnit(state.horMarPt, state.horMarUnit); | |
| } | |
| if (state.autoVerMargin) { | |
| verMar.text = formatPtAsUnit(state.verMarPt, state.verMarUnit); | |
| } | |
| updateRemLabel(horTotRem, ax.step, ax.remainder); | |
| updateRemLabel(verTotRem, ay.step, ay.remainder); | |
| refreshPreview(ax, ay); | |
| } | |
| function normalizeInputFields() { | |
| horGap.text = formatPtAsUnit(state.horGapPt, state.horGapUnit); | |
| verGap.text = formatPtAsUnit(state.verGapPt, state.verGapUnit); | |
| stroke.text = formatPtAsUnit(state.strokePt, state.strokeUnit); | |
| if (!state.autoHorMargin) { | |
| horMar.text = formatPtAsUnit(state.horMarPt, state.horMarUnit); | |
| } | |
| if (!state.autoVerMargin) { | |
| verMar.text = formatPtAsUnit(state.verMarPt, state.verMarUnit); | |
| } | |
| } | |
| function updateRemLabel(label, step, remainder) { | |
| if (Math.abs(remainder) < 0.0001) { | |
| label.visible = false; | |
| return; | |
| } | |
| label.visible = true; | |
| label.text = lfmt(L.labelRemainderPattern, formatNumberLocale(remainder / step, 2)); | |
| } | |
| horGap.onChange = function () { recalc(); normalizeInputFields(); }; | |
| verGap.onChange = function () { recalc(); normalizeInputFields(); }; | |
| stroke.onChange = function () { recalc(); normalizeInputFields(); }; | |
| horGap.onChanging = function () { recalc(); }; | |
| verGap.onChanging = function () { recalc(); }; | |
| stroke.onChanging = function () { recalc(); }; | |
| horMar.onChange = function () { | |
| state.autoHorMargin = false; | |
| recalc(); | |
| normalizeInputFields(); | |
| }; | |
| horMar.onChanging = function () { | |
| state.autoHorMargin = false; | |
| recalc(); | |
| }; | |
| verMar.onChange = function () { | |
| state.autoVerMargin = false; | |
| recalc(); | |
| normalizeInputFields(); | |
| }; | |
| verMar.onChanging = function () { | |
| state.autoVerMargin = false; | |
| recalc(); | |
| }; | |
| bindArrowStep(horGap, function () { return state.horGapPt; }, function (v) { state.horGapPt = v; }, function () { return state.horGapUnit; }); | |
| bindArrowStep(verGap, function () { return state.verGapPt; }, function (v) { state.verGapPt = v; }, function () { return state.verGapUnit; }); | |
| bindArrowStep(stroke, function () { return state.strokePt; }, function (v) { state.strokePt = v; }, function () { return state.strokeUnit; }); | |
| bindArrowStep( | |
| horMar, | |
| function () { return state.horMarPt; }, | |
| function (v) { | |
| state.autoHorMargin = false; | |
| state.horMarPt = v; | |
| }, | |
| function () { return state.horMarUnit; } | |
| ); | |
| bindArrowStep( | |
| verMar, | |
| function () { return state.verMarPt; }, | |
| function (v) { | |
| state.autoVerMargin = false; | |
| state.verMarPt = v; | |
| }, | |
| function () { return state.verMarUnit; } | |
| ); | |
| button1.onClick = function () { | |
| cleanupPreview(); | |
| dialog.close(); | |
| }; | |
| ok.onClick = function () { | |
| recalc(); | |
| if (state.horTot < 1 || state.verTot < 1) { | |
| alert(L.noFitInPage); | |
| return; | |
| } | |
| normalizeInputFields(); | |
| var payload = { | |
| horGapPt: state.horGapPt, | |
| verGapPt: state.verGapPt, | |
| strokePt: state.strokePt, | |
| horMarPt: state.horMarPt, | |
| verMarPt: state.verMarPt, | |
| autoHorMargin: state.autoHorMargin, | |
| autoVerMargin: state.autoVerMargin | |
| }; | |
| cleanupPreview(); | |
| dialog.close(); | |
| onAccept(payload); | |
| }; | |
| dialog.onClose = function () { | |
| cleanupPreview(); | |
| try { $.global.__gridImportPalette = null; } catch (_) {} | |
| return true; | |
| }; | |
| recalc(); | |
| try { $.global.__gridImportPalette = dialog; } catch (_) {} | |
| dialog.show(); | |
| function refreshPreview(ax, ay) { | |
| clearPreview(); | |
| if (ax.total < 1 || ay.total < 1) { | |
| safeRedraw(); | |
| return; | |
| } | |
| var pb = page.bounds; | |
| var pageTop = pb[0]; | |
| var pageLeft = pb[1]; | |
| var pageRight = pb[3]; | |
| var pageBottom = pb[2]; | |
| var strokeX = ptToDocX(state.strokePt); | |
| var strokeY = ptToDocY(state.strokePt); | |
| var gapX = ptToDocX(state.horGapPt); | |
| var gapY = ptToDocY(state.verGapPt); | |
| var stepX = itemWidth + (2 * strokeX) + gapX; | |
| var stepY = itemHeight + (2 * strokeY) + gapY; | |
| var maxPreview = 2000; | |
| var count = 0; | |
| var firstInRowPrevRect = null; | |
| var debugPrinted = 0; | |
| for (var r = 0; r <= ay.total; r++) { | |
| for (var c = 0; c <= ax.total; c++) { | |
| if (count >= maxPreview) { | |
| return; | |
| } | |
| var outerLeft = pageLeft + ax.margin + (c * stepX); | |
| var outerTop = pageTop + ay.margin + (r * stepY); | |
| var frameLeft = outerLeft + strokeX; | |
| var frameTop = outerTop + strokeY; | |
| var frameRight = frameLeft + itemWidth; | |
| var frameBottom = frameTop + itemHeight; | |
| var previewRect = page.rectangles.add({ | |
| geometricBounds: [frameTop, frameLeft, frameBottom, frameRight], | |
| itemLayer: previewLayer, | |
| fillColor: blackSwatch, | |
| strokeColor: blueSwatch, | |
| strokeWeight: state.strokePt, | |
| strokeTint: 10 | |
| }); | |
| var isExtra = (r === ay.total || c === ax.total); | |
| if (isExtra) { | |
| previewRect.fillTint = 10; | |
| } else { | |
| var idx = (r * ax.total) + c; | |
| previewRect.fillTint = (idx < previewPageCount) ? 50 : 30; | |
| } | |
| enforceOutsideOrCompensate(previewRect, state.strokePt); | |
| if (DEBUG_GRID && debugPrinted < 8) { | |
| var gb = previewRect.geometricBounds; | |
| var vb = previewRect.visibleBounds; | |
| dbg("PREVIEW r=" + r + " c=" + c + | |
| " gapH=" + round4(gapX) + | |
| " strokeX=" + round4(strokeX) + | |
| " outerLeft=" + round4(outerLeft) + | |
| " frameLeft=" + round4(frameLeft) + | |
| " gbL=" + round4(gb[1]) + " gbR=" + round4(gb[3]) + | |
| " vbL=" + round4(vb[1]) + " vbR=" + round4(vb[3])); | |
| if (c === 1 && firstInRowPrevRect && firstInRowPrevRect.isValid) { | |
| var prevVb = firstInRowPrevRect.visibleBounds; | |
| var gapReal = vb[1] - prevVb[3]; | |
| dbg("REAL_GAP_ROW r=" + r + " between c0->c1 = " + round4(gapReal) + " pt"); | |
| } | |
| debugPrinted++; | |
| } | |
| if (c === 0) { | |
| firstInRowPrevRect = previewRect; | |
| } | |
| previewItems.push(previewRect); | |
| count++; | |
| } | |
| } | |
| // Usable area defined by horMar/verMar (drawn above the rest of preview rectangles). | |
| var utilRect = page.rectangles.add({ | |
| geometricBounds: [ | |
| pageTop + ay.outerMargin, | |
| pageLeft + ax.outerMargin, | |
| pageBottom - ay.outerMargin, | |
| pageRight - ax.outerMargin | |
| ], | |
| itemLayer: previewLayer, | |
| fillColor: noneSwatch, | |
| strokeColor: redSwatch, | |
| strokeWeight: 0.1 | |
| }); | |
| previewItems.push(utilRect); | |
| safeRedraw(); | |
| } | |
| function clearPreview() { | |
| for (var i = previewItems.length - 1; i >= 0; i--) { | |
| if (previewItems[i] && previewItems[i].isValid) { | |
| previewItems[i].remove(); | |
| } | |
| } | |
| previewItems = []; | |
| safeRedraw(); | |
| } | |
| function cleanupPreview() { | |
| clearPreview(); | |
| if (previewLayer && previewLayer.isValid) { | |
| try { | |
| previewLayer.remove(); | |
| } catch (_) {} | |
| } | |
| } | |
| function safeRedraw() { | |
| try { | |
| app.redraw(); | |
| } catch (_) {} | |
| } | |
| function bindArrowStep(field, getValueFn, setValueFn, getUnitFn) { | |
| var stepPt = new UnitValue(1, "mm").as("pt"); | |
| field.addEventListener("keydown", function (ev) { | |
| var keyName = ""; | |
| try { keyName = ev.keyName || ""; } catch (eKn) {} | |
| var isUp = (keyName === "Up" || keyName === "UpArrow"); | |
| var isDown = (keyName === "Down" || keyName === "DownArrow"); | |
| if (!isUp && !isDown) { | |
| return; | |
| } | |
| var current = parseMeasureToPt(field.text, getValueFn()); | |
| var next = current + (isUp ? stepPt : -stepPt); | |
| if (next < 0) { | |
| next = 0; | |
| } | |
| setValueFn(next); | |
| field.text = formatPtAsUnit(next, getUnitFn ? getUnitFn() : "mm"); | |
| recalc(); | |
| normalizeInputFields(); | |
| try { if (ev.preventDefault) ev.preventDefault(); } catch (ePd) {} | |
| }); | |
| } | |
| } | |
| function enforceOutsideOrCompensate(rect, strokeWeight) { | |
| if (!rect || !rect.isValid || !strokeWeight || strokeWeight <= 0) { | |
| return; | |
| } | |
| var outsideApplied = false; | |
| if (typeof StrokeAlignment !== "undefined" && StrokeAlignment.OUTSIDE_ALIGNMENT !== undefined) { | |
| try { | |
| rect.strokeAlignment = StrokeAlignment.OUTSIDE_ALIGNMENT; | |
| outsideApplied = (rect.strokeAlignment === StrokeAlignment.OUTSIDE_ALIGNMENT); | |
| } catch (_) { | |
| outsideApplied = false; | |
| } | |
| } | |
| if (!outsideApplied) { | |
| // Emulate outside stroke when only center alignment is available: expand half-line on each side. | |
| var gb = rect.geometricBounds; | |
| var halfX = ptToDocX(strokeWeight / 2); | |
| var halfY = ptToDocY(strokeWeight / 2); | |
| rect.geometricBounds = [gb[0] - halfY, gb[1] - halfX, gb[2] + halfY, gb[3] + halfX]; | |
| dbg("Outside alignment fallback aplicado. Expandido X+-" + round4(halfX) + " / Y+-" + round4(halfY)); | |
| } | |
| } | |
| function dbg(msg) { | |
| if (!DEBUG_GRID) { | |
| return; | |
| } | |
| try { $.writeln("[GRIDDBG] " + msg); } catch (_) {} | |
| } | |
| function calcAxis(pageLen, itemLen, gap, stroke, margin, autoMargin) { | |
| var total; | |
| var step = itemLen + (2 * stroke) + gap; | |
| var outerMargin = Math.max(0, margin); | |
| var effectiveMargin = outerMargin; | |
| var availableLen; | |
| var usedLen; | |
| var innerOffset = 0; | |
| if (step <= 0 || pageLen <= 0) { | |
| return { total: 0, margin: effectiveMargin, outerMargin: outerMargin, step: step, remainder: 0 }; | |
| } | |
| if (autoMargin) { | |
| total = Math.floor((pageLen + gap) / step); | |
| if (total < 0) { total = 0; } | |
| usedLen = (total * (itemLen + (2 * stroke))) + (Math.max(0, total - 1) * gap); | |
| outerMargin = (pageLen - usedLen) / 2; | |
| if (outerMargin < 0) { outerMargin = 0; } | |
| effectiveMargin = outerMargin; | |
| availableLen = pageLen - (2 * outerMargin); | |
| } else { | |
| availableLen = pageLen - (2 * outerMargin); | |
| total = Math.floor((availableLen + gap) / step); | |
| if (total < 0) { total = 0; } | |
| usedLen = (total * (itemLen + (2 * stroke))) + (Math.max(0, total - 1) * gap); | |
| innerOffset = (availableLen - usedLen) / 2; | |
| if (innerOffset < 0) { innerOffset = 0; } | |
| effectiveMargin = outerMargin + innerOffset; | |
| } | |
| var remainder = availableLen - usedLen; | |
| return { | |
| total: total, | |
| margin: effectiveMargin, | |
| outerMargin: outerMargin, | |
| step: step, | |
| remainder: remainder | |
| }; | |
| } | |
| function parseMeasureToPt(text, fallbackPt) { | |
| if (text === null || text === undefined) { | |
| return fallbackPt; | |
| } | |
| var s = String(text); | |
| s = s.replace(/\s+/g, " ").replace(/,/g, "."); | |
| s = s.replace(/^\s+|\s+$/g, ""); | |
| if (!s) { | |
| return fallbackPt; | |
| } | |
| try { | |
| var uv = new UnitValue(s); | |
| var pt = uv.as("pt"); | |
| if (isNaN(pt)) { | |
| return fallbackPt; | |
| } | |
| return pt; | |
| } catch (_) { | |
| var n = Number(s); | |
| if (isNaN(n)) { | |
| return fallbackPt; | |
| } | |
| try { | |
| return new UnitValue(n, "mm").as("pt"); | |
| } catch (__){ | |
| return fallbackPt; | |
| } | |
| } | |
| } | |
| function parseMeasureToPtInCurrentUnit(text, fallbackPt, currentUnit) { | |
| var unit = normalizeUnitToken(currentUnit || "mm"); | |
| if (text === null || text === undefined) { | |
| return { valuePt: fallbackPt, unit: unit }; | |
| } | |
| var s = String(text); | |
| s = s.replace(/\s+/g, " ").replace(/,/g, "."); | |
| s = s.replace(/^\s+|\s+$/g, ""); | |
| if (!s) { | |
| return { valuePt: fallbackPt, unit: unit }; | |
| } | |
| var explicitUnit = extractExplicitUnit(s); | |
| if (explicitUnit) { | |
| try { | |
| var uvExplicit = new UnitValue(s); | |
| var ptExplicit = uvExplicit.as("pt"); | |
| if (!isNaN(ptExplicit)) { | |
| return { valuePt: ptExplicit, unit: explicitUnit }; | |
| } | |
| } catch (_) {} | |
| } | |
| var n = Number(s); | |
| if (!isNaN(n)) { | |
| try { | |
| return { valuePt: new UnitValue(n, unit).as("pt"), unit: unit }; | |
| } catch (_) { | |
| return { valuePt: fallbackPt, unit: unit }; | |
| } | |
| } | |
| try { | |
| var uv = new UnitValue(s); | |
| var pt = uv.as("pt"); | |
| if (!isNaN(pt)) { | |
| return { valuePt: pt, unit: unit }; | |
| } | |
| } catch (_) {} | |
| return { valuePt: fallbackPt, unit: unit }; | |
| } | |
| function formatPtAsMm(pt) { | |
| return formatPtAsUnit(pt, "mm"); | |
| } | |
| function formatPtAsUnit(pt, unit) { | |
| var u = normalizeUnitToken(unit || "mm"); | |
| return formatNumberLocale(new UnitValue(pt, "pt").as(u), 2) + " " + u; | |
| } | |
| function round2(n) { | |
| return Math.round(n * 100) / 100; | |
| } | |
| function formatNumberLocale(n, decimals) { | |
| var factor = Math.pow(10, decimals); | |
| var rounded = Math.round(n * factor) / factor; | |
| var s = String(rounded); | |
| if (LOCALE_DECIMAL === ",") { | |
| s = s.replace(/\./g, ","); | |
| } | |
| return s; | |
| } | |
| function round4(n) { | |
| return Math.round(n * 10000) / 10000; | |
| } | |
| function getLocaleDecimalSeparator() { | |
| try { | |
| var loc = String($.locale || "").toLowerCase(); | |
| if (/^(es|fr|de|it|pt|ru|nl|pl|tr|cs|da|fi|no|sv)/.test(loc)) { | |
| return ","; | |
| } | |
| } catch (_) {} | |
| return "."; | |
| } | |
| function extractExplicitUnit(s) { | |
| var m = String(s || "").toLowerCase().match(/[a-z]+$/); | |
| if (!m || !m[0]) { | |
| return null; | |
| } | |
| return normalizeUnitToken(m[0]); | |
| } | |
| function normalizeUnitToken(u) { | |
| var s = String(u || "").toLowerCase(); | |
| if (s === "inch" || s === "inches") { return "in"; } | |
| if (s === "point" || s === "points") { return "pt"; } | |
| if (s === "millimeter" || s === "millimeters") { return "mm"; } | |
| if (s === "centimeter" || s === "centimeters") { return "cm"; } | |
| if (s === "pica" || s === "picas") { return "pc"; } | |
| if (s === "pixel" || s === "pixels") { return "px"; } | |
| if (s === "mm" || s === "cm" || s === "pt" || s === "in" || s === "pc" || s === "px") { return s; } | |
| return "mm"; | |
| } | |
| function getOrCreatePreviewRedSwatch(doc) { | |
| var sw = doc.swatches.itemByName("Red"); | |
| if (sw.isValid) { | |
| return sw; | |
| } | |
| var c = doc.colors.itemByName("__preview_red__"); | |
| if (c.isValid) { | |
| return c; | |
| } | |
| try { | |
| return doc.colors.add({ | |
| name: "__preview_red__", | |
| model: ColorModel.PROCESS, | |
| space: ColorSpace.RGB, | |
| colorValue: [255, 0, 0] | |
| }); | |
| } catch (_) { | |
| return doc.swatches.itemByName("Black"); | |
| } | |
| } | |
| function getOrCreatePreviewBlueSwatch(doc) { | |
| var sw = doc.swatches.itemByName("Blue"); | |
| if (sw.isValid) { | |
| return sw; | |
| } | |
| var c = doc.colors.itemByName("__preview_blue__"); | |
| if (c.isValid) { | |
| return c; | |
| } | |
| try { | |
| return doc.colors.add({ | |
| name: "__preview_blue__", | |
| model: ColorModel.PROCESS, | |
| space: ColorSpace.RGB, | |
| colorValue: [0, 120, 255] | |
| }); | |
| } catch (_) { | |
| return doc.swatches.itemByName("Black"); | |
| } | |
| } | |
| function measurementUnitToUnitValueUnit(mu) { | |
| try { | |
| if (mu === MeasurementUnits.MILLIMETERS) { return "mm"; } | |
| if (mu === MeasurementUnits.CENTIMETERS) { return "cm"; } | |
| if (mu === MeasurementUnits.INCHES) { return "in"; } | |
| if (mu === MeasurementUnits.PICAS) { return "pc"; } | |
| if (mu === MeasurementUnits.POINTS) { return "pt"; } | |
| if (mu === MeasurementUnits.PIXELS) { return "px"; } | |
| } catch (_) {} | |
| return "pt"; | |
| } | |
| function convertUnit(value, fromUnit, toUnit) { | |
| try { | |
| return new UnitValue(value, fromUnit).as(toUnit); | |
| } catch (_) { | |
| return value; | |
| } | |
| } | |
| function ptToDocX(v) { return convertUnit(v, "pt", DOC_UNIT_X); } | |
| function ptToDocY(v) { return convertUnit(v, "pt", DOC_UNIT_Y); } | |
| function docXToPt(v) { return convertUnit(v, DOC_UNIT_X, "pt"); } | |
| function docYToPt(v) { return convertUnit(v, DOC_UNIT_Y, "pt"); } | |
| function measurePlacedSlugSize(page, doc, file, crop, pageNumber, prevPageNumber, prevCrop) { | |
| var noneSwatch = doc.swatches.itemByName("None"); | |
| if (!noneSwatch.isValid) { | |
| throw new Error(L.swatchNoneMissing); | |
| } | |
| var frame = null; | |
| try { | |
| app.importedPageAttributes.pageNumber = pageNumber; | |
| app.importedPageAttributes.importedPageCrop = crop; | |
| frame = page.rectangles.add({ | |
| geometricBounds: [0, 0, 10, 10], | |
| strokeWeight: 0, | |
| fillColor: noneSwatch | |
| }); | |
| var g = frame.place(file, false)[0]; | |
| var gb = g.geometricBounds; | |
| return { | |
| width: gb[3] - gb[1], | |
| height: gb[2] - gb[0] | |
| }; | |
| } catch (_) { | |
| return null; | |
| } finally { | |
| if (frame && frame.isValid) { | |
| frame.remove(); | |
| } | |
| app.importedPageAttributes.pageNumber = prevPageNumber; | |
| app.importedPageAttributes.importedPageCrop = prevCrop; | |
| } | |
| } | |
| function executePlacement(ui) { | |
| app.doScript( | |
| function () { | |
| executePlacementCore(ui); | |
| }, | |
| ScriptLanguage.JAVASCRIPT, | |
| undefined, | |
| UndoModes.ENTIRE_SCRIPT, | |
| L.undoLabel | |
| ); | |
| } | |
| function executePlacementCore(ui) { | |
| var overlayLayer = getOrCreateOverlayLayer(targetDoc, L.overlayLayerBaseName); | |
| moveLayerToTop(overlayLayer); | |
| var totalPlaced = 0; | |
| var currentPage = targetPage; | |
| var currentPlan = null; | |
| var currentPlanKey = ""; | |
| var failed = false; | |
| try { | |
| app.importedPageAttributes.importedPageCrop = placementCrop; | |
| for (var f = 0; f < files.length; f++) { | |
| var file = files[f]; | |
| var srcInfo = getSourceInfo(file, sourceInfoCache); | |
| validateUniformSlugSize(file, srcInfo); | |
| var metrics = srcInfo.metricsByPage[1]; | |
| var filePlan = buildGridPlan(currentPage, metrics.slugWidth, metrics.slugHeight, ui); | |
| if (filePlan.capacity < 1) { | |
| throw new Error(lfmt(L.noFitForFile, file.name)); | |
| } | |
| var filePlanKey = gridPlanKey(filePlan); | |
| if (currentPlan && (currentPlan.slotIndex > 0 || currentPlanKey !== filePlanKey)) { | |
| currentPage = targetDoc.pages.add(LocationOptions.AFTER, currentPage); | |
| currentPlan = null; | |
| currentPlanKey = ""; | |
| } | |
| for (var p = 1; p <= srcInfo.pageCount; p++) { | |
| var pageMetrics = srcInfo.metricsByPage[p]; | |
| if (!currentPlan || currentPlan.slotIndex >= currentPlan.capacity || currentPlanKey !== filePlanKey) { | |
| if (currentPlan && currentPlan.slotIndex >= currentPlan.capacity) { | |
| currentPage = targetDoc.pages.add(LocationOptions.AFTER, currentPage); | |
| } | |
| currentPlan = buildGridPlan(currentPage, metrics.slugWidth, metrics.slugHeight, ui); | |
| currentPlanKey = gridPlanKey(currentPlan); | |
| if (currentPlan.capacity < 1) { | |
| throw new Error(lfmt(L.noFitInTargetPage, currentPage.name)); | |
| } | |
| } | |
| app.importedPageAttributes.pageNumber = p; | |
| app.importedPageAttributes.importedPageCrop = placementCrop; | |
| var frameBounds = slotFrameBounds(currentPlan, currentPlan.slotIndex); | |
| var placedFrame = currentPage.rectangles.add({ | |
| geometricBounds: frameBounds, | |
| strokeWeight: 0, | |
| fillColor: targetDoc.swatches.itemByName("None") | |
| }); | |
| placedFrame.place(file, false); | |
| var overlayBounds = getOverlayBoundsFromSourceMetrics(placedFrame, pageMetrics); | |
| createOverlayFrame(targetDoc, currentPage, overlayLayer, overlayBounds, ui.strokePt, 10); | |
| currentPlan.slotIndex++; | |
| totalPlaced++; | |
| } | |
| } | |
| } catch (e) { | |
| failed = true; | |
| alert(L.errorPrefix + e.message); | |
| } finally { | |
| app.importedPageAttributes.pageNumber = originalPageNumber; | |
| app.importedPageAttributes.importedPageCrop = originalCrop; | |
| } | |
| if (!failed) { | |
| alert(lfmt(L.doneMessage, totalPlaced)); | |
| } | |
| } | |
| function lfmt(template) { | |
| var out = String(template || ""); | |
| for (var i = 1; i < arguments.length; i++) { | |
| out = out.replace(new RegExp("\\{" + (i - 1) + "\\}", "g"), String(arguments[i])); | |
| } | |
| return out; | |
| } | |
| })(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment