User Manual Quickstart General Concepts Frame Features Resources Style Reference Change Log Glossary Acknowledgements Api Reference Authorization Tokens Embedding The Editor Custom Integration Typescript Loading Printess JS-API Reference resourcePath and domain div token showBuyerSide templateName basketId and shopUserId Merge templates Translations Offensive language Avoid space around Restrict pan and zoom Save and Load Work Form Fields Creating a Thumbnail Image Backend Api

Custom Integration (custom-ui)

It’s highly recommended to start with the easy iframe integration. But if at any point you feel that the iframe integration lacks some kind of flexibility you can allways switch to a Custom Integration.

All the work you have done to make the iframe look like your website will still work, since custom integration is doing the exact same thing like the iframe way - but you can customize much further, because you have access to the entire UI-Code.

In Buyer Mode, Printess is always reduced to a pure view-container which will not expose any Ui other than the editable area. All controls and inputs must be provided by your website. This will give you full control on how your website looks. But you have to handle selection-change and page-change callbacks to update your UI, which in return needs to update Printess properties via the js-api.

Have a look into our github repository here: https://github.com/PrintessEditor/getting-started

You can also test drive the custom integration here: https://printesseditor.github.io/getting-started/index.html

Custom integration comes with a uiHelper.js file which does all of the ui-work you are already familiar with from the iframe-integration.

uiHelper.js uses the Printess-JS-Api to communicate with the editor.

Typescript

If you’re using typescript you’ll find a printess-editor.d.ts file in the repro which contains all types for the printess object. You also find uiHelper.ts the typescript version of our uiHelper which is using the “d.ts” file.

JS-API Reference Full Reference can be found here

Loading Printess

Be aware that Printess itself is loaded after the webcomponents polyfills. So first we need to load webcomponentjs from the Printess CDN.

We also need to load the bootstrap bundle for combo-boxes and offcanvas popups. Also the bootstrap-css as well as the bs-layout.css need to be loaded.

Finally we need to load the uiHelper.js, which contains all the UI-Logic.

Please have a careful look at the samples integration to get an idea how the callbacks from the printess api play together with the redraw of the UI-Elements.

 <!-- Bootstrap -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.1/dist/js/bootstrap.bundle.min.js"
  integrity="sha384-gtEjrD/SeCtmISkJkNUaaKMoLD0//ElJ19smozuHV6z3Iehds+3Ulb9Bn9Plx0x4"
  crossorigin="anonymous"></script>

<!-- Load polyfills -->
<script src="https://editor.printess.com/node_modules/@webcomponents/webcomponentsjs/webcomponents-loader.js"></script>

<!-- Load uiHelper --->
<script src="custom-ui/uiHelper.js"></script>

Now we wait for WebComponentsReady before loading Printess itself from our CDN.

<script>
  window.WebComponents = window.WebComponents || {
    waitFor(cb) {
      addEventListener('WebComponentsReady', cb);
    },
  };
  let printess;
  let api;
  WebComponents.waitFor(async () => {
    printess = await import(
      'https://editor.printess.com/printess-editor/printess-editor.js'
    );

    api = printess.attachPrintess({
      resourcePath: 'https://editor.printess.com/printess-editor', // needs to be always set
      domain: 'api.printess.com',
      div: document.getElementById('printess'),
      basketId: 'CurrentShopBasketId',
      shopUserId: 'CurrentShopCustomerId',
      token: 'YOUR SHOP-TOKEN',
      showBuyerSide: true,
      templateName: 'Retro Sign',
      templateVersion: 'published'
    });
  });
</script>

The attachPrintess call initializes Printess, passes the authentication token and the name of the template to be loaded. See all parameters here: JS-API

JS-API Reference

The return value of the attachPrintess() call holds a reference to to the Printess js-api, your direct link to the Printess Editor. In our example the variable is named api. You can access the full JS-Api documentation here: JS-API

resourcePath and domain

resourcePath: 'https://editor.printess.com/printess-editor',
domain: 'api.printess.com'

Please be aware that you’ll need to tell Printess the path to its resource files (Web-Assembly and Default Fonts) in a separate property resourcePath. Please do not change this value.

The domain should remain unchanged. It only needs to be changed if you are uing a private Printess cloud.

div

div: document.getElementById('printess')

In the div property you need to pass a div-element which Printess Editor will attach to. Printess is intended to have as much space as possible, so it is highly recommended to not leave space on left and right side. Especially on mobile.

token

 token: 'YOUR TOKEN'

token should be set to a Shop-Token which points to your Printess Account. You can get this token once you are logged in to the Printess Editor -> Account Menu -> API-Token. You’ll see 2 different tokens in the dialog. Please always use the Shop-Token.

showBuyerSide

showBuyerSide: true

showBuyerSide is a boolean which forces Printes to jump to the buyer-side directly. If you use the shop-token Printess will always show the buyer-side no matter what you pass in that property.

templateName

templateName: 'Sign'
templateVersion: 'published' // Can be draft or published (default) depending on which version of the document should get used

templateName is required and specifies the name of the template to load.
templateName can also take the save-token you received from saveJson() and load it directly.

basketId and shopUserId

To enable your customer to upload images and to save or load the state of work - you need to pass in minimum a BasketId to printess on attachPrintess().

Optionally you can pass a shopUserId to make Printess store in the context of the current customer (user). Also when the customer uploads an image it will be stored under the shopUserId. So if the customer returns later he or she will see its previous uploaded images.

{
  "basketId": "CurrentShopBasketId",
  "shopUserId": "CurrentShopCustomerId"
}

We are working on a method to assign an existing basketId to a shopUserId in the case the user logs in after he or she has already designed his or her artwork. So you can ensure that even with late sign in or user creation the existing uploaded images are assigned to that customer.

Merge templates

mergeTemplates: [{
  templateName: "motive1",
  documentName: "Document", // optional, if not supplied Primary or first Document is used
  templateVersion: "published", // Can be draft or published (default) depending on which version of the document should get used
  spreadIndex: 0 // [optional]
}];

A comonly used approach is to have a master-template with the final dimensions and all the general buyer side settings and the available colors and fonts. And then having multiple artwork-templates which the customer can select directly from the shop-catalog. Lets say the master-template is named card and the selected motive’s name is motive1. If you show the Printess editor you can now load card via the templateName property and merge in the document Document from template motive1 via the mergeTemplates property.
In spreadIndex you can define spread number where the merged template is placed on. It’s zero based and please keep in mind that on a facing-pages document each pair of pages counts only as a single spread.

Translations

translations: {
  "custom": {
    "name": "Your Name" // you can access this translation with ${gl("custom.name")}
  }
}

Printess provides an internal translation-table to display the buyer UI in different languages. The buyer side language for the individual templates can be set in the Template Preferences. If it is set to auto, the buyer UI will be displayed in the system language of the user, provided that the translation is available.

So along with customizing the buyer side UI you can also modify the text content to your needs by adding an own translation-table to the attachPrintess call. You will find all available keys in the translation.json on the Printess Github Repo. You can modify the values to the given keys to your needs by adding them to your own translation-table. If no custom translation is found, Printess’ fallback translation will be searched through.

In the uiHelper you need to call the printess.gl()function and pass through the keys for your translation as string chained together with a dot, e.g. “custom.name”, to receive “Your Name”.

Offensive language

To prevent the use of offensive language in customizeable texts, you can pass a list of forbidden words to Printess via the attach call (offensiveWords). You also can set this list per template in the preferences dialog. (Also the “offensive” option must be activated on frame level)

The use of offensive words can either throw an error during the validation or trigger the replacement of a bad word. Offensive words is just a comma separated list of strings. Optionally each word can have a replacement string separated by a colon.

offensiveWords: "shit,fuck:f**k,piss"

In the above example, the words “shit” and “piss” would throw a validation exception and “fuck” would be replaced by “f**k”

Avoid space around

Especially when you would like to disable zooming and panning in Printess, you might want Printess to exactly frame the template you have loaded. This is what the autoScale parameter is for.

autoScale {
  maxWidth: 500,
  maxHeight: 700
};

autoScale accepts 2 parameters, maxWidth and maxHeight. Both set the maximum expansion the Printess container can occupy. Depending on the aspect ratio of the loaded template the final size will be calculated.

Restrict pan and zoom

When using autoScale you might want to disable the possibilty of the user pan and zoom for the loaded template. Simply do so by setting the allowZoomAndPan parameter to false.

allowZoomAndPan: false;

Save and Load Work

To store the result of what your customer has configured in Printess you can simply call printess.saveJson(). In return you will get a token that you can easily use to load this state if the customer returns or wants to make changes. You also can use this token to load the customers design e.g. in your support portal to apply fixes you might have received via email or phone.

Save customers work

const myToken = await printess.saveJson();

Load customers work

await printess.loadJson(myToken);

To test it, we added a button in the toolbar Save State, which saves the current state and returns a token to load it later. Just try it, make some other changes or even load a different template, and then press Load State, paste the token to the prompt and you will see the state you prevoiusly stored.

Form Fields

Printess has the concept of Form Fields which can be created by the designer and changed by the buyer.

Populating on load

Lets say you want to pre-populate those form fields with customer data when showing the printess editor, you can do it like so:

api = printess.attachPrintess({
    ...
    formFields: [
      {
        name: "Name",
        value: "Peter Meyer"
      },
      {
        name: "Email",
        value: "peter.meyer@printess.com"
      }
    ]
  });

Just pass an array of objects to the attachPrintess method. Each object needs to address a form-field by its name and set its value as string. Even if the form-field type is number, you need to pass the value as string. The above example could be the pre-population of a business card template.

Receiving Form Field updates

Those Form Fields can contain information which are price relevant like material or color. The Sign template which you see when running index.html from the git-hub repo exposes a couple of such Form Fields. Material, Size - and if a solid material is selected - Drill Holes and Varnish. All 4 Form Fields are possibly price relevant so the eCommerce application must know if any of these values have been changed. To achieve this, you can pass a very simple callback to attachPrintess, where you then can adjust your basket settings to the users choices.

const formFieldChanged = (name, value) => {
  alert('Form Field: [' + name + "] changed to '" + value + "'");
};
printess.attachPrintess({
  /* ... all other properties ... */
  formFieldChangedCallback: formFieldChanged,
});

Creating a Thumbnail Image

After the buyer has put the design to the shopping basket you might want to retrieve a small image of the current layout. Do get a URL of such a “Thumbnail” you can call:

const fileName = 'thumb_' + new Date().getTime() + '.png';
const documentName = '';
const width = 400; // max is 400
const height = 400; // max is 400

printess
  .renderFirstPageImage(fileName, documentName, width, height)
  .then((thumbnailUrl) => {
    window.open(thumbnailUrl);
  });

fileName: has to be set, so you can put the basket ID here to override an existing image.

documentName: can be set if you for example want a thumbnail of a specific preview document. Otherwise the primary document will be taken. If you want to get a thumbnail of any existing preview document just pass “!PREVIEW!”. If no “preview”-document is found it falls back to the “primary” document and then to the first document of the template. You can see this in action on the “T-Shirt” example.

width: the maximum width of the thumbnail based on aspect ratio of the document, the resulting thumbnail-width can be smaller.

height: the maximum height of the thumbnail based on aspect ratio of the document, the resulting thumbnail-height can be smaller.

TIP: Press the Create Thumbnail Button to show a thumbnail of the current Template.

:warning: The thumbnail generation might take a couple of seconds. If you request the thumbnail when the buyer clicks continue - you need to show an overlay screen and wait for the call to finish before you unload the Printess editor!