UNPKG

@bloomreach/ui-extension-saas

Version:

Bloomreach Open UI SDK

296 lines (291 loc) 11.6 kB
(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 }); }));