diff --git a/lib/phast/client/scripts/System.js b/lib/phast/client/scripts/System.js index b5671fe..597d95e 100644 --- a/lib/phast/client/scripts/System.js +++ b/lib/phast/client/scripts/System.js @@ -1,3 +1,32 @@ +function Clipboard() +{ +} +Clipboard.setText = function(value) +{ + if ('clipboard' in navigator) + { + navigator.clipboard.writeText(value).then(() => + { + }).catch((err) => console.error(err.name, err.message)); + } + else + { + const textArea = document.createElement('textarea'); + textArea.value = value; + textArea.style.opacity = 0; + document.body.appendChild(textArea); + textArea.focus(); + textArea.select(); + try { + const success = document.execCommand('copy'); + //console.log(`Text copy was ${success ? 'successful' : 'unsuccessful'}.`); + } catch (err) { + console.error(err.name, err.message); + } + document.body.removeChild(textArea); + } +}; + function StringPadDirection(value) { this._value = value; @@ -767,4 +796,17 @@ if (typeof XMLHttpRequest === "undefined") catch (e) {} console.log("This browser does not support XMLHttpRequest."); }; +} + +if (!String.format) +{ + String.format = function() { + var args = arguments; + return args[0].replace(/{(\d+)}/g, function(match, number) { + return typeof args[parseInt(number) + 1] != 'undefined' + ? args[parseInt(number) + 1] + : match + ; + }); + }; } \ No newline at end of file diff --git a/lib/phast/client/scripts/controls/Alert.js b/lib/phast/client/scripts/controls/Alert.js index f1784b9..1cc67c7 100644 --- a/lib/phast/client/scripts/controls/Alert.js +++ b/lib/phast/client/scripts/controls/Alert.js @@ -1,3 +1,134 @@ +function Alert(parentElement) +{ + this.mvarTitle = ""; + this.setTitle = function(value) + { + this.mvarTitle = value; + }; + this.getTitle = function() + { + return this.mvarTitle; + } + + this.mvarContent = ""; + this.setContent = function(value) + { + this.mvarContent = value; + }; + this.getContent = function() + { + return this.mvarContent; + }; + + this.mvarCssClass = ""; + this.setCssClass = function(value) + { + this.mvarCssClass = value; + }; + this.getCssClass = function() + { + return this.mvarCssClass; + }; + + this.mvarTimeout = -1; + this.setTimeout = function(value) + { + this.mvarTimeout = value; + } + this.getTimeout = function() + { + return this.mvarTimeout; + }; + + this.mvarParentElement = null; + this.show = function(timeoutInMilliseconds) + { + var element = document.createElement("div"); + var cssClass = "uwt-alert"; + if (this.getCssClass() != "") cssClass += " " + this.getCssClass(); + element.className = cssClass; + element.ObjectReference = this; + + element.addEventListener("click", function(e) + { + this.ObjectReference.Hide(); + }); + + this.mvarParentElement = element; + + var elemTitle = document.createElement("div"); + elemTitle.className = "uwt-title"; + elemTitle.innerHTML = this.getTitle(); + element.appendChild(elemTitle); + + var elemContent = document.createElement("div"); + elemContent.className = "uwt-content"; + elemContent.innerHTML = this.getContent(); + element.appendChild(elemContent); + + + if (Alert.AlertContainer === null) + { + Alert.AlertContainer = document.createElement("div"); + Alert.AlertContainer.className = "uwt-alert-container"; + document.body.appendChild(Alert.AlertContainer); + } + Alert.AlertContainer.appendChild(element); + cssClass += " uwt-visible"; + + // timeout required to see the transition when first adding the element to the page + window.setTimeout(function() + { + element.className = cssClass; + }, 50); + + if (typeof(timeoutInMilliseconds) != "undefined") + { + window.setTimeout(function(sender) + { + sender.Hide(); + }, timeoutInMilliseconds, this); + } + }; + this.hide = function() + { + var cssClass = "uwt-alert"; + if (this.getCssClass() != "") cssClass += " " + this.getCssClass(); + this.mvarParentElement.className = cssClass; + }; +} + +Alert.AlertContainer = null; + +Alert.show = function(content, title, cssClass, timeoutInMilliseconds) +{ + var n = new Alert(); + + if (typeof(content) === "undefined") + { + console.warn("showing notification with empty content"); + content = ""; + } + n.setContent(content); + + if (typeof(title) === "undefined") + { + console.warn("showing notification with empty title"); + title = ""; + } + n.setTitle(title); + + if (typeof(cssClass) === "undefined") cssClass = ""; + n.setCssClass(cssClass); + + if (typeof(timeoutInMilliseconds) !== "undefined") + { + n.setTimeout(timeoutInMilliseconds); + } + + n.show(); +}; + window.addEventListener("load", function() { diff --git a/lib/phast/client/scripts/controls/ListView.js b/lib/phast/client/scripts/controls/ListView.js index 7778371..9605aa3 100644 --- a/lib/phast/client/scripts/controls/ListView.js +++ b/lib/phast/client/scripts/controls/ListView.js @@ -520,6 +520,7 @@ window.addEventListener("load", function(e) ListView.create = function(container, createParms) { + /* var table = document.createElement("table"); table.className = "uwt-listview"; @@ -568,6 +569,74 @@ ListView.create = function(container, createParms) table.appendChild(tbody); } container.appendChild(table); + */ + + var table = document.createElement("div"); + table.className = "uwt-listview"; + + var caption = document.createElement("div"); + caption.className = "uwt-listview-caption"; + + table.appendChild(caption); + + var content = document.createElement("div"); + content.className = "uwt-content"; + + var columnHeaders = document.createElement("div"); + columnHeaders.className = "uwt-listview-column-headers"; + + if (createParms.columns) + { + for (var i = 0; i < createParms.columns.length; i++) + { + var td = document.createElement("div"); + td.className = "uwt-listview-column-header"; + + var a = document.createElement("a"); + a.href = "#"; + a.innerHTML = createParms.columns[i].title; + td.appendChild(a); + // createParms.columns[i].id; + columnHeaders.appendChild(td); + } + } + content.appendChild(columnHeaders); + + var columnItems = document.createElement("div"); + columnItems.className = "uwt-listview-items"; + + if (createParms.items) + { + for (var i = 0; i < createParms.items.length; i++) + { + var tr = document.createElement("div"); + tr.className = "uwt-listview-item"; + + for (var j = 0; j < createParms.items[i].columns.length; j++) + { + var td = document.createElement("div"); + td.className = "uwt-listview-item-column"; + + var value = createParms.items[i].columns[j].value; + if (typeof(value) === "function") + { + value = value(); + } + else + { + td.innerHTML = value; + } + + tr.appendChild(td); + } + + // createParms.columns[i].id; + columnItems.appendChild(tr); + } + } + content.appendChild(columnItems); + + table.appendChild(content); var listview = new ListView(table); return listview; diff --git a/lib/phast/client/scripts/controls/Menu.js b/lib/phast/client/scripts/controls/Menu.js index a1d3edc..f654c15 100644 --- a/lib/phast/client/scripts/controls/Menu.js +++ b/lib/phast/client/scripts/controls/Menu.js @@ -69,40 +69,73 @@ function ContextMenu() for (var i = 0; i < this.Items.length; i++) { + this.Items[i].Menu = this; + var li = document.createElement("li"); System.ClassList.Add(li, "uwt-menu-item"); - if (this.Items[i].Visible) + + var visible = false; + if (typeof(this.Items[i].Visible) === "function") + { + visible = this.Items[i].Visible(); + } + else if (typeof(this.Items[i].Visible) === "undefined") + { + visible = false; + } + else + { + visible = this.Items[i].Visible; + } + + if (visible) { System.ClassList.Add(li, "uwt-visible"); } + else + { + System.ClassList.Remove(li, "uwt-visible"); + } if (this.Items[i].ClassName == "MenuItemCommand") { var elem1 = document.createElement("a"); - elem1.setAttribute("href", "#"); - elem1.addEventListener("click", function(e) + if (this.Items[i].TargetURL) { - this.NativeObject.Hide(); - this.MenuItem.Execute(); - - e.preventDefault(); - e.stopPropagation(); - return false; - }); + var targetUrl = this.Items[i].TargetURL; + if (typeof(targetUrl) === 'function') + { + targetUrl = targetUrl(); + } + elem1.setAttribute("href", targetUrl); + } + else + { + elem1.setAttribute("href", "#"); + elem1.addEventListener("click", function(e) + { + this.NativeObject.Hide(); + this.MenuItem.Execute(); + + e.preventDefault(); + e.stopPropagation(); + return false; + }); + } elem1.innerHTML = this.Items[i].Title; elem1.NativeObject = this; elem1.MenuItem = this.Items[i]; li.appendChild(elem1); - System.ClassList.Add(li, "Command"); + System.ClassList.Add(li, "uwt-menu-item-command"); } else if (this.Items[i].ClassName == "MenuItemSeparator") { - System.ClassList.Add(li, "Separator"); + System.ClassList.Add(li, "uwt-separator"); } else if (this.Items[i].ClassName == "MenuItemHeader") { - System.ClassList.Add(li, "Header"); + System.ClassList.Add(li, "uwt-menu-item-header"); li.innerHTML = this.Items[i].Title; } elem.appendChild(li); diff --git a/lib/phast/client/scripts/controls/Notification.js b/lib/phast/client/scripts/controls/Notification.js deleted file mode 100644 index 5054dcf..0000000 --- a/lib/phast/client/scripts/controls/Notification.js +++ /dev/null @@ -1,121 +0,0 @@ -function Notification(parentElement) -{ - this.mvarTitle = ""; - this.SetTitle = function(value) - { - this.mvarTitle = value; - }; - this.GetTitle = function() - { - return this.mvarTitle; - } - - this.mvarContent = ""; - this.SetContent = function(value) - { - this.mvarContent = value; - }; - this.GetContent = function() - { - return this.mvarContent; - }; - - this.mvarCssClass = ""; - this.SetCssClass = function(value) - { - this.mvarCssClass = value; - }; - this.GetCssClass = function() - { - return this.mvarCssClass; - }; - - this.mvarTimeout = -1; - this.SetTimeout = function(value) - { - this.mvarTimeout = value; - } - this.GetTimeout = function() - { - return this.mvarTimeout; - }; - - this.mvarParentElement = null; - this.Show = function(timeoutInMilliseconds) - { - var element = document.createElement("DIV"); - var cssClass = "Notification"; - if (this.GetCssClass() != "") cssClass += " " + this.GetCssClass(); - element.className = cssClass; - element.ObjectReference = this; - - element.addEventListener("click", function(e) - { - this.ObjectReference.Hide(); - }); - - this.mvarParentElement = element; - - var elemTitle = document.createElement("DIV"); - elemTitle.className = "Title"; - elemTitle.innerHTML = this.GetTitle(); - element.appendChild(elemTitle); - - var elemContent = document.createElement("DIV"); - elemContent.className = "Content"; - elemContent.innerHTML = this.GetContent(); - element.appendChild(elemContent); - - document.body.appendChild(element); - cssClass += " Visible"; - - // timeout required to see the transition when first adding the element to the page - window.setTimeout(function() - { - element.className = cssClass; - }, 50); - - if (typeof(timeoutInMilliseconds) != "undefined") - { - window.setTimeout(function(sender) - { - sender.Hide(); - }, timeoutInMilliseconds, this); - } - }; - this.Hide = function() - { - var cssClass = "Notification"; - if (this.GetCssClass() != "") cssClass += " " + this.GetCssClass(); - this.mvarParentElement.className = cssClass; - }; -} - -Notification.Show = function(content, title, cssClass, timeoutInMilliseconds) -{ - var n = new Notification(); - - if (typeof(content) === "undefined") - { - console.warn("showing notification with empty content"); - content = ""; - } - n.SetContent(content); - - if (typeof(title) === "undefined") - { - console.warn("showing notification with empty title"); - title = ""; - } - n.SetTitle(title); - - if (typeof(cssClass) === "undefined") cssClass = ""; - n.SetCssClass(cssClass); - - if (typeof(timeoutInMilliseconds) !== "undefined") - { - n.SetTimeout(timeoutInMilliseconds); - } - - n.Show(); -}; diff --git a/lib/phast/client/scripts/controls/Window.js b/lib/phast/client/scripts/controls/Window.js index b74adbe..f3b5ae8 100644 --- a/lib/phast/client/scripts/controls/Window.js +++ b/lib/phast/client/scripts/controls/Window.js @@ -7,23 +7,23 @@ function Window(parentElement) if (!parentElement) { parentElement = document.createElement("div"); - parentElement.className = "Window"; + parentElement.className = "uwt-window"; var titleBar = document.createElement("div"); - titleBar.className = "Header"; + titleBar.className = "uwt-header"; var title = document.createElement("span"); - title.className = "Title"; + title.className = "uwt-title"; titleBar.appendChild(title); parentElement.appendChild(titleBar); var content = document.createElement("div"); - content.className = "Content"; + content.className = "uwt-content"; parentElement.appendChild(content); var footer = document.createElement("div"); - footer.className = "Buttons"; + footer.className = "uwt-footer"; footer.NativeObject = this; footer.style.display = "none"; parentElement.appendChild(footer); @@ -308,14 +308,14 @@ function Window(parentElement) if (Window.ModalBackgroundElement == null) { Window.ModalBackgroundElement = document.createElement("div"); - Window.ModalBackgroundElement.className = "WindowModalBackground"; + Window.ModalBackgroundElement.className = "uwt-modal-background"; document.body.appendChild(Window.ModalBackgroundElement); } Window.ModalBackgroundElement.style.display = "block"; Window.ModalBackgroundElement.style.zIndex = (100 + Window.DialogCount); var WindowDOMObject = this.ParentElement; - WindowDOMObject.className = "Window Visible"; + System.ClassList.Add(WindowDOMObject, "uwt-visible"); WindowDOMObject.style.zIndex = (100 + Window.DialogCount + 1); @@ -326,7 +326,7 @@ function Window(parentElement) this.Hide = function() { var WindowDOMObject = this.ParentElement; - WindowDOMObject.className = "Window"; + System.ClassList.Remove(WindowDOMObject, "uwt-visible"); this.Closed.Execute(CallbackArgument.Empty); Window.DialogCount--; @@ -447,7 +447,7 @@ Window.ShowDialog = function (content, title, buttons, styles, iconName, classNa var divWindow = document.createElement("div"); - System.ClassList.Add(divWindow, "Window"); + System.ClassList.Add(divWindow, "uwt-window"); if (className) { System.ClassList.Add(divWindow, className); @@ -459,15 +459,15 @@ Window.ShowDialog = function (content, title, buttons, styles, iconName, classNa } var divHeader = document.createElement("div"); - divHeader.className = "Header"; + divHeader.className = "uwt-header"; var spanHeaderTitle = document.createElement("span"); - spanHeaderTitle.className = "Title"; + spanHeaderTitle.className = "uwt-title"; spanHeaderTitle.innerHTML = title; divHeader.appendChild(spanHeaderTitle); var divHeaderControlBox = document.createElement("div"); - divHeaderControlBox.className = "ControlBox"; + divHeaderControlBox.className = "uwt-controlbox"; var aButtonClose = document.createElement("a"); aButtonClose.className = "Close"; aButtonClose.href = "#"; @@ -482,15 +482,15 @@ Window.ShowDialog = function (content, title, buttons, styles, iconName, classNa divWindow.appendChild(divHeader); var divContent = document.createElement("div"); - divContent.className = "Content"; + divContent.className = "uwt-content"; var divContentContent = document.createElement("div"); - divContentContent.className = "Content"; + divContentContent.className = "uwt-content"; if (iconName && iconName !== null) { var divIcon = document.createElement("div"); - divIcon.className = "Icon"; + divIcon.className = "uwt-icon"; var divStockIcon = document.createElement("div"); divStockIcon.className = "StockIcon si-Large si-" + iconName; @@ -505,32 +505,32 @@ Window.ShowDialog = function (content, title, buttons, styles, iconName, classNa divContent.appendChild(divContentContent); var divLoading = document.createElement("div"); - divLoading.className = "Loading"; + divLoading.className = "uwt-loading"; var divLoadingStatus = document.createElement("div"); - divLoadingStatus.className = "LoadingStatus"; + divLoadingStatus.className = "uwt-loadingStatus"; var divLoadingStatusThrobber = document.createElement("div"); - divLoadingStatusThrobber.className = "Throbber"; + divLoadingStatusThrobber.className = "uwt-throbber"; divLoadingStatusThrobber.innerHTML = " "; divLoadingStatus.appendChild(divLoadingStatusThrobber); var pLoadingStatusText = document.createElement("p"); - pLoadingStatusText.className = "LoadingStatusText"; + pLoadingStatusText.className = "uwt-loadingStatusText"; divLoadingStatus.appendChild(pLoadingStatusText); divLoading.appendChild(divLoadingStatus); - divContent.appendChild(divLoading); + //divContent.appendChild(divLoading); divWindow.appendChild(divContent); var divFooter = document.createElement("div"); - divFooter.className = "Footer"; + divFooter.className = "uwt-footer"; for (var i = 0; i < buttons.length; i++) { var aButton = document.createElement("a"); - aButton.className = "pwt-Button"; + aButton.className = "uwt-button"; if (buttons[i].ClassName) aButton.className += " " + buttons[i].ClassName; if ((typeof (buttons[i].Enabled) !== 'undefined') && !buttons[i].Enabled) { diff --git a/lib/phast/server/Sorting/QuickSort.inc.php b/lib/phast/server/Sorting/QuickSort.inc.php index 4fe99fc..11bcb05 100644 --- a/lib/phast/server/Sorting/QuickSort.inc.php +++ b/lib/phast/server/Sorting/QuickSort.inc.php @@ -4,6 +4,7 @@ namespace Phast; class QuickSort { + /* private function partition(&$arr, $low, $high) { $pivot = $arr[$high]; @@ -25,27 +26,50 @@ class QuickSort { $low = 0; $high = count($arr); - if ($predicate($low, $high)) + if ($predicate($arr[$low], $arr[$high])) { $pi = $this->partition($arr, $low, $high); $this->quickSort($arr, $low, $pi - 1, $predicate); $this->quickSort($arr, $pi + 1, $high, $predicate); } } - - public function Sort(array $array, mixed $predicate) + */ + function partition(&$arr,$leftIndex,$rightIndex, $predicate) { - if (count($array) == 2) - { - if ($predicate($array[0], $array[1])) - { - return [ $array[0], $array[1] ]; - } - else - { - return [ $array[1], $array[0] ]; + $pivot=$arr[($leftIndex+$rightIndex)/2]; + + while ($leftIndex <= $rightIndex) + { + while ($arr[$leftIndex] < $pivot) + $leftIndex++; + while ($arr[$rightIndex] > $pivot) + $rightIndex--; + if ($predicate($arr[$leftIndex], $arr[$rightIndex]) <= 0) { + $tmp = $arr[$leftIndex]; + $arr[$leftIndex] = $arr[$rightIndex]; + $arr[$rightIndex] = $tmp; + $leftIndex++; + $rightIndex--; } } + return $leftIndex; + } + + function quickSort(&$arr, $leftIndex, $rightIndex, $predicate) + { + $index = $this->partition($arr,$leftIndex,$rightIndex, $predicate); + if ($leftIndex < $index - 1) + $this->quickSort($arr, $leftIndex, $index - 1, $predicate); + if ($index < $rightIndex) + $this->quickSort($arr, $index, $rightIndex, $predicate); + } + + + /** + * Usage: QuickSort::Sort(array, function (left, right)) + */ + public function Sort(array $array, mixed $predicate) + { $this->quickSort($array, 0, count($array), $predicate); return $array; } diff --git a/lib/phast/server/System.inc.php b/lib/phast/server/System.inc.php index 2c6a9b9..c640d1c 100644 --- a/lib/phast/server/System.inc.php +++ b/lib/phast/server/System.inc.php @@ -831,10 +831,10 @@ { $leftStr = System::__ReplaceAny($left->FileName, "{", "}" , "?"); $rightStr = System::__ReplaceAny($right->FileName, "{", "}" , "?"); - $val = strlen($leftStr) > strlen($rightStr); + $val = strlen($leftStr) < strlen($rightStr); return $val; }); - $actualPage = $sortedPages[0]; + $actualPage = $actualPages[count($actualPages) - 1]; if ($actualPage->FileName !== null) { $pathVars = System::ParsePathVariables($actualPage->FileName, System::GetVirtualPathString()); diff --git a/lib/phast/server/WebControl.inc.php b/lib/phast/server/WebControl.inc.php index 9c96da6..5c77ffb 100644 --- a/lib/phast/server/WebControl.inc.php +++ b/lib/phast/server/WebControl.inc.php @@ -332,7 +332,7 @@ for ($i = 0; $i < $count; $i++) { $item = $attributes[$i]; - echo($item->Name . "=\"" . $item->Value . "\""); + echo($item->Name . "=\"" . htmlspecialchars($item->Value) . "\""); if ($i < $count - 1) echo(" "); } } @@ -407,7 +407,7 @@ { echo($attr->Name); echo("=\""); - echo($attr->Value); + echo(htmlspecialchars($attr->Value)); echo("\""); if ($i < $count - 1) echo(" "); } diff --git a/lib/phast/server/WebPage.inc.php b/lib/phast/server/WebPage.inc.php index a4b5146..27b4111 100644 --- a/lib/phast/server/WebPage.inc.php +++ b/lib/phast/server/WebPage.inc.php @@ -468,6 +468,7 @@ { $this->BreadcrumbItems = array(); $this->ContentType = "text/html"; + $this->Controls = array(); $this->EnableTenantedHosting = true; $this->Metadata = array(); $this->OpenGraph = new WebOpenGraphSettings(); @@ -516,7 +517,11 @@ if ($this->MasterPage != null) { - if (!$this->MasterPage->Initialize($this)) return false; + if (!$this->MasterPage->Initialize($this)) + { + trigger_error("could not initialize MasterPage [" . $this->MasterPage->PhysicalFileName . "]"); + return false; + } } $initializingEventArgs = new CancelEventArgs(); @@ -527,8 +532,9 @@ if (method_exists($this, "OnInitializing")) { - $this->OnInitializing($initializingEventArgs); - if ($initializingEventArgs->Cancel) return false; + $retval = $this->OnInitializing($initializingEventArgs); + if (!$retval) return false; + if ($initializingEventArgs->Cancel) return true; } $initializingEventArgs->Cancel = false; @@ -536,8 +542,9 @@ { if (method_exists($this->ClassReference, "OnInitializing")) { - $this->ClassReference->OnInitializing($initializingEventArgs); - if ($initializingEventArgs->Cancel) return false; + $retval = $this->ClassReference->OnInitializing($initializingEventArgs); + if (!$retval) return false; + if ($initializingEventArgs->Cancel) return true; } if (method_exists($this->ClassReference, "OnInitialized")) { @@ -555,7 +562,7 @@ protected function OnInitializing(CancelEventArgs $e) { - + return true; } protected function OnInitialized(EventArgs $e) { @@ -867,15 +874,47 @@ } return $ary; } + + protected function OnPreRender(CancelEventArgs $e) + { + } public function Render() { if (!$this->Initialize()) { - trigger_error("Could not initialize the WebPage"); + trigger_error("could not initialize WebPage [" . $this->PhysicalFileName . "]"); return; } + + if ($this->MasterPage != null) + { + $e = new CancelEventArgs(); + $this->MasterPage->OnPreRender($e); + if ($e->Cancel) + return; + + $e = new CancelEventArgs(); + + if (method_exists($this->MasterPage->ClassReference, "OnPreRender")) + { + $retval = $this->MasterPage->ClassReference->OnPreRender($e); + if ($e->Cancel) return; + } + } + + $e = new CancelEventArgs(); + $this->OnPreRender($e); + if ($e->Cancel) + return; + + if (method_exists($this->ClassReference, "OnPreRender")) + { + $retval = $this->ClassReference->OnPreRender($e); + if ($e->Cancel) return; + } + $handled = false; switch (System::$WebPageFormat) @@ -1228,6 +1267,16 @@ $tagBODY->Controls[] = $ctl; } } + + + if (method_exists($this->ClassReference, "RenderContents")) + { + ob_start(); + $this->ClassReference->RenderContents($e); + $tagBODY->Content = ob_get_contents(); + ob_end_clean(); + } + $tagHTML->Controls[] = $tagBODY; $tagHTML->Render(); }