Update Function MISC_SERVE_SCALAR_UI

This commit is contained in:
2026-02-25 23:05:52 +00:00
parent e08bc98b5f
commit 4af0b18540

View File

@@ -1 +1,612 @@
@\@^@ SET PATH *LIBL ;
CREATE OR REPLACE FUNCTION RESTAPI.MISC_SERVE_SCALAR_UI (
P_URL VARCHAR(528) DEFAULT NULL ,
P_CONTENT CLOB(104857600) DEFAULT NULL ,
P_BASESERVERURL VARCHAR(528) DEFAULT NULL ,
P_SOURCES CLOB(104857600) DEFAULT NULL ,
P_LAYOUT VARCHAR(32) DEFAULT 'modern' ,
P_THEME VARCHAR(32) DEFAULT NULL ,
P_DARKMODE SMALLINT DEFAULT NULL ,
P_FORCEDARKMODESTATE VARCHAR(16) DEFAULT NULL ,
P_DOCUMENTDOWNLOADTYPE VARCHAR(32) DEFAULT NULL ,
P_FAVICON VARCHAR(528) DEFAULT NULL ,
P_WITHDEFAULTFONTS SMALLINT DEFAULT 1 ,
P_CUSTOMCSS CLOB(104857600) DEFAULT NULL ,
P_AUTHENTICATION CLOB(104857600) DEFAULT NULL ,
P_HIDESIDEBAR SMALLINT DEFAULT 0 ,
P_SHOWSIDEBAR SMALLINT DEFAULT 1 ,
P_HIDESEARCH SMALLINT DEFAULT 0 ,
P_HIDECLIENTBUTTON SMALLINT DEFAULT 0 ,
P_HIDEDARKMODETOGGLE SMALLINT DEFAULT 0 ,
P_HIDETESTREQUESTBUTTON SMALLINT DEFAULT NULL ,
P_HIDEMODELS SMALLINT DEFAULT 0 ,
P_SHOWOPERATIONID SMALLINT DEFAULT 0 ,
P_EXPANDALLRESPONSES SMALLINT DEFAULT NULL ,
P_EXPANDALLMODELSECTIONS SMALLINT DEFAULT NULL ,
P_DEFAULTOPENALLTAGS SMALLINT DEFAULT NULL ,
P_SHOWDEVELOPERTOOLS VARCHAR(16) DEFAULT 'always' ,
P_OPERATIONTITLESOURCE VARCHAR(32) DEFAULT NULL ,
P_ORDERREQUIREDPROPERTIESFIRST SMALLINT DEFAULT NULL ,
P_ORDERSCHEMAPROPERTIESBY VARCHAR(32) DEFAULT NULL ,
P_PATHROUTING CLOB(104857600) DEFAULT NULL ,
P_PERSISTAUTH SMALLINT DEFAULT NULL ,
P_SEARCHHOTKEY VARCHAR(16) DEFAULT NULL ,
P_DEFAULTHTTPCLIENT CLOB(104857600) DEFAULT NULL ,
P_TAGSSORTER VARCHAR(32) DEFAULT NULL ,
P_OPERATIONSSORTER VARCHAR(32) DEFAULT NULL ,
P_FETCH CLOB(104857600) DEFAULT NULL ,
P_PROXYURL VARCHAR(528) DEFAULT NULL ,
P_SERVERS CLOB(104857600) DEFAULT NULL ,
P_HIDDENCLIENTS CLOB(104857600) DEFAULT NULL ,
P_ONBEFOREREQUEST CLOB(104857600) DEFAULT NULL ,
P_ONREQUESTSENT CLOB(104857600) DEFAULT NULL ,
P_ONSHOWMORE CLOB(104857600) DEFAULT NULL ,
P_ONLOADED CLOB(104857600) DEFAULT NULL ,
P_ONSPECUPDATE CLOB(104857600) DEFAULT NULL ,
P_ONDOCUMENTSELECT CLOB(104857600) DEFAULT NULL ,
P_ONSERVERCHANGE CLOB(104857600) DEFAULT NULL ,
P_ONSIDEBARCLICK CLOB(104857600) DEFAULT NULL ,
P_METADATA CLOB(104857600) DEFAULT NULL ,
P_PLUGINS CLOB(104857600) DEFAULT NULL ,
P_REDIRECT VARCHAR(528) DEFAULT NULL ,
P_TELEMETRY SMALLINT DEFAULT 0 ,
P_GENERATEHEADINGSLUG CLOB(104857600) DEFAULT NULL ,
P_GENERATEOPERATIONSLUG CLOB(104857600) DEFAULT NULL ,
P_GENERATETAGSLUG CLOB(104857600) DEFAULT NULL ,
P_GENERATEWEBHOOKSLUG CLOB(104857600) DEFAULT NULL ,
P_GENERATEMODELSLUG CLOB(104857600) DEFAULT NULL ,
P_ISLOADING SMALLINT DEFAULT 1 )
RETURNS CLOB(2147483647)
LANGUAGE SQL
SPECIFIC RESTAPI.MISC_SERVE_SCALAR_UI
NOT DETERMINISTIC
READS SQL DATA
CALLED ON NULL INPUT
SET OPTION ALWBLK = *ALLREAD ,
ALWCPYDTA = *OPTIMIZE ,
COMMIT = *NONE ,
DECRESULT = (31, 31, 00) ,
DYNDFTCOL = *NO ,
DYNUSRPRF = *USER ,
SRTSEQ = *HEX
BEGIN
RETURN
( '<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Scalar API Reference - Full Config Playground</title>
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;700&display=swap" rel="stylesheet" />
<style>
body {
margin: 0;
padding: 0;
font-family: "Poppins", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
}
#app {
min-height: 100vh;
transition: filter 0.3s ease-in-out;
}
#app.modal-blur {
filter: blur(8px);
}
#modal-overlay {
position: fixed;
top: 0;
left: 0;
width:100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
display: none;
justify-content: center;
align-items: center;
z-index: 1000;
}
#modal-dialog {
background-color: white;
box-shadow: 0 4px 12px rgba(0,0, 0, 0.15);
width: 600px;
max-width: 90%;
padding: 24px;
display: flex;
flex-direction: column;
gap: 16px;
}
#modal-dialog h3 {
font-size:1.5em;
font-weight: bold;
margin: 0;
color:#333;
}
#modal-dialog p {
font-size: 0.9em;
line-height: 1.5;
color: #555;
margin: 0;
}
#input-container {
position: relative;
border: 1px solid #ccc;
padding: 12px;
min-height: 100px;
background-color: #f8f8f8;
}
#input-placeholder {
position: absolute;
top: 8px;
left: 12px;
color: #999;
font-size: 1.5em;
pointer-events: none;
}
#api-input {
width: 100%;
height: 100px;
border: none;
outline: none;
background: transparent;
resize: none;
padding-top: 18px;
box-sizing: border-box;
color: #333;
font-family: monospace;
font-size: 0.85em;
}
#button-container {
display: flex;
gap: 8px;
justify-content: flex-end;
margin-top: 16px;
}
.modal-btn {
padding: 10px 20px;
cursor: pointer;
font-size: 0.9em;
font-weight: 500;
border-radius: 4px;
}
#cancel-btn {
background-color: #f0f0f0;
border: 1px solid #ddd;
color: #333;
}
#cancel-btn:hover {
background-color: #e0e0e0;
}
#continue-btn {
background-color: #010e1c;
border: 1px solid #000000;
color: white;
}
#continue-btn:hover {
background-color: #021528;
}
</style>
</head>
<body>
<div id="modal-overlay">
<div id="modal-dialog">
<h3>Import API</h3>
<p>Paste the contents of your OpenAPI document (YAML/JSON) or a link to its location.</p>
<div id="input-container">
<span id="input-placeholder">OpenAPI Document or Link</span>
<textarea id="api-input"></textarea>
</div>
<div id="button-container">
<button id="cancel-btn" class="modal-btn">Cancel</button>
<buttonid="continue-btn" class="modal-btn">Continue</button>
</div>
</div>
</div>
<div id="app"></div>
<script>
(function(){
"use strict";
const ELEMENTS = {
app:"#app",
modal: "#modal-overlay",
input: "#api-input",
placeholder: "#input-placeholder",
cancelBtn: "#cancel-btn",
continueBtn: "#continue-btn"
};
const WELCOME_SPEC = {
openapi: "3.1.0",
info: {
title: "Welcome to Scalar",
description: "Please import an OpenAPI specification using the dialog above",
version: "1.0.0"
},
paths: {}
};
const DEFAULT_SCALAR_CONFIG = {
layout: ' ||
COALESCE ( '''' || P_LAYOUT || '''' , '''modern''' ) || ',
theme: ' || COALESCE ( '''' || P_THEME || '''' , 'undefined' )
|| ',
darkMode: ' || COALESCE (
CASE
WHEN P_DARKMODE = 1 THEN 'true'
WHEN P_DARKMODE = 0 THEN 'false'
ELSE NULL
END , 'undefined' ) || ',
forceDarkModeState: ' ||
COALESCE ( '''' || P_FORCEDARKMODESTATE || '''' , 'undefined' ) ||
',
documentDownloadType: ' ||
COALESCE ( '''' || P_DOCUMENTDOWNLOADTYPE || '''' , 'undefined' ) ||
',
favicon: ' ||
COALESCE ( '''' || P_FAVICON || '''' , 'undefined' ) || ',
withDefaultFonts: ' || COALESCE (
CASE
WHEN P_WITHDEFAULTFONTS = 1 THEN 'true'
ELSE 'false'
END , 'true' ) || ',
customCss: ' ||
COALESCE ( '''' || P_CUSTOMCSS || '''' , 'undefined' ) || ',
authentication: ' ||
COALESCE ( P_AUTHENTICATION , 'undefined' ) || ',
hideSidebar: '|| COALESCE (
CASE
WHEN P_HIDESIDEBAR = 1 THEN 'true'
ELSE 'false'
END , 'false' ) || ',
showSidebar: ' || COALESCE (
CASE
WHEN P_SHOWSIDEBAR = 1 THEN 'true'
ELSE 'false'
END , 'true' ) || ',
hideSearch: ' || COALESCE (
CASE
WHEN P_HIDESEARCH = 1 THEN 'true'
ELSE 'false'
END , 'false' ) || ',
hideClientButton: ' || COALESCE (
CASE
WHEN P_HIDECLIENTBUTTON = 1 THEN 'true'
ELSE 'false'
END , 'false' ) || ',
hideDarkModeToggle: ' || COALESCE (
CASE
WHEN P_HIDEDARKMODETOGGLE = 1 THEN 'true'
ELSE 'false'
END , 'false' ) || ',
hideTestRequestButton: ' || COALESCE (
CASE
WHEN P_HIDETESTREQUESTBUTTON = 1 THEN 'true'
WHEN P_HIDETESTREQUESTBUTTON = 0 THEN 'false'
ELSE NULL
END , 'undefined' ) || ',
hideModels: ' || COALESCE (
CASE
WHEN P_HIDEMODELS = 1 THEN 'true'
ELSE 'false'
END , 'false' ) || ',
showOperationId: ' || COALESCE (
CASE
WHEN P_SHOWOPERATIONID = 1 THEN 'true'
ELSE 'false'
END , 'false' ) || ',
expandAllResponses: ' || COALESCE (
CASE
WHEN P_EXPANDALLRESPONSES = 1 THEN 'true'
WHEN P_EXPANDALLRESPONSES = 0 THEN 'false'
ELSE NULL
END , 'undefined' ) || ',
expandAllModelSections: ' || COALESCE(
CASE
WHEN P_EXPANDALLMODELSECTIONS = 1 THEN 'true'
WHEN P_EXPANDALLMODELSECTIONS = 0 THEN 'false'
ELSE NULL
END , 'undefined' ) || ',
defaultOpenAllTags: ' || COALESCE (
CASE
WHEN P_DEFAULTOPENALLTAGS = 1 THEN 'true'
WHEN P_DEFAULTOPENALLTAGS = 0 THEN 'false'
ELSE NULL
END , 'undefined' ) || ',
showDeveloperTools: ' ||
COALESCE ( '''' || P_SHOWDEVELOPERTOOLS || '''' , '''always''' ) ||
',
operationTitleSource: ' ||
COALESCE ( '''' || P_OPERATIONTITLESOURCE || '''' , 'undefined' ) ||
',
orderRequiredPropertiesFirst: ' || COALESCE (
CASE
WHEN P_ORDERREQUIREDPROPERTIESFIRST = 1 THEN 'true'
WHEN P_ORDERREQUIREDPROPERTIESFIRST = 0 THEN 'false'
ELSE NULL
END , 'undefined' ) || ',
orderSchemaPropertiesBy: ' ||
COALESCE ( '''' || P_ORDERSCHEMAPROPERTIESBY || '''' , 'undefined' )
|| ',
pathRouting: ' || COALESCE ( P_PATHROUTING , 'undefined' )||
',
persistAuth: ' || COALESCE (
CASE
WHEN P_PERSISTAUTH = 1 THEN 'true'
WHEN P_PERSISTAUTH = 0 THEN 'false'
ELSE NULL
END , 'undefined' ) || ',
searchHotKey: ' ||
COALESCE ( '''' || P_SEARCHHOTKEY || '''' , 'undefined' ) || ',
defaultHttpClient: ' ||
COALESCE ( P_DEFAULTHTTPCLIENT , 'undefined' ) || ',
tagsSorter:' ||
COALESCE ( '''' || P_TAGSSORTER || '''' , 'undefined' ) || ',
operationsSorter: ' ||
COALESCE ( '''' || P_OPERATIONSSORTER || '''' , 'undefined' ) || ',
fetch: ' || COALESCE ( P_FETCH , 'undefined' ) || ',
proxyUrl: ' ||
COALESCE ( '''' || P_PROXYURL || '''' , 'undefined' ) || ',
servers: ' || COALESCE ( P_SERVERS , 'undefined' ) || ',
hiddenClients: ' || COALESCE ( P_HIDDENCLIENTS , 'undefined' )
|| ',
onBeforeRequest: ' ||
COALESCE ( P_ONBEFOREREQUEST , 'undefined' ) || ',
onRequestSent: ' || COALESCE ( P_ONREQUESTSENT , 'undefined' )
|| ',
onShowMore: ' || COALESCE ( P_ONSHOWMORE , 'undefined' ) || ',
onLoaded: ' || COALESCE ( P_ONLOADED , 'undefined' ) || ',
onSpecUpdate: ' || COALESCE ( P_ONSPECUPDATE , 'undefined' ) ||',
onDocumentSelect: ' ||
COALESCE ( P_ONDOCUMENTSELECT , 'undefined' ) || ',
onServerChange: ' ||
COALESCE ( P_ONSERVERCHANGE , 'undefined' ) || ',
onSidebarClick: ' ||
COALESCE ( P_ONSIDEBARCLICK , 'undefined' ) || ',
metaData: ' ||COALESCE ( P_METADATA , 'undefined' ) || ',
plugins: ' || COALESCE ( P_PLUGINS , 'undefined' ) || ',
redirect: ' ||
COALESCE ( '''' || P_REDIRECT || '''' , 'undefined' ) || ',
telemetry: ' || COALESCE (
CASE
WHEN P_TELEMETRY = 1 THEN 'true'
WHEN P_TELEMETRY = 0 THEN 'false'
ELSE NULL
END , 'undefined' ) || ',
generateHeadingSlug: ' ||
COALESCE ( P_GENERATEHEADINGSLUG , 'undefined' ) || ',
generateOperationSlug: ' ||
COALESCE ( P_GENERATEOPERATIONSLUG , 'undefined' ) || ',
generateTagSlug: ' ||
COALESCE ( P_GENERATETAGSLUG , 'undefined' ) || ',
generateWebhookSlug: ' ||
COALESCE ( P_GENERATEWEBHOOKSLUG , 'undefined' ) || ',
generateModelSlug: ' ||
COALESCE ( P_GENERATEMODELSLUG , 'undefined' ) || ',
isLoading:' || COALESCE (
CASE
WHEN P_ISLOADING = 1 THEN 'true'
WHEN P_ISLOADING = 0 THEN 'false'
ELSE NULL
END , 'undefined' ) || '
};
function getQueryParameter(paramName) {
const params = new URLSearchParams(window.location.search);
const normalizedName = paramName.toLowerCase();
for (const [key, value] of params) {
if (key.toLowerCase() === normalizedName) {
return value;
}
}
return null;
}
function isValidUrl(input) {
try {
const url = new URL(input);
const isHttpProtocol = url.protocol ==="http:" || url.protocol === "https:";
const isNotProtocolRelative = !input.startsWith("//");
return isHttpProtocol && isNotProtocolRelative;
} catch (error) {
return false;
}
}
function parseOpenApiContent(input) {
const trimmedInput = input.trim();
if (trimmedInput.startsWith("{") || trimmedInput.startsWith("[")) {
return JSON.parse(trimmedInput);
}
returntrimmedInput;
}
function hasValue(value) {
return value !== null && value !== undefined && value !== "";
}
const sqlParameters = {
url: "",
content: null,
sources: null,
baseServerURL: null
};
function determineInitialConfiguration() {
const config = {};
let showModal = false;
const specUrlParam = getQueryParameter("specUrl");
if (hasValue(specUrlParam)) {
config.url = specUrlParam;
return { config, showModal };
}
if (hasValue(sqlParameters.url)) {
config.url = sqlParameters.url;
return { config, showModal };
}
if(hasValue(sqlParameters.content) || hasValue(sqlParameters.sources)) {
if (hasValue(sqlParameters.content)) {
config.content = sqlParameters.content;
}
if(hasValue(sqlParameters.sources)) {
config.sources = sqlParameters.sources;
}
return { config, showModal };
}
config.content = WELCOME_SPEC;
showModal = true;
return { config, showModal };
}
const ScalarManager = {
instance: null,
isInitialized: false,
render(userConfig = {}) {
const finalConfig = { ...userConfig };
if(hasValue(sqlParameters.baseServerURL)) {
finalConfig.baseServerURL = sqlParameters.baseServerURL;
}
if (this.instance) {
const appElement = document.querySelector(ELEMENTS.app);
if (appElement) {
appElement.innerHTML = "";
}
}
this.instance = Scalar.createApiReference(ELEMENTS.app, {
...DEFAULT_SCALAR_CONFIG,
...finalConfig
});
console.log("Scalar API Reference initialized");
},
canInitialize() {
const isScalarLoaded = typeof Scalar !== "undefined";
const isDomReady = document.readyState !== "loading";
if (!isScalarLoaded) {
console.log("Waiting for Scalar library...");
}
if (!isDomReady) {
console.log("Waiting for DOM...");
}
return isScalarLoaded && isDomReady;
},
initialize() {
if (this.isInitialized){
return;
}
if (!this.canInitialize()) {
return;
}
this.isInitialized = true;
console.log("Initializing Scalar application...");
const { config, showModal } = determineInitialConfiguration();
if (showModal) {
ModalManager.show();
} else {
ModalManager.hide();
}
this.render(config);
}
};
const ModalManager = {
elements: {},
initialize() {
this.elements = {
modal: document.getElementById("modal-overlay"),
input: document.getElementById("api-input"),
placeholder: document.getElementById("input-placeholder"),
cancelBtn: document.getElementById("cancel-btn"),
continueBtn: document.getElementById("continue-btn")
};
this.attachEventListeners();
},
attachEventListeners() {
this.elements.input.addEventListener("input", () => {
this.updatePlaceholder();
});
this.elements.cancelBtn.addEventListener("click", () => {
this.hide();
});
this.elements.continueBtn.addEventListener("click", () => {
this.handleContinue();
});
},
updatePlaceholder() {
const hasInput = this.elements.input.value.length > 0;
this.elements.placeholder.style.display = hasInput ? "none" : "block";
},
show() {
this.elements.modal.style.display = "flex";
const appElement = document.querySelector(ELEMENTS.app);
if (appElement) {
appElement.classList.add("modal-blur");
}
},
hide() {
this.elements.modal.style.display = "none";
const appElement = document.querySelector(ELEMENTS.app);
if (appElement) {
appElement.classList.remove("modal-blur");
}
},
handleContinue() {
const userInput = this.elements.input.value.trim();
if (!userInput) {
alert("Please enter an OpenAPI document or URL");
return;
}
if (isValidUrl(userInput)) {
this.loadFromUrl(userInput);
return;
}
this.loadFromContent(userInput);
},
loadFromUrl(url) {
ScalarManager.render({ url });
this.hide();
},
loadFromContent(contentString) {
try {
const content = parseOpenApiContent(contentString);
ScalarManager.render({ content });
this.hide();
} catch (error) {
alert("Error parsing content: " + error.message);
}
}
};
const InitializationCoordinator = {
state: {
domReady: false,
scalarLibraryReady: false
},
tryInitialize() {
if(this.state.domReady && this.state.scalarLibraryReady) {
ScalarManager.initialize();
}
},
markDomReady() {
this.state.domReady = true;
this.tryInitialize();
},
markScalarReady() {
this.state.scalarLibraryReady = true;
this.tryInitialize();
},
setup() {
document.addEventListener("DOMContentLoaded", () => {
this.markDomReady();
});
window.onScalarLibraryLoaded = () => {
this.markScalarReady();
};
}
};
ModalManager.initialize();
InitializationCoordinator.setup();
})();
</script>
<script src="https://cdn.jsdelivr.net/npm/@scalar/api-reference/dist/browser/standalone.min.js"
onload="window.onScalarLibraryLoaded();"></script>
</body>
</html>' ) ;
END ;
GRANT ALTER , EXECUTE
ON SPECIFIC FUNCTION RESTAPI.MISC_SERVE_SCALAR_UI
TO AMAPICS WITH GRANT OPTION ;
GRANT EXECUTE
ON SPECIFIC FUNCTION RESTAPI.MISC_SERVE_SCALAR_UI
TO PUBLIC ;