fixes and improvements to tenant; implement Tenant Management Server

This commit is contained in:
Michael Becker 2024-11-01 22:52:57 -04:00
parent fb25146ff1
commit 6d743abcd1
37 changed files with 2367 additions and 25 deletions

View File

@ -1,19 +0,0 @@
<?php
use Phast\IncludeFile;
use Phast\System;
System::$IncludeFiles[] = new IncludeFile("/lib/mocha/system.inc.php", true);
System::$EnableTenantedHosting = false;
System::$Configuration["Application.Title"] = "Mocha SUV";
System::$Configuration["Application.DefaultTenant"] = "super";
System::$Configuration["Application.ThemeName"] = "avondale";
System::$Configuration["Database.ServerName"] = "localhost";
System::$Configuration["Database.PortNumber"] = 3306;
System::$Configuration["Database.DatabaseName"] = "mocha_suv";
System::$Configuration["Database.UserName"] = "mocha_suv";
System::$Configuration["Database.Password"] = "mocha_suv";
System::$Configuration["LoginPageRedirectURL"] = "~/madi/authgwy/$(CurrentTenantName)/login.htmld";
System::$Configuration["Runtime.DisableAutomaticExtensionParsing"] = 1;
System::$Configuration["Paths.MasterPages"] = [ "/ui/masterPages" ];
System::$Configuration["Paths.Pages"] = [ "/ui/pages" ];
require_once ("BeforeLaunchEvent.inc.php");
?>

View File

@ -15,6 +15,7 @@
use Mocha\Oop\MethodImplementation; use Mocha\Oop\MethodImplementation;
use Mocha\Oop\Methods\BuildAttributeMethod; use Mocha\Oop\Methods\BuildAttributeMethod;
use Phast\System; use Phast\System;
use Phast\Utilities\Stopwatch;
use Phast\UUID; use Phast\UUID;
abstract class Oms abstract class Oms
@ -149,7 +150,16 @@
return null; return null;
} }
return $this->getRelatedInstancesInternal($sourceInstance, $relationshipInstance, $effectiveDate); // trigger_error("MADI debug: entering " . get_class($this) . "::getRelatedInstancesInternal");
// $stopwatch = new Stopwatch();
// $stopwatch->start();
$insts = $this->getRelatedInstancesInternal($sourceInstance, $relationshipInstance, $effectiveDate);
// $stopwatch->stop();
// trigger_error("MADI debug: exiting " . get_class($this) . "::getRelatedInstancesInternal (took " . $stopwatch->getElapsedTime() . "s)");
return $insts;
} }
protected abstract function getRelatedInstancesInternal(InstanceReference $sourceInstance, InstanceReference $relationshipInstance, \DateTime $effectiveDate = null) : ?array; protected abstract function getRelatedInstancesInternal(InstanceReference $sourceInstance, InstanceReference $relationshipInstance, \DateTime $effectiveDate = null) : ?array;

View File

@ -4,6 +4,7 @@
use Mocha\Core\InstanceReference; use Mocha\Core\InstanceReference;
use Mocha\Core\OmsContext; use Mocha\Core\OmsContext;
use Mocha\Oms\Oms; use Mocha\Oms\Oms;
use Phast\Utilities\Stopwatch;
abstract class MethodImplementation abstract class MethodImplementation
{ {
@ -13,7 +14,16 @@
public function execute(Oms $oms, OmsContext $context, InstanceReference $method, ?array $parms) : mixed public function execute(Oms $oms, OmsContext $context, InstanceReference $method, ?array $parms) : mixed
{ {
array_push($context->CallStack, $method); array_push($context->CallStack, $method);
trigger_error("MADI debug: entering " . get_class($this) . "::executeInternal");
$stopwatch = new Stopwatch();
$stopwatch->start();
$retval = $this->executeInternal($oms, $context, $method, $parms); $retval = $this->executeInternal($oms, $context, $method, $parms);
$stopwatch->stop();
trigger_error("MADI debug: exiting " . get_class($this) . "::executeInternal (took " . $stopwatch->getElapsedTime() . "s)");
array_pop($context->CallStack); array_pop($context->CallStack);
return $retval; return $retval;
} }

View File

@ -22,7 +22,16 @@
protected function OnInitializing(CancelEventArgs $e) protected function OnInitializing(CancelEventArgs $e)
{ {
$oms = mocha_get_oms(); $oms = mocha_get_oms();
$oms->setTenant($oms->getTenantByName(System::GetTenantName()));
$tenantName = System::GetTenantName();
$tenant = $oms->getTenantByName($tenantName);
if ($tenant == null)
{
System::Redirect("~/" . $tenantName, true);
exit();
}
$oms->setTenant($tenant);
$oms->initializeInstanceCache(); $oms->initializeInstanceCache();
// echo (" login token: " . $_SESSION["user_token_" . $oms->getTenant()->ID]); // echo (" login token: " . $_SESSION["user_token_" . $oms->getTenant()->ID]);
@ -90,7 +99,9 @@
{ {
$tenantName = $path[0]; $tenantName = $path[0];
} }
$oms->setTenant($oms->getTenantByName($tenantName));
$tenant = $oms->getTenantByName($tenantName);
$oms->setTenant($tenant);
$pageElement = $oms->getInstanceByGlobalIdentifier(KnownInstanceGuids::Element__LoginPage); $pageElement = $oms->getInstanceByGlobalIdentifier(KnownInstanceGuids::Element__LoginPage);
if ($pageElement === null) if ($pageElement === null)

View File

@ -13,12 +13,54 @@
use Phast\WebPage; use Phast\WebPage;
use Phast\WebScript; use Phast\WebScript;
global $pdo;
global $basepath;
$pdo = null;
$pdoex = null;
try
{
$pdo = new \PDO("mysql:host=" . System::$Configuration["Database.ServerName"] . ";port=" . System::$Configuration["Database.PortNumber"] . ";dbname=" . System::$Configuration["Database.DatabaseName"], System::$Configuration["Database.UserName"], System::$Configuration["Database.Password"]);
}
catch (\Exception $ex)
{
$pdoex = $ex;
echo($pdoex); die();
}
$basepath = $_SERVER["SERVER_NAME"];
class SUVPage extends WebPage class SUVPage extends WebPage
{ {
protected function OnPreRender(CancelEventArgs $e) protected function OnPreRender(CancelEventArgs $e)
{ {
global $pdo;
global $basepath;
$e->Cancel = true; $e->Cancel = true;
if ($_POST["reset"] == "1")
{
$stmt = $pdo->prepare("DELETE FROM mocha_attributes WHERE tenant_id > 2");
$stmt->execute();
$stmt = $pdo->prepare("DELETE FROM mocha_relationships WHERE tenant_id > 2");
$stmt->execute();
$stmt = $pdo->prepare("DELETE FROM mocha_instances WHERE tenant_id > 2");
$stmt->execute();
$stmt = $pdo->prepare("DELETE FROM mocha_tenant_references WHERE source_tenant_id > 2");
$stmt->execute();
$stmt = $pdo->prepare("DELETE FROM mocha_tenants WHERE id > 2");
$stmt->execute();
header("HTTP/1.1 302 Found");
header("Location: /suv/suvinfo.html");
exit();
}
$path = System::GetVirtualPath(); $path = System::GetVirtualPath();
if ($path[1] == "phpinfo.html") if ($path[1] == "phpinfo.html")
{ {
@ -94,6 +136,22 @@
return false; return false;
}); });
var btnResetTenants = document.getElementById("btnResetTenants");
btnResetTenants.addEventListener("click", function(e)
{
var hidResetTenantsConfirm = document.getElementById("hidResetTenantsConfirm");
if (!confirm("Reset tenants: Are you sure?"))
{
e.preventDefault();
e.stopPropagation();
return false;
}
else
{
hidResetTenantsConfirm.value = "1";
}
});
var wndCreateTenant_btnSaveChanges = document.getElementById("wndCreateTenant_btnSaveChanges"); var wndCreateTenant_btnSaveChanges = document.getElementById("wndCreateTenant_btnSaveChanges");
wndCreateTenant_btnSaveChanges.ni = wndCreateTenant; wndCreateTenant_btnSaveChanges.ni = wndCreateTenant;
wndCreateTenant_btnSaveChanges.addEventListener("click", function(e) wndCreateTenant_btnSaveChanges.addEventListener("click", function(e)
@ -209,7 +267,10 @@ EOF
?> ?>
<div style="margin-bottom: 16px;"> <div style="margin-bottom: 16px;">
<a id="btnAddTenant" class="uwt-button uwt-color-primary" href="#">Add Tenant</a> <a id="btnAddTenant" class="uwt-button uwt-color-primary" href="#">Add Tenant</a>
<button class="uwt-button">Reset Tenants</button> <form method="POST">
<input type="hidden" id="hidResetTenantsConfirm" name="reset" value="0" />
<button class="uwt-button" id="btnResetTenants">Reset Tenants</button>
</form>
</div> </div>
<table class="uwt-listview"> <table class="uwt-listview">
<thead> <thead>
@ -228,10 +289,22 @@ EOF
</thead> </thead>
<tbody> <tbody>
<?php <?php
global $pdo;
global $basepath;
$query = "SELECT * FROM mocha_tenants";
$stmt = $pdo->prepare($query);
$result = $stmt->execute();
$rows = $stmt->fetchAll();
foreach ($rows as $values)
{
if ($values["is_library"] != 0)
{
continue;
}
?> ?>
<tr> <tr>
<td>super</td> <td><a class="uwt-external-link" target="_blank" href="<?php echo("https://" . $basepath . "/" . $values["tenant_name"]); ?>"><?php echo ($values["tenant_name"]); ?></a></td>
<td>Active</td> <td>Active</td>
<td>Development</td> <td>Development</td>
<td>Local</td> <td>Local</td>
@ -242,6 +315,9 @@ EOF
<td></td> <td></td>
<td>Default Tenant</td> <td>Default Tenant</td>
</tr> </tr>
<?php
}
?>
</tbody> </tbody>
</table> </table>
<?php <?php

View File

@ -0,0 +1,68 @@
<?php
require_once ("include/Configuration.inc.php");
$pdo = null;
$pdoex = null;
try
{
$pdo = new \PDO("mysql:host=" . System::$Configuration["Database.ServerName"] . ";port=" . System::$Configuration["Database.PortNumber"] . ";dbname=" . System::$Configuration["Database.DatabaseName"], System::$Configuration["Database.UserName"], System::$Configuration["Database.Password"]);
}
catch (Exception $ex)
{
$pdoex = $ex;
echo($pdoex); die();
}
$data = file_get_contents("php://input");
$json = json_decode($data, true);
$action = $json["action"];
if ($action == "createTenant")
{
$tenantName = $json["tenantName"];
$tenantType = $json["tenantType"];
$tenantCount = $json["tenantCount"];
$stmt = $pdo->prepare("INSERT INTO mocha_tenants (tenant_name, global_identifier, effective_date, is_library) VALUES (:tenant_name, mocha_uuid_v4(), NOW(), 0)");
$stmt2 = $pdo->prepare("INSERT INTO mocha_tenant_references (source_tenant_id, target_tenant_id) VALUES (:source_tenant_id, 1)");
if ($tenantCount == 1)
{
$result = $stmt->execute(array
(
"tenant_name" => $tenantName
));
$lastInsertId = $pdo->lastInsertId();
$result = $stmt2->execute(array
(
":source_tenant_id" => $lastInsertId
));
echo ($result);
}
else if ($tenantCount > 1)
{
for ($i = 0; $i < $tenantCount; $i++)
{
$result = $stmt->execute(array
(
"tenant_name" => $tenantName . ($i + 1)
));
$lastInsertId = $pdo->lastInsertId();
$result = $stmt2->execute(array
(
":source_tenant_id" => $lastInsertId
));
echo ($result);
}
}
}
else
{
echo("undefined action: '" . $action . "'");
}
?>

View File

@ -0,0 +1,144 @@
function post(url, payload, callback)
{
var xhr = new XMLHttpRequest();
xhr.callback = callback;
xhr.onreadystatechange = function()
{
if (this.readyState == 4)
{
if (typeof(this.callback) == 'function')
{
this.callback();
}
}
};
var payloadText = null;
if (typeof(payload) === 'string' || typeof(payload) == 'boolean' || typeof(payload) == 'number')
{
payloadText = payload.toString();
}
else if (typeof(payload) === 'object')
{
payloadText = JSON.stringify(payload);
}
xhr.open("POST", url);
xhr.send(JSON.stringify(payload));
}
function alert(message)
{
if (typeof(message) == 'string')
{
Dialog.ShowDialog("", message, [ { "dialogResult": DialogResult.OK, "title": "OK", "className": "uwt-color-primary" }]);
}
else if (typeof(message) == 'object')
{
Dialog.ShowDialog("", message.content, [ { "dialogResult": DialogResult.OK, "title": "OK", "className": "uwt-color-primary", "callback": function(dlg, btn)
{
message.callback();
}
}]);
}
}
window.addEventListener("load", function()
{
var tsbProvision = document.getElementById("tsbProvision");
tsbProvision.addEventListener("click", function()
{
// usage: Dialog.ShowDialog(title, prompt, buttons, fields, callback)
Dialog.ShowDialog
(
"Provision New Tenant(s)",
"",
[
{
"dialogResult": DialogResult.OK,
"title": "OK",
"className": "uwt-color-primary",
"callback": function(dlg, btn)
{
post("/api.php", {
"action": "createTenant",
"tenantName": dlg.getField("tenant_name").getValue(),
"tenantType": dlg.getField("tenant_type").getValue(),
"tenantCount": dlg.getField("tenant_count").getValue()
}, function()
{
window.location.reload();
});
return true;
}
},
{
"dialogResult": DialogResult.CANCEL,
"title": "Cancel"
}
],
[
{
"type": "literal",
"value": "<p>Please specify the name of your new tenant and select a tenant type. For more information about the various tenant types please consult the <a href=\"#\">Mocha documentation</a>.</p>"
},
{
"id": "tenant_name",
"type": "text",
"title": "Tenant name"
},
{
"id": "tenant_type",
"type": "choice",
"title": "Tenant type",
"choices":
[
{
"title": "Production",
"value": "{5535F488-6C8E-42BC-86A3-664D70411A2A}",
"color": "#85C744"
},
{
"title": "Sandbox",
"value": "{6A3767FD-6606-426F-B8D9-507B9FFE595C}",
"color": "#F1C40F"
},
{
"title": "Implementation",
"value": "{E860A64C-C156-49E7-80E5-E3BA3CE4D15D}",
"color": "#2BBCE0"
},
{
"title": "Development",
"value": "{B4F900F1-2C22-41FD-AAB9-7C956663256F}",
"color": "#E73C3C"
},
{
"title": "Internal Development",
"value": "{716D4C16-040F-4EBB-A920-DDF88765A017}",
"color": "#E73C3C"
},
{
"title": "Sandbox Preview Preview",
"value": "{b225d85b-d1a2-4ce7-90bc-410f2d5c0a53}",
"color": "#F1C40F"
}
]
},
{
"type": "literal",
"value": "<p>You may specify the number of tenants to create. If this is more than 1, tenants are named 'tenant<i>N</i>', where 'tenant' is the specified tenant name and 'N' is a value from 1 to the number of tenants requested.</p>"
},
{
"id": "tenant_count",
"type": "numeric",
"title": "Number of tenants",
"value": 1,
"minimumValue": 1,
"maximumValue": 9
}
]
);
});
});

View File

@ -0,0 +1,220 @@
function DialogResult(value)
{
this.value = value;
}
DialogResult.OK = new DialogResult(1);
DialogResult.CANCEL = new DialogResult(2);
// ewwww
// Only implement if no native implementation is available
if (typeof(Array.isArray) === 'undefined')
{
Array.isArray = function(obj)
{
return Object.prototype.toString.call(obj) === '[object Array]';
};
}
function Dialog()
{
}
Dialog.__handleButton = function(dialog, button, callback)
{
if (typeof(button.btn.callback) == 'function')
{
var ret = button.btn.callback(dialog, button);
if (typeof(ret) == 'boolean')
{
if (!ret)
{
// callback returned false; do not continue processing
return;
}
}
}
if (typeof(callback) == 'function')
{
var ret = callback(dialog, button);
if (typeof(ret) == 'boolean')
{
if (!ret)
{
// callback returned false; do not continue processing
return;
}
}
}
if (typeof(button.dialogResult) !== 'undefined')
{
dialog.window.Hide();
}
};
Dialog.ShowDialog = function(title, prompt, buttons, fields, callback)
{
var dlg = new Dialog();
dlg.getField = function(id)
{
for (var i = 0; i < this.fields.length; i++)
{
if (this.fields[i].id == id) return this.fields[i];
}
return null;
};
dlg.fields = fields;
var wnd = new Window();
wnd.dlg = dlg;
dlg.window = wnd;
wnd.SetTitle(title);
wnd.ParentElement.addEventListener("keydown", function(e)
{
if (e.keyCode == 13)
{
Dialog.__handleButton(this.NativeObject.dlg, this.NativeObject.dlg.__okButton, null);
}
});
var cel = wnd.GetContentElement();
var p = document.createElement("p");
p.innerHTML = prompt;
cel.appendChild(p);
if (Array.isArray(fields))
{
var formview = document.createElement("table");
formview.className = "uwt-formview";
for (var i = 0; i < fields.length; i++)
{
fields[i].element = null;
fields[i].getValue = function()
{
return null;
};
var tr = document.createElement("tr");
tr.className = "uwt-formview-item";
var td = document.createElement("td");
td.className = "uwt-formview-item-title";
if (fields[i].type != "literal")
{
var label = document.createElement("label");
label.innerHTML = fields[i].title;
td.appendChild(label);
tr.appendChild(td);
}
td = document.createElement("td");
td.className = "uwt-formview-item-content";
if (fields[i].type == "literal")
{
td.innerHTML = fields[i].value;
td.colSpan = 2;
}
else if (fields[i].type == "text" || fields[i].type == "numeric")
{
var input = document.createElement("input");
if (fields[i].type == "numeric")
{
input.type = "number";
}
else
{
input.type = "text";
}
td.appendChild(input);
if (typeof(fields[i].value) == 'number')
{
input.value = fields[i].value;
}
fields[i].element = input;
fields[i].getValue = function()
{
return this.element.value;
};
}
else if (fields[i].type == "choice")
{
var select = document.createElement("select");
for (var j = 0; j < fields[i].choices.length; j++)
{
var option = document.createElement("option");
option.innerHTML = fields[i].choices[j].title;
if (typeof(fields[i].choices[j].value) !== 'undefined')
{
option.value = fields[i].choices[j].value;
}
if (typeof(fields[i].choices[j].color) !== 'undefined')
{
option.setAttribute("data-color", fields[i].choices[j].color);
}
select.appendChild(option);
}
td.appendChild(select);
select.NativeObject = new DropDownWrapper(select);
fields[i].element = select;
fields[i].getValue = function()
{
return this.element.value;
};
}
tr.appendChild(td);
formview.appendChild(tr);
}
cel.appendChild(formview);
}
var ftt = wnd.GetFooterElement();
ftt.style.display = "";
if (Array.isArray(buttons))
{
for (var i = 0; i < buttons.length; i++)
{
var btn = document.createElement("a");
btn.className = "uwt-button";
if (buttons[i].className)
{
System.ClassList.Add(btn, buttons[i].className);
}
if (buttons[i].title)
{
btn.innerHTML = buttons[i].title;
}
if (typeof(buttons[i].dialogResult) !== 'undefined')
{
btn.dialogResult = buttons[i].dialogResult;
if (btn.dialogResult == DialogResult.OK)
{
dlg.__okButton = btn;
}
}
btn.btn = buttons[i];
btn.dlg = dlg;
btn.addEventListener("click", function()
{
Dialog.__handleButton(this.dlg, this, callback);
});
ftt.appendChild(btn);
}
}
wnd.ShowDialog();
};

View File

@ -0,0 +1,18 @@
<?php
class System
{
public static $Configuration;
}
System::$Configuration = array();
System::$Configuration["Application.Title"] = "Mocha SUV";
System::$Configuration["Application.DefaultTenant"] = "super";
System::$Configuration["Application.ThemeName"] = "avondale";
System::$Configuration["Database.ServerName"] = "localhost";
System::$Configuration["Database.PortNumber"] = 3306;
System::$Configuration["Database.DatabaseName"] = "mocha_suv";
System::$Configuration["Database.UserName"] = "mocha_suv";
System::$Configuration["Database.Password"] = "TjMG2k8eAR5xAHE613qJsNAagTBPGfaj";
?>

View File

@ -0,0 +1,205 @@
<?php
require_once ("include/Configuration.inc.php");
$pdo = null;
$pdoex = null;
try
{
$pdo = new \PDO("mysql:host=" . System::$Configuration["Database.ServerName"] . ";port=" . System::$Configuration["Database.PortNumber"] . ";dbname=" . System::$Configuration["Database.DatabaseName"], System::$Configuration["Database.UserName"], System::$Configuration["Database.Password"]);
}
catch (Exception $ex)
{
$pdoex = $ex;
echo($pdoex); die();
}
$basepath = $_SERVER["SERVER_NAME"];
?>
<html>
<head>
<title>Tenant Management System</title>
<link rel="stylesheet" type="text/css" href="style/avondale/avondale.min.css" />
<style type="text/css">
a.uwt-external-link::after
{
content: "\f08e";
font-family: "Font Awesome 6 Pro";
padding-left: 8px;
font-weight: 300;
}
div.uwt-page-header > div.uwt-toolbar
{
background-color: #eee;
padding: 16px;
margin-bottom: -16px;
margin-left: -16px;
margin-right: -16px;
border-top: 1px solid #aaa;
margin-top: ;
padding-bottom: 8px;
}
div.uwt-page-header > div.uwt-toolbar > a
{
color: #000;
text-decoration: none;
padding: 8px;
}
div.uwt-page-header > div.uwt-toolbar > a:hover
{
background-color: #ccc;
}
div.uwt-page-header > div.uwt-toolbar > a:active
{
background-color: #aaa;
}
div.uwt-toolbar > span.uwt-separator
{
border-left: 1px solid #ccc;
border-right: 1px solid #fff;
}
div.uwt-window
{
max-width: 800px;
}
div.uwt-window > div.uwt-content > p:empty
{
display: none;
}
p
{
margin: 16px 0px;
}
ul.uwt-menu > li > a > span.uwt-icon.uwt-color-tile
{
background-color: #fff;
border: 1px solid var(--uwt-color-dark);
padding: 8px;
margin: 8px;
display: inline-block;
position: absolute;
left: 0px;
top: 0px;
}
ul.uwt-menu > li > a > span.uwt-title, ul.uwt-menu > li > a > span.uwt-description
{
padding-left: 16px;
}
</style>
<script type="text/javascript" src="scripts/phast/System.js.php"></script>
<script type="text/javascript" src="dialog.js"></script>
<script type="text/javascript" src="app.js"></script>
</head>
<body class="uwt-header-visible">
<form method="POST">
<div class="uwt-page-header">
<h1>Tenant Management</h1>
<p>Welcome, <strong>superuser</strong></p>
<div class="uwt-toolbar">
<a id="tsbProvision" href="#">Provision New Tenant</a>
<span class="uwt-separator">&nbsp;</span>
<a id="tsbPackageImport" href="#">Import Package</a>
<a id="tsbPackageExport" href="#">Export Package</a>
</div>
</div>
<div class="uwt-page-content">
<?php
if ($pdoex === null)
{
?>
<h2>Customer Tenants</h2>
<table class="uwt-listview">
<thead>
<tr>
<th>Tenant Name</th>
<th>Status</th>
<th>Tenant Type</th>
<th>Data Center</th>
<th>Charge / No Charge</th>
<th>Initial Term</th>
<th>Renewal Term</th>
<th>Tenant Start Date</th>
<th>Tenant End Date</th>
<th>Purpose</th>
</tr>
</thead>
<tbody>
<?php
$query = "SELECT * FROM mocha_tenants";
$stmt = $pdo->prepare($query);
$result = $stmt->execute();
$rows = $stmt->fetchAll();
foreach ($rows as $values)
{
if ($values["is_library"] != 0)
{
continue;
}
?>
<tr>
<td><a class="uwt-external-link" target="_blank" href="<?php echo("https://" . $basepath . "/" . $values["tenant_name"]); ?>"><?php echo ($values["tenant_name"]); ?></a></td>
<td>Active</td>
<td>MADI Internal Development</td>
<td>Local</td>
<td>No Charge</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<?php
}
?>
</tbody>
</table>
<?php
}
else
{
?>
<div class="uwt-window uwt-visible" style="margin-left: auto; margin-right: auto; margin-top: 240px; width: 800px; display: block; position: static;">
<div class="uwt-header">
<span class="uwt-title">Database Intialization Error</span>
</div>
<div class="uwt-content">
<p><?php print_r($pdoex->getCode() . " : " . $pdoex->getMessage()); ?></p>
<table class="uwt-listview">
<thead>
<tr>
<th>#</th>
<th>File Name</th>
<th>Line Number</th>
<th>Function</th>
</tr>
</thead>
<tbody>
<?php
$trace = $pdoex->getTrace();
for ($i = 0; $i < count($trace); $i++)
{
?>
<tr>
<td><?php echo($i); ?></td>
<td><?php echo($trace[$i]["file"]); ?></td>
<td><?php echo($trace[$i]["line"]); ?></td>
<td><?php echo($trace[$i]["class"] . "::" . $trace[$i]["function"]); ?></td>
</tr>
<?php
}
?>
</tbody>
</table>
</div>
</div>
<?php
}
?>
</div>
</form>
</body>
</html>

View File

@ -0,0 +1,5 @@
function KnownInstanceKeys()
{
}
KnownInstanceKeys.DisplayOption__NotEnterable = "924$2";

View File

@ -0,0 +1,208 @@
function McxElementListView(parentElement)
{
this.ParentElement = parentElement;
this.CaptionElement = this.ParentElement.children[0];
this.HeaderElement = this.ParentElement.children[1];
this.HeaderRowElement = this.HeaderElement.children[0];
this.CountInput = this.ParentElement.parentElement.parentElement.children[0];
this.HeaderAddRowButton = this.HeaderRowElement.children[0].children[0];
this.HeaderAddRowButton.NativeObject = this;
this.HeaderAddRowButton.addEventListener("click", function(e)
{
var lv = this.NativeObject;
lv.addRowBefore(0);
e.preventDefault();
e.stopPropagation();
return false;
});
this.BodyElement = this.ParentElement.children[2];
this.setEmpty = function(value)
{
if (value)
{
System.ClassList.Add(this.ParentElement.parentElement, "mcx-empty");
}
else
{
System.ClassList.Remove(this.ParentElement.parentElement, "mcx-empty");
}
};
this.buildRow = function(callback, callback_parms)
{
var lvInstId = this.ParentElement.getAttribute("data-fqecid");
var xhr = new XMLHttpRequest();
var url = System.ExpandRelativePath("~/" + System.TenantName + "/flowController.htmld");
xhr.open("POST", url);
var h = {
"_flowExecutionKey": "e0s1",
"ecid": lvInstId,
"sessionSecureToken": "7733ad40-edf6-4dc9-aa90-85bcf93cc8f0",
"clientRequestID" : "9af7ce5bc51348a6981539a98b267072"
};
xhr.__callback = callback;
xhr.__this = this;
xhr.onreadystatechange = function(e)
{
if (this.readyState === 4)
{
responseJSON = JSON.parse(this.responseText);
if (responseJSON.result == "success")
{
if (responseJSON.item.widget == "row")
{
// !!! `this` is now XHR, not McxElementListView !!!
var tr = document.createElement("tr");
tr.appendChild(this.__this.createAddRemoveColumn());
var newRowIndex = this.__this.BodyElement.children.length;
this.__this.CountInput.value = this.__this.BodyElement.children.length + 1;
for (var i = 1; i < this.__this.HeaderRowElement.children.length; i++)
{
// ! BEGIN HACK !
var columnOffset = 0;
if (this.__this.HeaderRowElement.children.length != responseJSON.item.contents.length)
{
columnOffset = 1;
}
var td = document.createElement("td");
var rowDefinition = responseJSON.item.contents[i - columnOffset];
if (typeof(rowDefinition) !== "undefined")
{
// var colInstId = this.__this.HeaderRowElement.children[i].getAttribute("data-ecid");
var colInstId = rowDefinition.ecid;
var colWidget = rowDefinition.widget;
var fqecid = lvInstId + ":" + newRowIndex + ":" + colInstId;
if (colWidget === "text")
{
var input = document.createElement("input");
input.id = "ec_" + fqecid;
input.name = "ec_" + fqecid;
input.setAttribute("data-ecid", "ec_" + fqecid);
input.type = "text";
td.appendChild(input);
}
else if (colWidget === "checkbox")
{
var input = document.createElement("input");
input.id = "ec_" + fqecid;
input.name = "ec_" + fqecid;
input.setAttribute("data-ecid", "ec_" + fqecid);
input.type = "checkbox";
td.appendChild(input);
//! must be called after appendChild since it needs to finagle the DOM
new CheckBox(input);
}
else if (colWidget === "monikerListInput")
{
var multiselect = false;
if (rowDefinition.multiselect === true)
{
multiselect = true;
}
var moniker = McxInstanceBrowser.create({ "multiselect": multiselect, "fullyQualifiedECID": fqecid, "ecid": rowDefinition.ecid, "validClassIds": [ rowDefinition.ecdt ], "autocompleteUrl": "~/prompt/c0/" + rowDefinition.ecdt });
if (moniker)
{
td.appendChild(moniker);
}
}
}
else
{
td.innerHTML = "undefined row def at index " + i;
}
tr.appendChild(td);
}
this.__callback(tr, callback_parms);
}
}
}
};
xhr.send(JSON.stringify(h));
};
this.addRowBefore = function(beforeIndex)
{
this.buildRow(function(tr, parms)
{
parms[0].BodyElement.insertBefore(tr, parms[0].BodyElement.children[parms[1]]);
}, [ this, beforeIndex ]);
this.setEmpty(false);
};
this.addRowAfter = function(afterElement)
{
this.buildRow(function(tr, parms)
{
parms[0].BodyElement.insertAfter(tr, parms[1]);
}, [ this, afterElement ]);
this.setEmpty(false);
};
this.removeRow = function(row)
{
row.remove();
this.setEmpty(this.BodyElement.children.length == 0);
};
this.removeRowAt = function(index)
{
this.BodyElement.children[index].remove();
this.setEmpty(this.BodyElement.children.length == 0);
};
this.createAddRemoveColumn = function()
{
var td = document.createElement("td");
td.className = "uwt-listview-row-buttons";
var aAdd = document.createElement("a");
aAdd.className = "uwt-listview-row-add";
aAdd.href = "#";
aAdd.NativeObject = this;
aAdd.addEventListener("click", function(e)
{
this.NativeObject.addRowAfter(this.parentElement);
e.preventDefault();
e.stopPropagation();
return false;
});
td.appendChild(aAdd);
var aRemove = document.createElement("a");
aRemove.className = "uwt-listview-row-remove";
aRemove.href = "#";
aRemove.NativeObject = this;
aRemove.addEventListener("click", function(e)
{
this.NativeObject.removeRow(this.parentElement.parentElement);
e.preventDefault();
e.stopPropagation();
return false;
});
td.appendChild(aRemove);
return td;
};
}
window.addEventListener("load", function()
{
var items = document.getElementsByClassName("mcx-element");
for (var i = 0; i < items.length; i++)
{
if (items[i].tagName === "TABLE" && System.ClassList.Contains(items[i], "uwt-listview"))
{
items[i].McxElementListView = new McxElementListView(items[i]);
}
}
});

View File

@ -0,0 +1,224 @@
function McxElementContent(parentElement)
{
this.ParentElement = parentElement;
this.LabelTd = this.ParentElement.children[0];
if (this.LabelTd)
{
if (this.LabelTd.tagName === "td")
{
this.LabelElement = this.LabelTd.children[0];
}
else
{
this.LabelElement = this.LabelTd;
}
}
this.updateElementContentsWithFlowController = function(value, changes)
{
alert("update elements");
for (var i = 0; i < changes.length; i++)
{
var ecid = changes[i].ecid;
var ec = document.getElementById("ec_" + ecid);
if (ec)
{
if (changes[i].addsDisplayOptions)
{
for (var j = 0; j < changes[i].addsDisplayOptions.length; j++)
{
if (changes[i].addsDisplayOptions[j].iid == "924$2")
{
if (value)
{
ec.setAttribute("disabled", "disabled");
}
else
{
ec.removeAttribute("disabled");
}
}
}
}
if (changes[i].removesDisplayOptions)
{
for (var j = 0; j < changes[i].removesDisplayOptions.length; j++)
{
if (changes[i].removesDisplayOptions[j].iid == KnownInstanceKeys.DisplayOption__NotEnterable)
{
if (value)
{
ec.removeAttribute("disabled");
}
else
{
ec.setAttribute("disabled", "disabled");
}
}
}
}
}
}
};
this.ValueContainer = this.ParentElement.children[1];
if (this.ValueContainer.children.length > 0)
{
if (this.ValueContainer.children[0].tagName === "INPUT")
{
this.ValueContainer.children[0].addEventListener("blur", function()
{
console.log(" DO validation Here!");
});
}
else if (this.ValueContainer.children[0].tagName === "DIV" && System.ClassList.Contains(this.ValueContainer.children[0], "mcx-instancebrowser"))
{
this.ValueContainer.children[0].children[2].addEventListener("blur", function(e)
{
var ib = this.parentElement.NativeObject;
console.log("IB selected items: " + ib.getSelectedItems().length);
});
}
else if (this.ValueContainer.children[0].tagName === "DIV" && System.ClassList.Contains(this.ValueContainer.children[0], "uwt-checkbox"))
{
var inputElement = this.ValueContainer.children[1];
inputElement.McxNativeObject = this;
inputElement.addEventListener("change", function()
{
var value = this.NativeObject.GetChecked();
var ecid = this.McxNativeObject.ParentElement.getAttribute("data-fqecid");
var xhr = new XMLHttpRequest();
var url = System.ExpandRelativePath("~/" + System.TenantName + "/flowController.htmld");
xhr.NativeObject = this.McxNativeObject;
xhr.NativeObject.ValueElement = this.NativeObject.ParentElement;
xhr.inputElement = this;
xhr.onreadystatechange = function()
{
if (this.readyState === 4)
{
console.log(xhr);
if (this.status === 200)
{
json = JSON.parse(xhr.responseText);
this.NativeObject.updateElementContentsWithFlowController(json.value, json.changes);
}
else
{
this.NativeObject.ValueElement.NativeObject.__inhibit_update = true;
this.NativeObject.ValueElement.NativeObject.ToggleChecked();
this.NativeObject.ValueElement.NativeObject.__inhibit_update = false;
if (this.status === 403 || this.status === 401)
{
Alert.show("Please log in to continue", "Not Logged In", "uwt-color-danger", 5000, "NotLoggedIn");
}
}
}
};
xhr.open("POST", url);
var h = {
"_flowExecutionKey": "e0s1",
"ecid": ecid,
"sessionSecureToken": "7733ad40-edf6-4dc9-aa90-85bcf93cc8f0",
"clientRequestID" : "9af7ce5bc51348a6981539a98b267072",
"value": value
};
xhr.send(JSON.stringify(h));
return true;
});
}
}
this.InstanceID = this.ParentElement.getAttribute("data-instance-id");
this.ECID = this.ParentElement.getAttribute("data-ecid");
if (this.LabelElement)
{
this.LabelElement.NativeObject = this;
this.LabelElement.addEventListener("contextmenu", function(e)
{
var cm = new ContextMenu();
var ecid = this.NativeObject.ECID;
var iid = this.NativeObject.InstanceID;
cm.Items = [
{
"JJJJ": this.NativeObject,
"ClassName": "MenuItemCommand",
"Title": "Show Field Properties",
"Visible": true,
"Execute": function()
{
var popup = Popup.create(this.JJJJ.LabelTd);
var listview = ListView.create(popup.ParentElement, {
"columns": [
{
"id": "ecid",
"title": "ECID"
},
{
"id": "iid",
"title": "Instance ID"
}
],
"items": [
{
"columns": [
{
"id": "ecid",
"value": ecid
},
{
"id": "iid",
"value": iid
}
]
}
]
});
popup.ParentElement.appendChild(listview.ParentElement);
popup.Show();
}
},
{
"ClassName": "MenuItemCommand",
"Title": "Show Field EC",
"Visible": true,
"Execute": function()
{
window.open(System.ExpandRelativePath("~/" + System.TenantName + "/d/inst/1$56/" + ecid + ".htmld"));
}
}
];
cm.Show(e.clientX, e.clientY, this);
e.preventDefault();
e.stopPropagation();
return false;
});
}
}
window.addEventListener("load", function()
{
var items = document.getElementsByClassName("mcx-elementcontent");
for (var i = 0; i < items.length; i++)
{
// console.log("found mcx-elementcontent");
// console.log(items[i]);
items[i].McxNativeObject = new McxElementContent(items[i]);
}
/*
var items = document.getElementsByClassName("mcx-element");
for (var i = 0; i < items.length; i++)
{
items[i].McxNativeObject = new McxElementContent(items[i]);
}
*/
});

View File

@ -0,0 +1,495 @@
function McxInstanceBrowser(parentElement)
{
this.ParentElement = parentElement;
this.HiddenElement = this.ParentElement.children[1];
this.TextBoxElement = this.ParentElement.children[2];
this.ListElement = this.ParentElement.children[3];
this.SearchResultsElement = this.ParentElement.children[4];
this.SearchResultsMenuElement = this.SearchResultsElement.children[0];
this.SearchResultsSpinnerElement = this.SearchResultsElement.children[1];
this.SearchResultsPlaceholderElement = this.SearchResultsElement.children[2];
this.__timeout = null;
this.TextBoxElement.NativeObject = this;
this.TextBoxElement.addEventListener("focus", function(e)
{
this.NativeObject.search(this.NativeObject.TextBoxElement.value);
this.NativeObject.setEditing(true);
});
this.ParentElement.addEventListener("blur", function(e)
{
console.log(e.relatedTarget);
this.NativeObject.setEditing(false);
});
this.setEditing = function(value)
{
if (value)
{
System.ClassList.Add(this.ParentElement, "mcx-editing");
}
else
{
System.ClassList.Remove(this.ParentElement, "mcx-editing");
}
};
this.SearchResultsElement.NativeObject = this;
this.SearchResultsElement.addEventListener("mousemove", function(e)
{
var searchResultsElements = this.NativeObject.SearchResultsMenuElement.children;
for (var i = 0; i < searchResultsElements.length; i++)
{
System.ClassList.Remove(searchResultsElements[i], "uwt-highlight");
}
System.ClassList.Add(e.target, "uwt-highlight");
});
this.SearchResultsElement.addEventListener("keydown", function(e)
{
if (e.keyCode == KeyboardKeys.Tab)
{
// we are tabbing out of the search results, forward
this.NativeObject.setEditing(false);
}
});
this.buildSearchResult = function(searchResult)
{
var li = document.createElement("li");
/*
var a = document.createElement("a");
a.href = System.ExpandRelativePath("~/" + System.TenantName + "/d/inst/" + searchResult.iid + ".htmld");
a.setAttribute("data-instance-id", searchResult.iid);
a.innerText = searchResult.title;
li.appendChild(a);
*/
var a = McxMoniker.create(searchResult.instanceId, searchResult.text, searchResult.viewTask);
li.appendChild(a);
a = document.createElement("a");
a.className = "uwt-delete-button";
a.NativeObject = this;
a.Index = this.ListElement.children.length;
a.addEventListener("click", function()
{
this.NativeObject.removeAt(this.Index);
});
li.appendChild(a);
return li;
};
this.getSelectedInstanceKeysString = function()
{
var str = "";
for (var i = 0; i < this.ListElement.children.length; i++)
{
var iid = this.ListElement.children[i].children[0].getAttribute("data-instance-id");
str += iid;
if (i < this.ListElement.children.length - 1)
{
str += ",";
}
}
return str;
};
this.setPlaceholderText = function(value)
{
this.SearchResultsPlaceholderElement.innerText = value;
};
this.clearSearchResults = function()
{
while(this.SearchResultsMenuElement.children.length > 0)
{
this.SearchResultsMenuElement.children[0].remove();
}
};
this.clearSelectedItems = function()
{
while (this.ListElement.children.length > 0)
{
this.ListElement.children[0].remove();
}
};
this.getSelectedItems = function()
{
var items = [];
var strbps = this.HiddenElement.value;
if (strbps === "")
return items;
var strbpa = strbps.split(",");
for (var i = 0; i < strbpa.length; i++)
{
items.push(InstanceKey.parse(strbpa[i]));
}
return items;
};
this.activateSearchResult = function(searchResult)
{
// `this` refers to the McxInstanceBrowser
if (!System.ClassList.Contains(this.ParentElement, "mcx-multiselect"))
{
this.clearSelectedItems();
}
this.ListElement.appendChild(this.buildSearchResult(searchResult));
this.TextBoxElement.value = "";
this.HiddenElement.value = this.getSelectedInstanceKeysString();
this.ParentElement.setAttribute("data-instance-ids", this.getSelectedInstanceKeysString());
return true;
};
this.search = function(query)
{
if (typeof(query) === 'undefined')
{
query = this.TextBoxElement.value;
}
System.ClassList.Add(this.SearchResultsElement, "uwt-loading");
this.clearSearchResults();
this.setPlaceholderText("type to search the list");
if (query === "")
{
System.ClassList.Add(this.SearchResultsElement, "mcx-placeholder-visible");
}
else
{
System.ClassList.Remove(this.SearchResultsElement, "mcx-placeholder-visible");
}
var xhr = new XMLHttpRequest();
xhr.NativeObject = this;
var url = System.ExpandRelativePath("~/" + System.TenantName + "/prompt/c0/" + this.ParentElement.getAttribute("data-ecid") + ".htmld");
xhr.open("POST", url);
var h = {
"_flowExecutionKey": "e0s1",
"_eventId_prompt": this.ParentElement.getAttribute("data-ecid"),
"sessionSecureToken": "7733ad40-edf6-4dc9-aa90-85bcf93cc8f0",
"clientRequestID" : "9af7ce5bc51348a6981539a98b267072",
"q" : query
};
xhr.onreadystatechange = function()
{
if (this.readyState === 4)
{
if (this.status == 200)
{
var json = JSON.parse(this.responseText);
this.NativeObject.clearSearchResults();
System.ClassList.Remove(this.NativeObject.SearchResultsElement, "mcx-placeholder-visible");
for (var i = 0; i < json.items.length; i++)
{
var li = document.createElement("li");
li.className = "uwt-menu-item uwt-menu-item-command uwt-visible";
li.searchResult = json.items[i];
li.NativeObject = this.NativeObject;
li.addEventListener("click", function()
{
if (this.NativeObject.activateSearchResult(this.searchResult))
{
this.NativeObject.setEditing(false);
}
});
var moniker = McxMoniker.create(json.items[i].instanceId, json.items[i].text);
/*
var span = document.createElement("span");
span.className = "uwt-title uwt-description-empty";
span.innerText = json.items[i].title;
li.appendChild(span);
*/
li.appendChild(moniker);
this.NativeObject.SearchResultsMenuElement.appendChild(li);
}
System.ClassList.Remove(this.NativeObject.SearchResultsElement, "uwt-loading");
}
else
{
if (json.responseCode === 403)
{
Alert.show("Please log in to continue", "Not Authorized", "uwt-color-danger");
}
else
{
System.ClassList.Add(this.NativeObject.SearchResultsElement, "mcx-placeholder-visible");
this.NativeObject.setPlaceholderText("Too many results. Please refine your search.");
}
System.ClassList.Remove(this.NativeObject.SearchResultsElement, "uwt-loading");
}
}
};
xhr.send(JSON.stringify(h));
};
this.TextBoxElement.addEventListener("keydown", function(e)
{
if (e.keyCode == 13)
{
if (this.NativeObject.SearchResultsMenuElement.children.length === 1)
{
if (this.NativeObject.activateSearchResult(this.NativeObject.SearchResultsMenuElement.children[0].searchResult))
{
this.NativeObject.setEditing(false);
}
}
else
{
if (this.NativeObject.__timeout !== null)
{
window.clearTimeout(this.NativeObject.__timeout);
}
this.NativeObject.search();
window.setTimeout(function(thiss)
{
if (thiss.NativeObject.SearchResultsMenuElement.children.length === 1)
{
if (thiss.NativeObject.activateSearchResult(thiss.NativeObject.SearchResultsMenuElement.children[0].searchResult))
{
thiss.NativeObject.setEditing(false);
}
}
}, 100, this);
}
e.preventDefault();
e.stopPropagation();
return false;
}
if (e.keyCode == 37)
{
return;
}
else if (e.keyCode == 38)
{
return;
}
else if (e.keyCode == 39)
{
return;
}
else if (e.keyCode == 40)
{
return;
}
else if (e.keyCode == 16 || e.keyCode == 17 || e.keyCode == 18)
{
return;
}
console.log(e.keyCode);
System.ClassList.Add(this.NativeObject.SearchResultsElement, "uwt-loading");
if (this.NativeObject.__timeout !== null)
{
window.clearTimeout(this.NativeObject.__timeout);
}
this.NativeObject.__timeout = window.setTimeout(function(thiss)
{
thiss.search(thiss.TextBoxElement.value);
}, 1000, this.NativeObject);
if (e.keyCode == KeyboardKeys.Tab && e.shiftKey)
{
// we are tabbing out of the input element, backward
this.NativeObject.setEditing(false);
return true;
}
if (e.keyCode == KeyboardKeys.Enter)
{
e.preventDefault();
e.stopPropagation();
return false;
}
else if (e.keyCode == KeyboardKeys.Escape)
{
System.ClassList.Remove(this.NativeObject.ParentElement, "mcx-editing");
}
else if (e.keyCode == KeyboardKeys.ArrowUp)
{
var searchResultsElements = this.NativeObject.SearchResultsMenuElement.children;
if (searchResultsElements.length > 0)
{
var i = searchResultsElements.length - 1;
var currentIndex = -1;
while (i >= 0)
{
if (System.ClassList.Contains(searchResultsElements[i], "uwt-highlight"))
{
currentIndex = i;
}
System.ClassList.Remove(searchResultsElements[i], "uwt-highlight");
i--;
}
if (currentIndex > 0)
{
System.ClassList.Add(searchResultsElements[currentIndex - 1], "uwt-highlight");
}
else
{
System.ClassList.Add(searchResultsElements[searchResultsElements.length - 1], "uwt-highlight");
}
}
}
else if (e.keyCode == KeyboardKeys.ArrowDown)
{
var searchResultsElements = this.NativeObject.SearchResultsMenuElement.children;
if (searchResultsElements.length > 0)
{
var i = 0;
var currentIndex = -1;
while (i < searchResultsElements.length)
{
if (System.ClassList.Contains(searchResultsElements[i], "uwt-highlight"))
{
currentIndex = i;
}
System.ClassList.Remove(searchResultsElements[i], "uwt-highlight");
i++;
}
if (currentIndex < searchResultsElements.length - 1)
{
System.ClassList.Add(searchResultsElements[currentIndex + 1], "uwt-highlight");
}
else
{
System.ClassList.Add(searchResultsElements[0], "uwt-highlight");
}
}
}
});
this.removeAt = function(index)
{
console.log(this.HiddenElement);
var strbps = this.HiddenElement.value;
var strbpa = strbps.split(",");
var strbpn = [ ];
for (var i = 0; i < strbpa.length; i++)
{
if (i !== index)
{
strbpn.push(strbpa[i]);
}
}
this.ListElement.children[index].remove();
this.HiddenElement.value = strbpn.join(",");
};
for (var i = 0; i < this.ListElement.children.length; i++)
{
var delete_btn = this.ListElement.children[i].children[1];
delete_btn.NativeObject = this;
delete_btn.addEventListener("click", function()
{
var index = Array.prototype.indexOf.call(this.NativeObject.ListElement.children, this.parentElement);
this.NativeObject.removeAt(index);
});
}
}
McxInstanceBrowser.create = function(parms)
{
var div = document.createElement("DIV");
div.className = "mcx-instancebrowser mcx-editable";
if (parms.multiselect === true)
{
System.ClassList.Add(div, "mcx-multiselect");
}
var value = null;
if (parms.ecid)
{
div.setAttribute("data-ecid", parms.ecid);
}
if (typeof(parms.selectedInstanceIds) === "object")
{
value = parms.selectedInstanceIds.join(";");
div.setAttribute("data-instance-ids", value);
}
if (typeof(parms.validClassIds) === "object")
{
div.setAttribute("data-valid-class-ids", parms.validClassIds.join(";"));
}
if (parms.autocompleteUrl)
{
div.setAttribute("data-autocomplete-url", parms.autocompleteUrl);
}
var divTitle = document.createElement("DIV");
if (parms.title)
{
divTitle.innerHTML = title;
}
div.appendChild(divTitle);
var inputHidden = document.createElement("INPUT");
inputHidden.type = "hidden";
inputHidden.name = "ec_" + parms.fullyQualifiedECID;
if (value !== null)
{
inputHidden.value = value;
}
div.appendChild(inputHidden);
var input = document.createElement("INPUT");
input.type = "text";
div.appendChild(input);
var ul = document.createElement("UL");
ul.className = "mcx-selected-items";
div.appendChild(ul);
var divSearchResults = document.createElement("DIV");
divSearchResults.className = "uwt-popup mcx-search-results";
var ulSearchResults = document.createElement("UL");
ulSearchResults.className = "uwt-menu uwt-multiselect uwt-highlight";
divSearchResults.appendChild(ulSearchResults);
var divSpinner = document.createElement("DIV");
divSpinner.className = "uwt-spinner";
divSearchResults.appendChild(divSpinner);
var divPlaceholder = document.createElement("DIV");
divPlaceholder.className = "uwt-placeholder";
divPlaceholder.innerText = "type to search the list";
divSearchResults.appendChild(divPlaceholder);
div.appendChild(divSearchResults);
new McxInstanceBrowser(div);
return div;
};
window.addEventListener("load", function()
{
var items = document.getElementsByClassName("mcx-instancebrowser");
for (var i = 0; i < items.length; i++)
{
items[i].NativeObject = new McxInstanceBrowser(items[i]);
}
});
window.addEventListener("click", function(e)
{
var ibs = document.getElementsByClassName("mcx-instancebrowser");
for (var i = 0; i < ibs.length; i++)
{
if (!System.CheckIfSenderIsInside(e.target, ibs[i]))
{
ibs[i].NativeObject.setEditing(false);
}
}
});

View File

@ -0,0 +1,22 @@
function InstanceKey()
{
this.ClassIndex = 0;
this.InstanceIndex = 0;
this.toString = function()
{
return this.ClassIndex + "$" + this.InstanceIndex;
};
}
InstanceKey.parse = function(value)
{
var split = value.split("$");
var classIndex = parseInt(split[0]);
var instanceIndex = parseInt(split[1]);
var ik = new InstanceKey();
ik.ClassIndex = classIndex;
ik.InstanceIndex = instanceIndex;
return ik;
};

View File

@ -0,0 +1,15 @@
var mochaMessages = {
"MXRES.CONTEXTMENUITEM.ViewPrintableVersion": "View Printable Version",
"MXRES.CONTEXTMENUITEM.ExportToSpreadsheet": "Export to Spreadsheet",
"MXRES.MONIKER.CONTEXTMENUITEM.CopyInstanceID": "Copy Instance ID ({0})",
"MXRES.MONIKER.CONTEXTMENUITEM.CopyText": "Copy Text",
"MXRES.MONIKER.CONTEXTMENUITEM.CopyTextAndInstanceID": "Copy Text and Instance ID",
"MXRES.MONIKER.CONTEXTMENUITEM.CopyURL": "Copy URL",
"MXRES.MONIKER.CONTEXTMENUITEM.EditInNewWindow": "Edit in New Window",
"MXRES.MONIKER.CONTEXTMENUITEM.EditInstance": "Edit Instance",
"MXRES.MONIKER.CONTEXTMENUITEM.SearchInstanceID": "Search Instance ID ({0})",
"MXRES.MONIKER.CONTEXTMENUITEM.SearchInstanceIDInMaster": "Search Instance ID ({0}) in Master",
"MXRES.MONIKER.CONTEXTMENUITEM.SearchInstanceIDInNewWindow": "Search Instance ID ({0}) in New Window",
"MXRES.MONIKER.CONTEXTMENUITEM.SeeInNewWindow": "See in New Tab",
"MXRES.MONIKER.CONTEXTMENUITEM.SeeRelatedInstances": "See Related Instances"
};

View File

@ -0,0 +1,412 @@
function McxMoniker(parentElement)
{
this.ParentElement = parentElement;
if (this.ParentElement.children[0].tagName == "IMG")
{
this.IconElement = this.ParentElement.children[0];
this.LabelElement = this.ParentElement.children[1];
this.ButtonElement = this.ParentElement.children[2];
this.PopupElement = this.ParentElement.children[3];
}
else
{
this.IconElement = null;
this.LabelElement = this.ParentElement.children[0];
this.ButtonElement = this.ParentElement.children[1];
this.PopupElement = this.ParentElement.children[2];
}
this.ParentElement.addEventListener("contextmenu", function(e)
{
var cm = new ContextMenu();
cm.Data = this.McxNativeObject;
var ecid = this.NativeObject.ECID;
var iid = this.McxNativeObject.ParentElement.getAttribute("data-instance-id");
cm.Items = [
{
"ClassName": "MenuItemCommand",
"Title": mochaMessages["MXRES.MONIKER.CONTEXTMENUITEM.SeeInNewWindow"],
"Visible": function()
{
return this.Menu.Data.LabelElement.tagName == "A";
},
"Execute": function()
{
var ik = InstanceKey.parse(iid);
var castClassId = "1$" + ik.ClassIndex;
var relativeUrl = System.ExpandRelativePath("~/" + System.TenantName + "/d/inst/" + castClassId + "/" + iid + ".htmld");
var url = new URL(relativeUrl, document.baseURI).href;
window.open(relativeUrl);
}
},
{
"ClassName": "MenuItemSeparator",
"Visible": function()
{
return this.Menu.Data.LabelElement.tagName == "A";
}
},
{
"ClassName": "MenuItemCommand",
"Title": mochaMessages["MXRES.MONIKER.CONTEXTMENUITEM.CopyURL"],
"Visible": true,
"Execute": function()
{
var ik = InstanceKey.parse(iid);
var castClassId = "1$" + ik.ClassIndex;
var relativeUrl = System.ExpandRelativePath("~/" + System.TenantName + "/d/inst/" + castClassId + "/" + iid + ".htmld");
var url = new URL(relativeUrl, document.baseURI).href;
Clipboard.setText(url);
}
},
{
"ClassName": "MenuItemCommand",
"Title": mochaMessages["MXRES.MONIKER.CONTEXTMENUITEM.CopyText"],
"Visible": true,
"Execute": function()
{
Clipboard.setText(this.Menu.Data.LabelElement.innerText);
}
},
{
"ClassName": "MenuItemSeparator",
"Visible": true
},
{
"ClassName": "MenuItemCommand",
"Title": String.format(mochaMessages["MXRES.MONIKER.CONTEXTMENUITEM.CopyInstanceID"], iid),
"Visible": true,
"Execute": function()
{
Clipboard.setText(iid);
}
},
{
"ClassName": "MenuItemCommand",
"Title": mochaMessages["MXRES.MONIKER.CONTEXTMENUITEM.CopyTextAndInstanceID"],
"Visible": true,
"Execute": function()
{
Clipboard.setText(this.Menu.Data.LabelElement.innerText);
}
},
{
"ClassName": "MenuItemSeparator",
"Visible": true
},
{
"ClassName": "MenuItemCommand",
"Title": mochaMessages["MXRES.MONIKER.CONTEXTMENUITEM.EditInstance"],
"Visible": true,
"TargetURL": function()
{
var ik = InstanceKey.parse(iid);
var castClassId = "1$" + ik.ClassIndex;
var relativeUrl = System.ExpandRelativePath("~/" + System.TenantName + "/d/inst/" + castClassId + "/" + iid + ".htmld");
var url = new URL(relativeUrl, document.baseURI).href;
return url;
}
},
{
"ClassName": "MenuItemCommand",
"Title": String.format(mochaMessages["MXRES.MONIKER.CONTEXTMENUITEM.SearchInstanceID"], iid),
"Visible": true,
"TargetURL": function()
{
return System.ExpandRelativePath("~/" + System.TenantName + "/d/search.htmld?q=" + iid + "&branch=true");
}
},
{
"ClassName": "MenuItemSeparator",
"Visible": true
},
{
"ClassName": "MenuItemCommand",
"Title": mochaMessages["MXRES.CONTEXTMENUITEM.ViewPrintableVersion"],
"Visible": true,
"Execute": function()
{
Window.ShowDialog("The method or operation is not implemented", "Not Implemented");
}
},
{
"ClassName": "MenuItemCommand",
"Title": mochaMessages["MXRES.CONTEXTMENUITEM.ExportToSpreadsheet"],
"Visible": true,
"Execute": function()
{
Window.ShowDialog("The method or operation is not implemented", "Not Implemented");
}
}
];
cm.Show(e.clientX, e.clientY, document.body);
e.preventDefault();
e.stopPropagation();
return false;
});
this.ActionsMenuElement = this.PopupElement.children[0].children[1];
this.ClassTitleElement = this.PopupElement.children[1].children[0].children[0].children[0];
this.InstanceTitleElement = this.PopupElement.children[1].children[0].children[0].children[1];
this.PreviewContentElement = this.PopupElement.children[1].children[1];
this.InstanceID = this.ParentElement.getAttribute("data-instance-id");
this.setInstanceTitle = function(value)
{
this.InstanceTitleElement.innerText = value;
};
this.setClassTitle = function(value)
{
this.ClassTitleElement.innerText = value;
};
this.BuildMenuItem = function(title, url)
{
};
this.ButtonElement.McxNativeObject = this;
this.OnOpening = function()
{
System.ClassList.Add(this.PopupElement, "uwt-loading");
var url = System.ExpandRelativePath("~/" + System.TenantName + "/inst/" + this.InstanceID + "/rel-tasks.htmld");
var xhr = new XMLHttpRequest();
xhr.timeout = 5000;
xhr.open("GET", url);
xhr.thiss = this;
xhr.onreadystatechange = function(e)
{
var xhr = e.target;
if (xhr.readyState == 4)
{
if (xhr.status == 200)
{
var json = JSON.parse(xhr.responseText);
console.log(json);
if (json.result == "failure" && json.responseCode == 403)
{
Alert.show(json.message, json.title, "uwt-color-danger");
return;
}
if (json.instance)
{
if (json.instance.label)
{
// xhr.thiss.setClassTitle("Return Attribute Method Binding");
xhr.thiss.setClassTitle(json.instance.label);
}
if (json.instance.title)
{
// xhr.thiss.setInstanceTitle("Common Text@get Concatenated Date and Time Format (BA)*P*S(public)[ramb]");
xhr.thiss.setInstanceTitle(json.instance.title);
}
}
if (json.taskGroups)
{
System.ClassList.Remove(xhr.thiss.ActionsMenuElement.parentElement, "uwt-empty");
xhr.thiss.ActionsMenuElement.innerHTML = "";
for (var i = 0; i < json.taskGroups.length; i++)
{
var tgprimary = json.taskGroups[i].taskGroups[0];
if (tgprimary.taskGroups.length === 0)
continue;
var label = tgprimary.label;
var li = document.createElement("li");
li.className = "uwt-menu-item-command uwt-menu-item-popup uwt-visible";
var a = document.createElement("a");
a.href = "#";
var span = document.createElement("span");
span.className = "uwt-title";
span.innerText = label;
a.appendChild(span);
li.appendChild(a);
var ulMenuChild = document.createElement("ul");
ulMenuChild.className = "uwt-menu uwt-popup";
for (var j = 0; j < tgprimary.taskGroups.length; j++)
{
var tgsecondary = tgprimary.taskGroups[j].tasks[0];
var li2 = document.createElement("li");
li2.className = "uwt-menu-item-command uwt-visible";
var a2 = document.createElement("a");
a2.href = tgsecondary.uri;
var span2 = document.createElement("span");
span2.className = "uwt-title";
span2.innerText = tgsecondary.label;
a2.appendChild(span2);
li2.appendChild(a2);
ulMenuChild.appendChild(li2);
}
li.appendChild(ulMenuChild);
xhr.thiss.ActionsMenuElement.appendChild(li);
}
}
if (json.messages)
{
for (var i = 0; i < json.messages.length; i++)
{
Alert.show(json.messages[i].content, json.messages[i].title, "uwt-color-danger");
}
}
if (json.preview)
{
xhr.thiss.PreviewContentElement.innerHTML = json.preview;
}
System.ClassList.Remove(xhr.thiss.PopupElement, "uwt-loading");
xhr.thiss.ParentElement.NativeObject.UpdatePopupLocation();
}
else if (xhr.status == 403)
{
}
else if (xhr.status == 0)
{
Alert.show("Please check your connection and try again", "Connection lost", "uwt-color-danger", 5000);
}
}
};
xhr.send(null);
};
}
McxMoniker.create = function(instanceKey, title, viewTask)
{
var div = document.createElement("div");
div.setAttribute("data-instance-id", instanceKey);
div.className = "mcx-moniker uwt-actionpreviewbutton apb-show-text apb-style-ellipsis";
var img = document.createElement("img");
img.className = "apb-icon";
img.addEventListener("error", function()
{
this.style.display="none";
});
img.src = "/madi/asset/uic-assets/1.1.5/zq/icons/1$" + instanceKey.split("$")[0];
img.setAttribute("alt", "");
div.appendChild(img);
var a = document.createElement("a");
if (viewTask != null)
{
a.className = "apb-text";
a.href = System.ExpandRelativePath("~/" + System.TenantName + "/d/inst/" + instanceKey + ".htmld");
}
else
{
a.className = "apb-text apb-empty";
}
if (title == "")
{
a.innerHTML = "&nbsp;";
}
else
{
a.innerText = title;
}
div.appendChild(a);
a = document.createElement("a");
a.className = "apb-button";
a.href = System.ExpandRelativePath("~/" + System.TenantName + "/d/inst/" + instanceKey + "/rel-tasks.htmld");
a.innerHTML = "&nbsp;";
div.appendChild(a);
var apbPreview = document.createElement("div");
apbPreview.className = "apb-preview uwt-popup";
var apbActions = document.createElement("div");
apbActions.className = "apb-actions uwt-empty";
var h2 = document.createElement("h2");
h2.innerText = "Available Actions";
apbActions.appendChild(h2);
var ul = document.createElement("ul");
ul.className = "uwt-menu";
apbActions.appendChild(ul);
apbPreview.appendChild(apbActions);
var apbPreviewContent = document.createElement("div");
apbPreviewContent.className = "apb-preview-content";
var apbHeader = document.createElement("div");
apbHeader.className = "apb-header";
var h2 = document.createElement("h2");
var spanClassTitle = document.createElement("span");
spanClassTitle.className = "apb-class-title";
spanClassTitle.innerText = "Relationship";
h2.appendChild(spanClassTitle);
var img = document.createElement("img");
img.className = "apb-icon";
img.src = "/madi/asset/uic-assets/1.1.5/zq/icons/1$" + instanceKey.split("$")[0];
img.setAttribute("alt", "");
h2.appendChild(img);
var text = document.createElement("a");
text.className = "apb-text apb-empty";
text.href= "";
text.innerText = title;
h2.appendChild(text);
apbHeader.appendChild(h2);
apbPreviewContent.appendChild(apbHeader);
apbPreview.appendChild(apbPreviewContent);
var apbSpinner = document.createElement("div");
apbSpinner.className = "uwt-spinner";
apbPreview.appendChild(apbSpinner);
div.appendChild(apbPreview);
//</div><div class="apb-preview-content"><div class="apb-header"><h2><span class="apb-class-title">Work Set</span><img class="apb-icon" src="/madi/asset/uic-assets/1.1.5/zq/icons/1$15.png"><a class="apb-text" href="/super/d/inst/1$15/15$12.htmld">Conditional Select Attribute Case [Nonsingular]</a></h2></div><div class="apb-content"></div></div><div class="uwt-spinner">&nbsp;</div></div></div>"
div.NativeObject = new AdditionalDetailWidget(div);
div.McxNativeObject = new McxMoniker(div);
div.NativeObject.OnOpening = function()
{
this.Parent.McxNativeObject.OnOpening();
};
return div;
};
window.addEventListener("load", function()
{
var items = document.getElementsByClassName("mcx-moniker");
for (var i = 0; i < items.length; i++)
{
items[i].McxNativeObject = new McxMoniker(items[i]);
items[i].NativeObject.OnOpening = function()
{
this.Parent.McxNativeObject.OnOpening();
};
}
});

View File

@ -0,0 +1,110 @@
function McxTypeaheadSearch(parentElement)
{
this.ParentElement = parentElement;
this.FormElement = this.ParentElement.children[0];
this.TextBoxElement = this.FormElement.children[0];
this.PopupElement = this.ParentElement.children[1];
this.MenuElement = this.PopupElement.children[0];
this.clearSearchResults = function()
{
while (this.MenuElement.children.length > 0)
{
this.MenuElement.children[0].remove();
}
};
this.activateSearchResult = function(searchResult)
{
window.location.href = searchResult.uri;
};
this.search = function(query)
{
System.ClassList.Add(this.PopupElement, "uwt-visible");
System.ClassList.Add(this.PopupElement, "uwt-loading");
var xhr = new XMLHttpRequest();
var searchUrl = System.ExpandRelativePath("~/" + System.TenantName + "/search.htmld?q=" + encodeURIComponent(query));
// var searchUrl = System.ExpandRelativePath("~/madi/pex/fs/" + System.TenantName + "typeahead?q=" + encodeURIComponent(query) + "&contextualsearch=true&autocomplete=true&clientRequestId=");
/*
if (this.ParentElement.hasAttribute("data-valid-class-ids"))
{
searchUrl += "&validClassIds=" + this.ParentElement.getAttribute("data-valid-class-ids");
}
*/
xhr.open("GET", searchUrl, true);
xhr.NativeObject = this;
xhr.onreadystatechange = function()
{
if (this.readyState === 4)
{
var resultsText = this.responseText;
var json = JSON.parse(resultsText);
System.ClassList.Remove(this.NativeObject.PopupElement, "uwt-loading");
if (json.result === "success")
{
this.NativeObject.clearSearchResults();
for (var i = 0; i < json.items.length; i++)
{
var li = document.createElement("li");
li.className = "uwt-menu-item uwt-menu-item-command uwt-visible";
li.searchResult = json.items[i];
li.NativeObject = this.NativeObject;
li.addEventListener("click", function()
{
if (this.NativeObject.activateSearchResult(this.searchResult))
{
this.NativeObject.setEditing(false);
}
});
var span = document.createElement("span");
span.className = "uwt-title";
span.innerText = json.items[i].label;
li.appendChild(span);
span = document.createElement("span");
span.className = "uwt-description";
span.innerText = json.items[i].summaryDescription;
li.appendChild(span);
this.NativeObject.MenuElement.appendChild(li);
}
System.ClassList.Remove(this.NativeObject.PopupElement, "uwt-loading");
}
else
{
if (json.responseCode === 403)
{
Alert.show("Please log in to continue", "Not Authorized", "uwt-color-danger");
}
System.ClassList.Remove(this.NativeObject.PopupElement, "uwt-loading");
}
}
};
xhr.send(null);
};
this.__timeout = null;
this.TextBoxElement.NativeObject = this;
this.TextBoxElement.addEventListener("keyup", function(e)
{
if (this.NativeObject.__timeout !== null)
{
window.clearTimeout(this.NativeObject.__timeout);
}
this.NativeObject.__timeout = window.setTimeout(function(thiss)
{
thiss.search(thiss.TextBoxElement.value);
}, 500, this.NativeObject);
});
}
window.addEventListener("load", function()
{
var primarySearch = document.getElementsByClassName("uwt-searchbar");
primarySearch[0].NativeObject = new McxTypeaheadSearch(primarySearch[0]);
});

View File

@ -0,0 +1,55 @@
<?php
if (file_exists(dirname(__FILE__) . "/phast/JSMin.inc.php"))
{
include_once(dirname(__FILE__) . "/phast/JSMin.inc.php");
}
$last_modified_time = filemtime(__FILE__);
$etag = md5_file(__FILE__);
// always send headers
header("Last-Modified: ".gmdate("D, d M Y H:i:s", $last_modified_time)." GMT");
header("Etag: $etag");
// exit if not modified
if (@strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) == $last_modified_time ||
@trim($_SERVER['HTTP_IF_NONE_MATCH']) == $etag)
{
header("HTTP/1.1 304 Not Modified");
exit;
}
header ("Content-Type: text/javascript");
$bundles = array();
$files = glob("*.js");
foreach ($files as $file)
{
$bundles[] = $file;
}
$input = "";
foreach ($bundles as $bundle)
{
$input .= "/* BEGIN '" . $bundle . "' */\r\n";
$input .= file_get_contents($bundle) . "\r\n";
$input .= "/* END '" . $bundle . "' */\r\n\r\n";
}
if (isset($_GET["minify"]) && $_GET["minify"] == "false")
{
echo($input);
}
else
{
if (class_exists("\\JSMin\\JSMin"))
{
$output = \JSMin\JSMin::minify($input);
}
else
{
$output = "/* could not find class '\\JSMin\\JSMin'; minify is unavailable */\r\n";
$output .= $input;
}
echo($output);
}
?>

View File

@ -0,0 +1 @@
../../../../phast/lib/phast/client/scripts

View File

@ -0,0 +1,26 @@
function dataDirMsgHelper_OnClick(e)
{
Window.ShowDialog(
"<ol>" +
"<li>Clone the <a target=\"_blank\" href=\"https://gitea.azcona-becker.net/mochapowered/mocha-common\">mochapowered/mocha-common</a> repository.</li>" +
"<li>Copy mocha-common/data to the folder in which setup.php from mocha-php is located.</li>" +
"<li>Refresh this page to see if the folder is recognized.</li>" +
"</ol>",
"Installing the data folder"
);
e.preventDefault();
e.stopPropagation();
return false;
}
window.addEventListener("load", function () {
var dataDirMsgHelper = document.getElementById("dataDirMsgHelper");
if (dataDirMsgHelper)
{
dataDirMsgHelper.addEventListener("click", dataDirMsgHelper_OnClick);
}
});

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long