697 lines
19 KiB
PHP
697 lines
19 KiB
PHP
<?php
|
|
namespace Phast;
|
|
|
|
use UniversalEditor\ObjectModels\Markup\MarkupElement;
|
|
use Phast\Parser\ControlLoader;
|
|
|
|
class WebControl
|
|
{
|
|
/**
|
|
* The unique identifier of this WebControl on a WebPage.
|
|
* @var string
|
|
*/
|
|
public $ID;
|
|
/**
|
|
* The unique identifier of this WebControl on the client rendered WebPage.
|
|
* @var string
|
|
*/
|
|
public $ClientID;
|
|
/**
|
|
* Determines how ClientIDs are generated for WebControls.
|
|
* @var WebControlClientIDMode
|
|
*/
|
|
public $ClientIDMode;
|
|
|
|
public $Content;
|
|
|
|
/**
|
|
* True if the WebControl is enabled (does not have the "disabled" attribute set); false if it is disabled.
|
|
* @var boolean
|
|
*/
|
|
public $Enabled;
|
|
|
|
/**
|
|
* True if the WebControl should render its content to the output HTML; false otherwise.
|
|
* @var boolean
|
|
*/
|
|
public $EnableRender;
|
|
|
|
public $ExtraData;
|
|
|
|
public $Controls;
|
|
public $HasContent;
|
|
|
|
public $ParentObject;
|
|
|
|
public $Top;
|
|
public $Left;
|
|
public $Width;
|
|
public $Height;
|
|
|
|
public $MinimumWidth;
|
|
public $MinimumHeight;
|
|
|
|
public $MaximumWidth;
|
|
public $MaximumHeight;
|
|
|
|
public $Visible;
|
|
|
|
/**
|
|
* The horizontal alignment of this WebControl.
|
|
* @var HorizontalAlignment
|
|
*/
|
|
public $HorizontalAlignment;
|
|
/**
|
|
* The vertical alignment of this WebControl.
|
|
* @var VerticalAlignment
|
|
*/
|
|
public $VerticalAlignment;
|
|
|
|
/**
|
|
* The CssClass to assign to this WebControl. CssClass is assigned after all classes defined in ClassList have been assigned.
|
|
* @var string
|
|
* @see WebControl::$ClassList
|
|
*/
|
|
public $CssClass;
|
|
/**
|
|
* Array of CssClasses to assign to this WebControl.
|
|
* @var string[]
|
|
* @see WebControl::$CssClass
|
|
*/
|
|
public $ClassList;
|
|
|
|
public $TagName;
|
|
public $Attributes;
|
|
public $StyleRules;
|
|
|
|
public $ToolTipTitle;
|
|
public $ToolTipText;
|
|
|
|
/**
|
|
* True if child tags should be parsed as control properties; false if they should be parsed as child controls.
|
|
* @var boolean
|
|
*/
|
|
public $ParseChildElements;
|
|
|
|
public $OnClientClick;
|
|
|
|
public function GetAllControls()
|
|
{
|
|
return $this->Controls;
|
|
}
|
|
|
|
/**
|
|
* Retrieves the control with the specified ID in this control's child control collection.
|
|
* @param string $id The ID of the control to search for.
|
|
* @return WebControl|NULL The control with the specified ID, or null if no control with the specified ID was found.
|
|
*/
|
|
public function GetControlByID($id, $recurse = true)
|
|
{
|
|
$ctls = $this->GetAllControls();
|
|
foreach ($ctls as $ctl)
|
|
{
|
|
if ($ctl->ID == $id) return $ctl;
|
|
if ($recurse)
|
|
{
|
|
$ctl1 = $ctl->GetControlByID($id, true);
|
|
if ($ctl1 != null) return $ctl1;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public function FindParentPage()
|
|
{
|
|
$parent = $this->ParentObject;
|
|
while ($parent != null)
|
|
{
|
|
if (get_class($parent) == "Phast\\Parser\\Page" || get_class($parent) == "Phast\\Parser\\MasterPage")
|
|
{
|
|
return $parent;
|
|
}
|
|
$parent = $parent->ParentObject;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Generates a random string of the specified length using the characters specified in the string valid_chars.
|
|
* @param string $valid_chars Set of characters used to build the resulting random string.
|
|
* @param int $length The length of the resulting random string.
|
|
* @return string The random string of the specified length using the specified character set.
|
|
*/
|
|
private static function GenerateRandomString($valid_chars, $length)
|
|
{
|
|
// start with an empty random string
|
|
$random_string = "";
|
|
|
|
// count the number of chars in the valid chars string so we know how many choices we have
|
|
$num_valid_chars = strlen($valid_chars);
|
|
|
|
// repeat the steps until we've created a string of the right length
|
|
for ($i = 0; $i < $length; $i++)
|
|
{
|
|
// pick a random number from 1 up to the number of valid chars
|
|
$random_pick = mt_rand(1, $num_valid_chars);
|
|
|
|
// take the random character out of the string of valid chars
|
|
// subtract 1 from $random_pick because strings are indexed starting at 0, and we started picking at 1
|
|
$random_char = $valid_chars[$random_pick-1];
|
|
|
|
// add the randomly-chosen char onto the end of our string so far
|
|
$random_string .= $random_char;
|
|
}
|
|
|
|
// return our finished random string
|
|
return $random_string;
|
|
}
|
|
|
|
public function __construct()
|
|
{
|
|
$this->Enabled = true;
|
|
$this->Visible = true;
|
|
$this->HorizontalAlignment = HorizontalAlignment::Inherit;
|
|
$this->VerticalAlignment = VerticalAlignment::Inherit;
|
|
|
|
$this->Controls = array();
|
|
$this->EnableRender = true;
|
|
|
|
$this->HasContent = true;
|
|
|
|
$this->TagName = null;
|
|
$this->ClassList = array();
|
|
$this->Attributes = array();
|
|
$this->StyleRules = array();
|
|
|
|
$this->ParseChildElements = false;
|
|
|
|
$this->ClientIDMode = WebControlClientIDMode::None;
|
|
}
|
|
|
|
/**
|
|
* Retrieves a ClientProperty associated with this control via a browser cookie.
|
|
* @param string $name The name of the property to retrieve.
|
|
* @param string $defaultValue The value to retrieve if the ClientProperty has not been set.
|
|
* @return string The value of the property with the given name, or defaultValue if the property has not been set.
|
|
*/
|
|
public function GetClientProperty($name, $defaultValue = null)
|
|
{
|
|
if (!isset($_COOKIE[$this->ID . "__ClientProperty_" . $name])) return $defaultValue;
|
|
return $_COOKIE[$this->ID . "__ClientProperty_" . $name];
|
|
}
|
|
/**
|
|
* Updates a ClientProperty associated with this control via a browser cookie.
|
|
* @param string $name The name of the property to update.
|
|
* @param string $value The value with which to update the property.
|
|
* @param string $expires Expiration data for the cookie associated with the ClientProperty.
|
|
*/
|
|
public function SetClientProperty($name, $value, $expires = null)
|
|
{
|
|
setcookie($this->ID . "__ClientProperty_" . $name, $value, $expires);
|
|
}
|
|
|
|
private $Initialized;
|
|
|
|
/**
|
|
* Initializes this control, calling the OnInitialize() function and initializing any child
|
|
* controls.
|
|
*/
|
|
public function Initialize()
|
|
{
|
|
$id = null;
|
|
$clientid = null;
|
|
|
|
if ($this->ClientIDMode == WebControlClientIDMode::Automatic && $this->ID == null)
|
|
{
|
|
$parent = $this->ParentObject;
|
|
$clientid = "";
|
|
|
|
while ($parent != null)
|
|
{
|
|
$clientid = $parent->ID . "_" . $clientid;
|
|
$parent = $parent->ParentObject;
|
|
}
|
|
|
|
$id = "WFX" . WebControl::GenerateRandomString("ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890", 10);
|
|
$clientid .= $id;
|
|
}
|
|
if ($id != null) $this->ID = $id;
|
|
if ($clientid != null) $this->ClientID = $clientid;
|
|
|
|
if ($this->OnClientClick != null)
|
|
{
|
|
$this->Attributes[] = new WebControlAttribute("onclick", $this->OnClientClick);
|
|
}
|
|
|
|
$this->OnInitialize();
|
|
if (is_array($this->Controls))
|
|
{
|
|
foreach ($this->Controls as $control)
|
|
{
|
|
$control->ParentObject = $this;
|
|
if (method_exists($control, "Initialize"))
|
|
{
|
|
$control->Initialize();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
trigger_error("Controls is not array in " . get_class($this) . " ; did you forget to call parent::__construct() ?");
|
|
}
|
|
$this->Initialized = true;
|
|
}
|
|
|
|
protected function OnInitialize()
|
|
{
|
|
|
|
}
|
|
|
|
protected function BeforeContent()
|
|
{
|
|
|
|
}
|
|
protected function RenderContent()
|
|
{
|
|
|
|
}
|
|
protected function AfterContent()
|
|
{
|
|
|
|
}
|
|
|
|
/**
|
|
* Renders an HTML beginning tag with the specified parameters.
|
|
* @param string $tagName The name of the tag to open.
|
|
* @param array $namedParameters Associative array that specifies ClassNames, Attributes, and StyleRules to render with the beginning tag.
|
|
*/
|
|
public static function BeginTag($tagName, $namedParameters)
|
|
{
|
|
echo("<" . $tagName);
|
|
|
|
if (is_array($namedParameters))
|
|
{
|
|
if (isset($namedParameters["ClassNames"])) $classNames = $namedParameters["ClassNames"];
|
|
if (isset($namedParameters["Attributes"])) $attributes = $namedParameters["Attributes"];
|
|
if (isset($namedParameters["StyleRules"])) $styleRules = $namedParameters["StyleRules"];
|
|
}
|
|
|
|
if (!isset($classNames) || !is_array($classNames)) $classNames = array();
|
|
if (!isset($attributes) ||!is_array($attributes)) $attributes = array();
|
|
if (!isset($styleRules) ||!is_array($styleRules)) $styleRules = array();
|
|
|
|
$count = count($classNames);
|
|
if ($count > 0)
|
|
{
|
|
echo(" class=\"");
|
|
for ($i = 0; $i < $count; $i++)
|
|
{
|
|
echo($classNames[$i]);
|
|
if ($i < $count - 1) echo(" ");
|
|
}
|
|
echo("\"");
|
|
}
|
|
|
|
$count = count($styleRules);
|
|
if ($count > 0)
|
|
{
|
|
echo(" style=\"");
|
|
for ($i = 0; $i < $count; $i++)
|
|
{
|
|
$item = $styleRules[$i];
|
|
echo($item->Name . ": " . $item->Value);
|
|
if ($i < $count - 1) echo("; ");
|
|
}
|
|
echo("\"");
|
|
}
|
|
|
|
$count = count($attributes);
|
|
if ($count > 0)
|
|
{
|
|
echo(" ");
|
|
for ($i = 0; $i < $count; $i++)
|
|
{
|
|
$item = $attributes[$i];
|
|
echo($item->Name . "=\"" . htmlspecialchars($item->Value) . "\"");
|
|
if ($i < $count - 1) echo(" ");
|
|
}
|
|
}
|
|
echo(">");
|
|
}
|
|
/**
|
|
* Renders an HTML ending tag with the given tag name.
|
|
* @param string $tagName The name of the tag to close.
|
|
*/
|
|
public static function EndTag($tagName)
|
|
{
|
|
echo("</" . $tagName . ">");
|
|
}
|
|
|
|
/**
|
|
* Renders the beginning tag of this WebControl, including any attribute, CSS class, or style
|
|
* information specified by the control author or the caller.
|
|
*/
|
|
protected function RenderBeginTag()
|
|
{
|
|
if ($this->TagName != "")
|
|
{
|
|
echo("<" . $this->TagName);
|
|
|
|
$styleAttributeContent = "";
|
|
$classAttributeContent = "";
|
|
|
|
if (is_array($this->Attributes))
|
|
{
|
|
$count = count($this->Attributes);
|
|
if ($count > 0)
|
|
{
|
|
$found = false;
|
|
foreach ($this->Attributes as $attr)
|
|
{
|
|
if (!(strtolower($attr->Name) == "style" || strtolower($attr->Name) == "class" || strtolower($attr->Name) == "disabled"))
|
|
{
|
|
$found = true;
|
|
break;
|
|
}
|
|
}
|
|
if ($found) echo(" ");
|
|
$i = 0;
|
|
foreach ($this->Attributes as $attr)
|
|
{
|
|
if (strtolower($attr->Name) == "style")
|
|
{
|
|
if (!StringMethods::EndsWith($attr->Value, ";"))
|
|
{
|
|
$styleAttributeContent .= $attr->Value . "; ";
|
|
}
|
|
else
|
|
{
|
|
$styleAttributeContent .= $attr->Value;
|
|
}
|
|
}
|
|
else if (strtolower($attr->Name) == "class")
|
|
{
|
|
$classAttributeContent .= $attr->Value;
|
|
}
|
|
else if (strtolower($attr->Name) == "disabled")
|
|
{
|
|
// we normalize the disabled attribute
|
|
$this->Enabled = false;
|
|
echo(" disabled=\"disabled\"");
|
|
}
|
|
else if (strtolower($attr->Name) == "id")
|
|
{
|
|
$this->ID = $attr->Value;
|
|
}
|
|
else
|
|
{
|
|
echo($attr->Name);
|
|
echo("=\"");
|
|
echo(htmlspecialchars($attr->Value));
|
|
echo("\"");
|
|
if ($i < $count - 1) echo(" ");
|
|
}
|
|
$i++;
|
|
}
|
|
}
|
|
}
|
|
|
|
$styleRules = $this->StyleRules;
|
|
if (!$this->Visible)
|
|
{
|
|
$styleRules[] = new WebStyleSheetRule("display", "none");
|
|
}
|
|
if ($this->Width != null)
|
|
{
|
|
$styleRules[] = new WebStyleSheetRule("width", $this->Width);
|
|
}
|
|
if ($this->Height != null)
|
|
{
|
|
$styleRules[] = new WebStyleSheetRule("height", $this->Height);
|
|
}
|
|
if ($this->MinimumWidth != null)
|
|
{
|
|
$styleRules[] = new WebStyleSheetRule("min-width", $this->MinimumWidth);
|
|
}
|
|
if ($this->MinimumHeight != null)
|
|
{
|
|
$styleRules[] = new WebStyleSheetRule("min-height", $this->MinimumHeight);
|
|
}
|
|
if ($this->MaximumWidth != null)
|
|
{
|
|
$styleRules[] = new WebStyleSheetRule("max-width", $this->MaximumWidth);
|
|
}
|
|
if ($this->MaximumHeight != null)
|
|
{
|
|
$styleRules[] = new WebStyleSheetRule("max-height", $this->MaximumHeight);
|
|
}
|
|
|
|
if (count($styleRules) > 0 || $styleAttributeContent != "")
|
|
{
|
|
echo(" style=\"");
|
|
echo($styleAttributeContent);
|
|
$count = count($styleRules);
|
|
$i = 0;
|
|
foreach ($styleRules as $rule)
|
|
{
|
|
echo($rule->Name);
|
|
echo(": ");
|
|
echo($rule->Value);
|
|
echo(";");
|
|
if ($i < $count - 1) echo(" ");
|
|
$i++;
|
|
}
|
|
echo("\"");
|
|
}
|
|
if ($this->CssClass != "")
|
|
{
|
|
if ($classAttributeContent != "") $classAttributeContent .= " ";
|
|
$classAttributeContent .= $this->CssClass;
|
|
}
|
|
if (count($this->ClassList) > 0)
|
|
{
|
|
if ($classAttributeContent != "") $classAttributeContent .= " ";
|
|
$count = count($this->ClassList);
|
|
for ($i = 0; $i < $count; $i++)
|
|
{
|
|
$classAttributeContent .= $this->ClassList[$i];
|
|
if ($i < $count - 1) $classAttributeContent .= " ";
|
|
}
|
|
}
|
|
|
|
if ($classAttributeContent != "")
|
|
{
|
|
echo(" class=\"" . $classAttributeContent . "\"");
|
|
}
|
|
|
|
if ($this->ClientID != null)
|
|
{
|
|
echo(" id=\"" . $this->ClientID . "\"");
|
|
}
|
|
else if ($this->ID != null)
|
|
{
|
|
echo(" id=\"" . $this->ID . "\"");
|
|
}
|
|
|
|
if ($this->ToolTipTitle != null) echo(" data-tooltip-title=\"" . $this->ToolTipTitle . "\"");
|
|
if ($this->ToolTipText != null) echo(" data-tooltip-content=\"" . $this->ToolTipText . "\"");
|
|
|
|
if (!$this->DoesHaveContent()) echo(" /");
|
|
echo(">");
|
|
}
|
|
}
|
|
|
|
private static $tagNamesThatMustHaveContent= array("script", "div", "i");
|
|
private function DoesHaveContent()
|
|
{
|
|
$mustHaveContent = in_array(strtolower($this->TagName), WebControl::$tagNamesThatMustHaveContent);
|
|
return $this->HasContent || $mustHaveContent;
|
|
}
|
|
|
|
/**
|
|
* Renders the ending tag of this WebControl.
|
|
*/
|
|
protected function RenderEndTag()
|
|
{
|
|
if ($this->TagName != "" && $this->DoesHaveContent())
|
|
{
|
|
echo("</" . $this->TagName . ">");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Renders the beginning tag of this WebControl, followed by any leading content specified by
|
|
* the control author.
|
|
*/
|
|
public function BeginContent()
|
|
{
|
|
if ($this->EnableRender !== true) return;
|
|
|
|
$this->RenderBeginTag();
|
|
$this->BeforeContent();
|
|
}
|
|
/**
|
|
* Renders any trailing content specified by the control author before the ending tag of this
|
|
* WebControl, followed by the ending tag itself.
|
|
*/
|
|
public function EndContent()
|
|
{
|
|
if ($this->EnableRender !== true) return;
|
|
|
|
$this->AfterContent();
|
|
$this->RenderEndTag();
|
|
}
|
|
|
|
/**
|
|
* Creates the child controls for this WebControl.
|
|
*/
|
|
protected function CreateControl()
|
|
{
|
|
}
|
|
|
|
/**
|
|
* Renders this WebControl and any child controls.
|
|
*/
|
|
public function Render()
|
|
{
|
|
//echo("checking EnableRender");
|
|
if ($this->EnableRender !== true) return;
|
|
|
|
//echo("initializing if not initialized");
|
|
if (!$this->Initialized) $this->Initialize();
|
|
|
|
//echo("checking Enabled");
|
|
if ($this->Enabled !== true)
|
|
{
|
|
$this->Attributes[] = new WebControlAttribute("disabled", "disabled");
|
|
}
|
|
//echo("creating");
|
|
$this->CreateControl();
|
|
|
|
//echo("begining content");
|
|
$this->BeginContent();
|
|
if (is_callable($this->Content))
|
|
{
|
|
call_user_func($this->Content, $this, $this->ExtraData);
|
|
}
|
|
else if (is_string($this->Content))
|
|
{
|
|
echo($this->Content);
|
|
}
|
|
else
|
|
{
|
|
//echo("checking controls");
|
|
if (count($this->Controls) > 0)
|
|
{
|
|
//echo("we have");
|
|
foreach ($this->Controls as $control)
|
|
{
|
|
//echo("rendering child");
|
|
$control->Render();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//echo("rendering content");
|
|
$this->RenderContent();
|
|
}
|
|
}
|
|
//echo("ending content");
|
|
$this->EndContent();
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* Parses an XML representation of a WebControl MarkupElement
|
|
* @param MarkupElement $element
|
|
* @param PhastParser $parser
|
|
* @return WebPage
|
|
*/
|
|
public static function FromMarkup($element, $parser)
|
|
{
|
|
$ctl = new WebControl();
|
|
|
|
$attNamespacePath = $element->GetAttribute("NamespacePath");
|
|
$attTagName = $element->GetAttribute("TagName");
|
|
|
|
$virtualTagPath = "";
|
|
if ($attNamespacePath != null) $virtualTagPath .= $attNamespacePath->Value . "\\";
|
|
if ($attTagName != null) $virtualTagPath .= $attTagName->Value;
|
|
if ($virtualTagPath != "")
|
|
{
|
|
$ctl->VirtualTagPath = $virtualTagPath;
|
|
}
|
|
|
|
$references = array();
|
|
$tagReferences = $element->GetElement("References");
|
|
if ($tagReferences != null)
|
|
{
|
|
foreach ($tagReferences->Elements as $elem)
|
|
{
|
|
if (get_class($elem) != "UniversalEditor\\ObjectModels\\Markup\\MarkupTagElement") continue;
|
|
|
|
$attTagPrefix = $elem->GetAttribute("TagPrefix");
|
|
if ($attTagPrefix == null) continue;
|
|
|
|
$attNamespacePath = $elem->GetAttribute("NamespacePath");
|
|
if ($attNamespacePath == null) continue;
|
|
|
|
$attNamespaceURL = $elem->GetAttribute("NamespaceURL");
|
|
$namespaceURL = "";
|
|
if ($attNamespaceURL != null) $namespaceURL = $attNamespaceURL->Value;
|
|
|
|
$references[] = new WebNamespaceReference($attTagPrefix->Value, $attNamespacePath->Value, $namespaceURL);
|
|
}
|
|
}
|
|
foreach ($references as $reference)
|
|
{
|
|
ControlLoader::$Namespaces[$reference->TagPrefix] = $reference->NamespacePath;
|
|
}
|
|
|
|
$tagContent = $element->GetElement("Content");
|
|
if ($tagContent != null)
|
|
{
|
|
foreach ($tagContent->Elements as $elem)
|
|
{
|
|
ControlLoader::LoadControl($elem, $ctl);
|
|
}
|
|
}
|
|
|
|
$attrCssClass = $element->GetAttribute("CssClass");
|
|
if ($attrCssClass != null)
|
|
{
|
|
$ctl->ClassList[] = $attrCssClass->Value;
|
|
}
|
|
|
|
/*
|
|
$attrCodeBehindClassName = $element->GetAttribute("CodeBehindClassName");
|
|
if ($attrCodeBehindClassName != null)
|
|
{
|
|
$ctl->CodeBehindClassName = $attrCodeBehindClassName->Value;
|
|
|
|
if (class_exists($page->CodeBehindClassName))
|
|
{
|
|
$page->ClassReference = new $page->CodeBehindClassName();
|
|
$page->ClassReference->Page = $page;
|
|
$page->IsPostback = ($_SERVER["REQUEST_METHOD"] == "POST");
|
|
|
|
if (method_exists($page->ClassReference, "OnClassLoaded"))
|
|
{
|
|
$page->ClassReference->OnClassLoaded(EventArgs::GetEmptyInstance());
|
|
}
|
|
else
|
|
{
|
|
System::WriteErrorLog("Code-behind for '" . $page->CodeBehindClassName . "' does not define an 'OnClassLoaded' entry point");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
System::WriteErrorLog("Code-behind for '" . $page->CodeBehindClassName . "' not found");
|
|
}
|
|
}
|
|
*/
|
|
return $ctl;
|
|
}
|
|
}
|
|
?>
|