Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I use higher order functions like Array.reduce() in an Indesign script?

I've started a project where I need to use Adobe Indesign and ExtendScript to programmatically extract some data from a series of INDD files. The version of Javascript used for scripting in these programs doesn't support any of the higher order functions that I'm used to using (Array.reduce(), Array.forEach(), Array.map(), etc...).

Is there a way to add this functionality to ExtendScript? I feel like I'm walking around in a room with a four foot high ceiling.

like image 650
Jack Steam Avatar asked Feb 08 '16 17:02

Jack Steam


Video Answer


2 Answers

Use a Polyfill

ExtendScript appears to support prototyping of pure Javascript objects (but not Indesign DOM objects), so it is possible to use a polyfill to add missing functionality. Polyfill code can be found on MDN on the page for the method in question under "Polyfill". Here's an example: MDN Array.prototype.reduce() Polyfill. There are polyfills for numerous methods, including Array.map(), Array.indexOf(), Array.filter(), and Array.forEach().

To implement the code, just create an appropriately named file (ie, polyfill.js or reduce.js) in the same folder as your script. Copy the polyfill code from MDN into the file you just created, like so:

// Production steps of ECMA-262, Edition 5, 15.4.4.21
// Reference: http://es5.github.io/#x15.4.4.21
if (!Array.prototype.reduce) {
  Array.prototype.reduce = function(callback /*, initialValue*/) {
    'use strict';
    if (this == null) {
      throw new TypeError('Array.prototype.reduce called on null or undefined');
    }
    if (typeof callback !== 'function') {
      throw new TypeError(callback + ' is not a function');
    }
    var t = Object(this), len = t.length >>> 0, k = 0, value;
    if (arguments.length == 2) {
      value = arguments[1];
    } else {
      while (k < len && !(k in t)) {
        k++; 
      }
      if (k >= len) {
        throw new TypeError('Reduce of empty array with no initial value');
      }
      value = t[k++];
    }
    for (; k < len; k++) {
      if (k in t) {
        value = callback(value, t[k], k, t);
      }
    }
    return value;
  };
}

Then add the following line at the beginning of your script, replacing the filename appropriately:

#include 'polyfill.js';

The semicolon at the end of the line isn't included in Adobe documentation, but I find that sometimes ExtendScript throws an error if it's left off, especially if you're using #include multiple times.

like image 193
Jack Steam Avatar answered Oct 03 '22 21:10

Jack Steam


I use underscore.js instead.

Underscore.js http://underscorejs.org/

#include '/path-to/underscore.js'
var _ = this._;

adding this snippet at the beginning of the script.

thank you

mg.

like image 23
milligramme Avatar answered Oct 03 '22 22:10

milligramme