@bloomreach/ui-extension-saas
Version:
Bloomreach Open UI SDK
296 lines (291 loc) • 11.6 kB
JavaScript
(function(global, factory) {
typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("emittery"), require("penpal")) : typeof define === "function" && define.amd ? define([ "exports", "emittery", "penpal" ], factory) : (global = global || self,
factory(global.UiExtension = {}, global.Emittery, global.Penpal));
})(this, (function(exports, Emittery, Penpal) {
"use strict";
Emittery = Emittery && Object.prototype.hasOwnProperty.call(Emittery, "default") ? Emittery["default"] : Emittery;
Penpal = Penpal && Object.prototype.hasOwnProperty.call(Penpal, "default") ? Penpal["default"] : Penpal;
(function(UiExtensionErrorCode) {
UiExtensionErrorCode["ConnectionDestroyed"] = "ConnectionDestroyed";
UiExtensionErrorCode["DialogCanceled"] = "DialogCanceled";
UiExtensionErrorCode["DialogExists"] = "DialogExists";
UiExtensionErrorCode["IncompatibleParent"] = "IncompatibleParent";
UiExtensionErrorCode["InternalError"] = "InternalError";
UiExtensionErrorCode["NotInIframe"] = "NotInIframe";
})(exports.UiExtensionErrorCode || (exports.UiExtensionErrorCode = {}));
(function(UiStyling) {
UiStyling["Classic"] = "classic";
UiStyling["Material"] = "material";
})(exports.UiStyling || (exports.UiStyling = {}));
(function(DocumentEditorMode) {
DocumentEditorMode["View"] = "view";
DocumentEditorMode["Compare"] = "compare";
DocumentEditorMode["Edit"] = "edit";
})(exports.DocumentEditorMode || (exports.DocumentEditorMode = {}));
(function(DialogSize) {
DialogSize["Large"] = "large";
DialogSize["Medium"] = "medium";
DialogSize["Small"] = "small";
})(exports.DialogSize || (exports.DialogSize = {}));
const experienceManagerMethodsOnly = [ "getDocumentValues", "getDocumentFieldValue", "setDocumentFieldValue" ];
class ParentError extends Error {
constructor(code, message) {
super(message);
this.code = code;
this.message = message;
Object.setPrototypeOf(this, new.target.prototype);
}
toPromise() {
return Promise.reject(this);
}
static fromPenpal(error) {
const errorCode = ParentError.convertPenpalErrorCode(error);
return new ParentError(errorCode, error.message);
}
static convertPenpalErrorCode(error) {
switch (error.code) {
case Penpal.ERR_NOT_IN_IFRAME:
return exports.UiExtensionErrorCode.NotInIframe;
case Penpal.ERR_CONNECTION_DESTROYED:
return exports.UiExtensionErrorCode.ConnectionDestroyed;
case "DialogCanceled":
return exports.UiExtensionErrorCode.DialogCanceled;
case "DialogExists":
return exports.UiExtensionErrorCode.DialogExists;
default:
return exports.UiExtensionErrorCode.InternalError;
}
}
}
class ParentConnection {
constructor(_parent) {
this._parent = _parent;
}
call(method, ...args) {
if (!this._parent[method]) {
const errorMessage = experienceManagerMethodsOnly.includes(String(method)) ? `${String(method)}() is only supported in the Experience Manager` : `missing ${String(method)}()`;
return new ParentError(exports.UiExtensionErrorCode.IncompatibleParent, errorMessage).toPromise();
}
try {
return this._parent[method](...args).catch(ParentConnection.convertPenpalError);
} catch (error) {
return ParentConnection.convertPenpalError(error);
}
}
static convertPenpalError(error) {
return ParentError.fromPenpal(error).toPromise();
}
}
function connect(parentOrigin, eventEmitter) {
try {
return Penpal.connectToParent({
parentOrigin: parentOrigin,
methods: {
emitEvent: eventEmitter.emit.bind(eventEmitter)
}
}).promise.then(parent => new ParentConnection(parent));
} catch (penpalError) {
return ParentError.fromPenpal(penpalError).toPromise();
}
}
function _extends() {
_extends = Object.assign || function(target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i];
for (var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key];
}
}
}
return target;
};
return _extends.apply(this, arguments);
}
var _a, _b, _c;
const SCOPE_CHANNEL = "channel";
const SCOPE_PAGE = `${SCOPE_CHANNEL}.page`;
const SCOPE_DOCUMENT = "document";
const SCOPE_FIELD = `${SCOPE_DOCUMENT}.field`;
const PARENT = Symbol("parent");
const EVENT_EMITTER = Symbol("eventEmitter");
const EVENT_SCOPE = Symbol("eventScope");
const FIELD_DOM_OBSERVER = Symbol("fieldDomObserver");
const FIELD_OVERFLOW_STYLE = Symbol("fieldOverflowStyle");
const FIELD_HEIGHT = Symbol("fieldHeight");
const FIELD_HEIGHT_MODE = Symbol("fieldHeightMode");
const FIELD_HEIGHT_LISTENER = Symbol("fieldHeightListener");
const KEY_ESCAPE = 27;
function defineLazyGetter(object, property, getter) {
let value;
Object.defineProperty(object, property, {
get: () => {
if (value === undefined) {
value = getter();
}
return value;
},
configurable: false,
enumerable: true
});
}
class Scope {
constructor(parent) {
this[PARENT] = parent;
}
}
class ScopeEmitter extends Scope {
constructor(parent, eventEmitter, eventScope) {
super(parent);
this[EVENT_EMITTER] = eventEmitter;
this[EVENT_SCOPE] = eventScope;
}
on(eventName, callback) {
return this[EVENT_EMITTER].on(`${this[EVENT_SCOPE]}.${eventName}`, callback);
}
}
class Page extends ScopeEmitter {
get() {
return this[PARENT].call("getPage");
}
refresh() {
return this[PARENT].call("refreshPage");
}
}
class Channel extends ScopeEmitter {
constructor(parent, eventEmitter, eventScope) {
super(parent, eventEmitter, eventScope);
defineLazyGetter(this, "page", () => new Page(parent, eventEmitter, SCOPE_PAGE));
}
refresh() {
return this[PARENT].call("refreshChannel");
}
get() {
return this[PARENT].call("getChannel");
}
}
class Document extends Scope {
constructor(parent) {
super(parent);
defineLazyGetter(this, "field", () => new Field(this[PARENT]));
}
get() {
return this[PARENT].call("getDocument");
}
navigate(path) {
return this[PARENT].call("navigateDocument", path);
}
open(id) {
return this[PARENT].call("openDocument", id);
}
setFieldValue(path, value) {
return this[PARENT].call("setDocumentFieldValue", path, value);
}
getFieldValue(path) {
return this[PARENT].call("getDocumentFieldValue", path);
}
getValues() {
return this[PARENT].call("getDocumentValues");
}
}
function enableAutoHeight() {
if (this[FIELD_HEIGHT_MODE] === "auto") {
return;
}
document.body.addEventListener("load", this[FIELD_HEIGHT_LISTENER], true);
this[FIELD_DOM_OBSERVER].observe(document.body, {
attributes: true,
characterData: true,
childList: true,
subtree: true
});
this[FIELD_HEIGHT_MODE] = "auto";
this[FIELD_OVERFLOW_STYLE] = document.body.style.overflowY;
document.body.style.overflowY = "hidden";
}
function disableAutoHeight() {
if (this[FIELD_HEIGHT_MODE] !== "auto") {
return;
}
document.body.removeEventListener("load", this[FIELD_HEIGHT_LISTENER], true);
this[FIELD_DOM_OBSERVER].disconnect();
this[FIELD_HEIGHT_MODE] = "manual";
document.body.style.overflowY = this[FIELD_OVERFLOW_STYLE];
}
function updateHeight(height) {
if (this[FIELD_HEIGHT] === height) {
return;
}
this[FIELD_HEIGHT] = height;
return this[PARENT].call("setFieldHeight", height);
}
class Field extends Scope {
constructor(parent) {
super(parent);
this[_a] = "manual";
this[_b] = () => updateHeight.call(this, document.body.scrollHeight);
this[_c] = new MutationObserver(this[FIELD_HEIGHT_LISTENER]);
window.addEventListener("focus", () => parent.call("emitEvent", `${SCOPE_FIELD}.focus`));
window.addEventListener("blur", () => parent.call("emitEvent", `${SCOPE_FIELD}.blur`));
}
getValue(...path) {
return this[PARENT].call("getFieldValue", ...path);
}
getCompareValue(...path) {
return this[PARENT].call("getFieldCompareValue", ...path);
}
setValue(value) {
return this[PARENT].call("setFieldValue", value);
}
setHeight(height) {
if (height === "auto") {
return enableAutoHeight.call(this) || Promise.resolve();
}
disableAutoHeight.call(this);
return updateHeight.call(this, height) || Promise.resolve();
}
}
_a = FIELD_HEIGHT_MODE, _b = FIELD_HEIGHT_LISTENER, _c = FIELD_DOM_OBSERVER;
class Dialog extends Scope {
constructor(parent) {
super(parent);
window.addEventListener("keydown", ({which: which}) => which === KEY_ESCAPE && this.cancel());
}
cancel() {
return this[PARENT].call("cancelDialog");
}
close(value) {
return this[PARENT].call("closeDialog", value);
}
open(options) {
return this[PARENT].call("openDialog", options);
}
options() {
return this[PARENT].call("getDialogOptions");
}
}
class Ui extends Scope {
constructor(parent, eventEmitter) {
super(parent);
defineLazyGetter(this, "channel", () => new Channel(parent, eventEmitter, SCOPE_CHANNEL));
defineLazyGetter(this, "dialog", () => new Dialog(parent));
defineLazyGetter(this, "document", () => new Document(parent));
}
init() {
return this[PARENT].call("getProperties").then(properties => _extends(this, properties));
}
}
class UiExtension {
static register() {
const parentOrigin = new URLSearchParams(window.location.search).get("br.parentOrigin");
const eventEmitter = new Emittery;
return connect(parentOrigin, eventEmitter).then(parentConnection => new Ui(parentConnection, eventEmitter).init());
}
}
const register = UiExtension.register;
exports.default = UiExtension;
exports.register = register;
Object.defineProperty(exports, "__esModule", {
value: true
});
}));