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

2

6

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.

Bureaucracy answered 8/2, 2016 at 17:51 Comment(0)
B
6

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.

Bureaucracy answered 8/2, 2016 at 17:51 Comment(2)
It would be helpful to share your polyfill.js on github for others with the same problem.Baboon
@Baboon I'm doing that here github.com/fabiantheblind/extendscript.prototypes contributions are welcomeSlyviasm
M
3

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.

Minimum answered 9/2, 2016 at 2:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.