/** * @description The loadLibraries() method sequentially loads the collection of libraries provided by rgLibraries, using the given path * @param {string[]} rgLibraries Indicates the libraries to load as an array of [string] type * @param {string} path Specifies the path for all libraries */ function loadLibraries(rgLibraries, path) { /** * @description The addLibraryScript() method adds a script library to be loaded, and once loading is complete, it calls the given callback. * @param {string} src Specifies the source of the library to load * @param {callback} callback Indicates the callback to call once the loading is complete */ function addLibraryScript(src, callback) { var oScript = document.createElement('script'); oScript.src = (path || "") + src; oScript.onload = callback; document.head.appendChild(oScript); } /** * @description The loadLibrary() method loads a library based on its index. Once loading is complete, it recursively proceeds to load the next library. * @param {number} index Indicates the index of the library to load */ function loadLibrary(index) { if (index < rgLibraries.length) addLibraryScript(rgLibraries[index], function () { loadLibrary(index + 1); }) } // starts loading the libraries loadLibrary(0); } /** * @description The arrangeRollistPreview() method gets the left/right client-rectangles the rollist(left) and image-preview(right) should go * @param {HTMLElement} oHostImagePreview Specifies the HTML element to host the image-preview * @param {HTMLElement} oImagePreview Indicates the HTML element to display the image-preview * @returns {object} Returns an object of {l(eft),r(ight)} type, where: * * l(eft) {array}, specifies the client-rectangle to show the rollist, as an array of [x,y,width,height] type * r(ight) {array}, specifies the client-rectangle to show the image-preview * */ function arrangeRollistPreview(oHostImagePreview, oImagePreview) { var nHRatio = 0.7, nVRatio = 0.7, rtHostImagePreview = exontrol.Ert(oHostImagePreview), rtLeft = [0, (1 - nVRatio) * rtHostImagePreview[3] / 2, nHRatio * rtHostImagePreview[2], nVRatio * rtHostImagePreview[3]], rtRight = [rtLeft[2], 0, rtHostImagePreview[2] - rtLeft[2], rtHostImagePreview[3]], rtCenterRight, rtImagePreview; if (oImagePreview) { rtImagePreview = exontrol.Ert(oImagePreview); rtCenterRight = exontrol.G.C2R(exontrol.G.R2C(rtRight), rtImagePreview[2], rtImagePreview[3]); if (rtImagePreview[2] > rtRight[2]) { rtRight[3] = rtCenterRight[3] / (rtImagePreview[2] / rtRight[2]); rtRight[1] = rtCenterRight[1] + (rtCenterRight[3] - rtRight[3]) / 2; exontrol.IRt(rtRight, -8, -8); } else rtRight = rtCenterRight; } exontrol.IRt(rtLeft, -8, -8); return { l: rtLeft, r: rtRight } } /** * @description The morphRect() method creates an intermediate client rectangle based on the from/to values and progress, returning an array of [x,y,width,height] type. * @param {array} rtFrom Indicates the initial-rectangle, as an array of [x,y,width,height] type * @param {array} rtTo Indicates the target-rectangle, as an array of [x,y,width,height] type * @param {number} progress Specifies the progress as a value between 0 and 1 * @returns {array} Returns the intermediate client rectangle, as an array of [x,y,width,height] type */ function morphRect(rtFrom, rtTo, progress) { function morph(from, to, progress) { return from + progress * (to - from); } var rtProgress = exontrol.C2R(); for (var i = 0, l = rtProgress.length; i < l; i++) rtProgress[i] = morph(rtFrom[i], rtTo[i], progress); return rtProgress } /** * @description The setElementPos() method changes the left, top width and height properties of the giving element * @param {HTMLElement} oHTMLElement Specifies the HTML element to move * @param {(number|array)} left Indicates the left position of the element, or an array of [x,y,width,height] type that represents new position of the element (in this case the top, width and height are ignored) * @param {number} top Specifies the top position of the element * @param {number} width Specifies the width of the element * @param {number} height Specifies the height of the element */ function setElementPos(oHTMLElement, left, top, width, height) { if (left instanceof Array) { height = left[3]; width = left[2]; top = left[1]; left = left[0]; } var oStyle = oHTMLElement.style; if (left != null) oStyle.left = exontrol.toU(left); if (top != null) oStyle.top = exontrol.toU(top); if (width != null) oStyle.width = exontrol.toU(width); if (height != null) oStyle.height = exontrol.toU(height); } var sReleaseNotes = "/content/products/" + this.document.currentScript.dataset.product.toLowerCase() + "/notes.txt?time=" + Date.now(), // ensures that the browser retrieves the data from the server each time, bypassing the cache oRollist; loadLibraries(['/exontrol.common.min.js', '/exrollist/lib/exontrol.rollist.min.js'], "/js/publish"); window.addEventListener("load", function () { /** * @description The isReleasedRecently() method checks whether the product has been recently released * @param {string} source Indicates the release-notes * @returns {boolean} Returns true if the product has been recently released, otherwise false */ function isReleasedRecently(source) { var oMatch = source.match(/^\d+\.\d+(\.\d+\.\d+)?[ \t]*(.*)/m); return oMatch && (dtReleaseDate = Date.Create(oMatch[2])).isValid() && (dtReleaseDate > new Date().addD(-31)); } if (exontrol) { var oWindowTop = window.top, sSelectVersion = new URLSearchParams(oWindowTop.location.search).get("v"), oImagePreview = document.getElementById("imgprew"), oHostImagePreview = oImagePreview && oImagePreview.closest(".host-preview-control"), hasVerticalScrollbar = document.body.scrollHeight > document.body.clientHeight, oHostRollist, oFrom, oTo, rgFeaturesData; oHostImagePreview && !hasVerticalScrollbar && exontrol.Ld(sReleaseNotes, { i: function (source) { source && (sSelectVersion || isReleasedRecently(source) || (rgFeaturesData = PRODUCT && PRODUCT.querySelector('ul') && Array.from(PRODUCT.querySelector('ul').children).map(function (oLI) { return oLI.outerHTML; }))) && setTimeout(function () { oHostImagePreview.style.backgroundImage = "none"; oTo = arrangeRollistPreview(oHostImagePreview, oImagePreview); oFrom = { l: exontrol.ORt(oTo.l.slice(), -oTo.l[2], 0), r: exontrol.Ert(oImagePreview) }; oHostRollist = document.createElement("span"); oHostRollist.id = "rollist"; oHostRollist.tabIndex = 0; oHostRollist.className = rgFeaturesData ? "features" : "notes"; setElementPos(oHostRollist, oFrom.l) oHostImagePreview.append(oHostRollist); // centers the image into the host and saves its original size setElementPos(oImagePreview, oFrom.r = exontrol.G.C2R(exontrol.G.R2C([0, 0].concat(exontrol.Ert(oHostImagePreview).slice(2))), oFrom.r[2], oFrom.r[3])); oImagePreview.original = { width: oFrom.r[2], height: oFrom.r[3] } exontrol.Rollist.ImportOptions.hdr = true; exontrol.Rollist.ImportOptions.eor = /^[ \t]*\r\n/m; oRollist = new exontrol.Rollist(oHostRollist, { data: rgFeaturesData || sReleaseNotes, cyclic: rgFeaturesData != null, data2: function () { return Array.from(PRODUCT.querySelector('ul').children).map(function (oLI) { return oLI.outerHTML; }) }(), select: sSelectVersion, allowFilterInput: "key", allowActions: "scroll", misc: { hAlign: 0.075, gradualOpacity: "1-0.2", zIndex: 299 } }); /** * @description The onselect() method notifies your application once the user selects an item at runtime (clicks an item) * @param {object} oItem Indicates the item being selected as an object of Item type */ oRollist.on("select", function (oItem) { if (oItem.Key) { var oURL = new URL(oWindowTop.location.href); oURL.searchParams.set('v', oItem.Key); oWindowTop.history.replaceState(null, null, decodeURIComponent(oURL.toString())); } }); /** * @description The onadditem() method notifies your application that a new item has been added to the control * @param {Item} oItem Indicates an object of Item type being added * @event */ oRollist.on("additem", function (oItem) { // sets the item's Key based on the first four digits appearing consecutively on the first line var sValue = oItem.Value, oVersion = sValue.match(/^\d+\.\d+(\.\d+\.\d+)?/); if (oVersion) oItem.Key = oVersion[0]; // escapes HTML characters (< and >) by replacing them with their respective HTML entities (< and >) sValue = sValue.replace(//g, ">"); // marks the first line as ho highlight using CSS sValue = sValue.replace(/^(.*)(\r?\n)?/, "$1$2"); // replaces *NEW:, *Added: and *Fixed: with elements //sValue = sValue.replace(/\*(.*?):/g, "*$1:"); sValue = sValue.replace(/\*(.*?):/g, function (all, p1) { return "*" + p1 + ":"; }); // changes the item's value oItem.Value = sValue; }); /** * @description The oncreate() method occurs once an HTML element is created and linked to a visible item. You can use this event to associate or set additional properties or options for the newly created element. * @param {oEvent} oEvent Defines the HTML element being constructed for a visible item, represented as an object with properties: {item,html}, where item is of type Item and html is of type HTMLElement * @param {Item} oEvent.item Specifies the item for which the HTML element is generated * @param {HTMLElement} oEvent.html Indicates the HTML element associated with the item * @event */ oRollist.on("create", function (oEvent) { var oHTMLElement = oEvent.html; // splits the HTML element into lines and adds a tooltip to each line, showing the full text if the line is not fully visible oHTMLElement.innerHTML = oHTMLElement.innerHTML.replace(/^(.*)$/gm, "$1"); oHTMLElement.querySelectorAll("line").forEach(function (oLine) { oLine.title = oLine.innerText; }) }); /** * @description The render() method renders/updates the control's content (moves the HTML elements based on the (current) layout) * @param {LVI} [oLayout] Indicates the layout of the items using an {LVI} type object, applied to HTML elements. If omitted, the current layout remains in effect. When specified, smooth transitions are disabled. * @private */ oRollist.render = (function (_super) { return function () { _super.apply(this, arguments); this.oHH.querySelectorAll("a[href2]").forEach(function (oAnchor) { var url = oAnchor.getAttribute('href2'); oAnchor.removeAttribute("href2"); // converts the "...help/source.htm" to "/rhelp.jsp?product=...&S=..." oMatchHelp = url.match(/help\/(.*)/s); if (!(bRemove = !oMatchHelp || !oMatchHelp[1])) oAnchor.href = "/rhelp.jsp?product=<%=product%>&S=" + oMatchHelp[1]; }) } })(oRollist.render); // smooths show the rollist and the image preview exontrol.A.Progress(function (p) { var rtImagePreview = morphRect(oFrom.r, oTo.r, p); setElementPos(oHostRollist, morphRect(oFrom.l, oTo.l, p)[0]); setElementPos(oImagePreview, rtImagePreview); }, { duration: 250, }) }, 5000); } }) } }); window.addEventListener("resize", function () { var oHostRollist = document.getElementById("rollist"), oImagePreview = document.getElementById("imgprew"), oHostImagePreview = oImagePreview && oImagePreview.closest(".host-preview-control"); if (oHostImagePreview && oHostRollist && oRollist) { oRollist.term(); oHostRollist.remove(); oImagePreview.style.left = 'initial'; oImagePreview.style.top = '50%'; oImagePreview.style.width = oImagePreview.original.width; oImagePreview.style.height = oImagePreview.original.height; } });