diff options
Diffstat (limited to 'app/php/controls')
-rw-r--r-- | app/php/controls/CalendarScaffold.php | 127 | ||||
-rw-r--r-- | app/php/controls/CalendarScaffold.tpl | 57 | ||||
-rw-r--r-- | app/php/controls/HeaderMenu.php | 16 | ||||
-rw-r--r-- | app/php/controls/HeaderMenu.tpl | 22 | ||||
-rw-r--r-- | app/php/controls/LoginBox.php | 23 | ||||
-rw-r--r-- | app/php/controls/LoginBox.tpl | 29 | ||||
-rw-r--r-- | app/php/controls/PasswordChange.php | 38 | ||||
-rw-r--r-- | app/php/controls/PasswordChange.tpl | 52 | ||||
-rw-r--r-- | app/php/controls/RegistrationForm.php | 26 | ||||
-rw-r--r-- | app/php/controls/RegistrationForm.tpl | 59 | ||||
-rw-r--r-- | app/php/controls/SafeActiveFileUpload.php | 12 | ||||
-rw-r--r-- | app/php/controls/SafeFileUpload.php | 34 | ||||
-rw-r--r-- | app/php/controls/TimezoneSelect.php | 49 | ||||
-rw-r--r-- | app/php/controls/TimezoneSelect.tpl | 4 | ||||
-rw-r--r-- | app/php/controls/UpcomingEvents.php | 35 | ||||
-rw-r--r-- | app/php/controls/UpcomingEvents.tpl | 10 | ||||
-rw-r--r-- | app/php/controls/UserSelection.php | 39 | ||||
-rw-r--r-- | app/php/controls/UserSelection.tpl | 25 | ||||
-rw-r--r-- | app/php/controls/config.xml | 6 |
19 files changed, 663 insertions, 0 deletions
diff --git a/app/php/controls/CalendarScaffold.php b/app/php/controls/CalendarScaffold.php new file mode 100644 index 0000000..f265d53 --- /dev/null +++ b/app/php/controls/CalendarScaffold.php @@ -0,0 +1,127 @@ +<?php + +Prado::using('System.Web.UI.ActiveControls.TActiveDataGrid'); +Prado::using('System.Web.UI.ActiveControls.TActiveTextBox'); +Prado::using('Application.facades.CalendarFacade'); + +class CalendarScaffold extends TTemplateControl { + + public function setFacade(Facade $facade) { + $this->setViewState('Facade', $facade); + } + + public function getFacade() { + return $this->getViewState('Facade'); + } + + public function onPreRender($param) { + parent::onPreRender($param); + if (!$this->Page->IsPostBack && !$this->Page->IsCallBack) { + $this->_rebindData(); + } + } + + private function _rebindCalendars(array $calendars) { + $this->Calendars->DataSource = $calendars; + $this->Calendars->dataBind(); + } + + private function _rebindCategoryList(array $categories) { + foreach ($this->Calendars->Columns as $column) { + if ($column->ID === 'Category' + && $column instanceof TActiveDropDownListColumn) { + $column->ListDataSource = $categories; + } + } + } + + private function _rebindData($refresh = FALSE) { + $this->_rebindCategoryList( + $this->_getCategories() + ); + $this->_rebindCalendars( + $this->_getCalendars($refresh) + ); + } + + private function _getCalendars($refresh = FALSE) { + if ($refresh) { + $this->clearViewState('Calendars'); + } + $calendars = $this->getViewState( + 'Calendars', + $this->getFacade()->getAll() + ); + $this->setViewState('Calendars', $calendars); + return $calendars; + } + + private function _getCategories() { + $categories = $this->getViewState( + 'Categories', + $this->getFacade()->getCategories() + ); + $this->setViewState('Categories', $categories); + return $categories; + } + + public function editRow($sender, $param) { + $this->Calendars->EditItemIndex = $param->Item->ItemIndex; + $this->_rebindData(); + } + + private function _compileSaveData(TDataGridItem $item) { + return [ + 'CategoryID' => $item->Category->DropDownList->SelectedValue, + 'Visible' => $item->Visible->CheckBox->Checked, + 'CustomName' => $item->CustomName->TextBox->SafeText, + 'CustomUrl' => $item->CustomUrl->TextBox->SafeText, + 'CustomImage' => $item->CustomImage->Value->SafeText + ]; + } + + public function saveRow($sender, $param) { + $calendar = $this->getFacade()->get( + $sender->DataKeys[$param->Item->ItemIndex] + ); + if ($calendar) { + foreach ($calendar as $c) { + $c->saveData($this->_compileSaveData($param->Item)); + } + } else { + throw new TInvalidDataValueException('Calendar not found'); + } + $this->Calendars->EditItemIndex = -1; + $this->_rebindData(TRUE); + } + + public function cancelRowEdit($sender, $param) { + $this->Calendars->EditItemIndex = -1; + $this->_rebindData(); + } + + public function uploadRowFile($sender, $param) { + $fileType = $sender->getFileType(); + if (preg_match('/^image\//', $fileType)) { + $calendar = $this->getFacade()->get($sender->CustomData); + if ($calendar) { + $targetFile = $calendar[0]->getCustomImagePath( + $sender->getLocalName(), + $fileType + ); + if ($sender->saveAs($targetFile)) { + $sender->NamingContainer->CustomImage->Value->Text = basename( + $targetFile + ); + } + } else { + throw new TInvalidDataValueException('Calendar not found'); + } + } else { + throw new TInvalidDataTypeException('Invalid file type'); + } + } + +} + +?> diff --git a/app/php/controls/CalendarScaffold.tpl b/app/php/controls/CalendarScaffold.tpl new file mode 100644 index 0000000..6688869 --- /dev/null +++ b/app/php/controls/CalendarScaffold.tpl @@ -0,0 +1,57 @@ +<com:TActiveDataGrid ID="Calendars" + DataKeyField="UID" + AutoGenerateColumns="false" + OnEditCommand="editRow" + OnCancelCommand="cancelRowEdit" + OnUpdateCommand="saveRow"> + <com:TActiveBoundColumn ID="Name" + ReadOnly="true" + HeaderText="Calendar" + DataField="Name" /> + <com:TActiveHyperLinkColumn ID="Website" + HeaderText="WWW" + Text="[www]" + Target="_blank" + DataNavigateUrlField="Website" /> + <com:TActiveHyperLinkColumn ID="Url" + HeaderText="ICS" + Text="[ics]" + Target="_blank" + DataNavigateUrlField="Url" /> + <com:TActiveDropDownListColumn ID="Category" + HeaderText="Category" + DataTextField="Category.Name" + DataValueField="CategoryID" + ListValueField="ID" + ListTextField="Name" /> + <com:TActiveCheckBoxColumn ID="Visible" + HeaderText="Default" + DataField="Visible" /> + <com:TActiveBoundColumn ID="CustomName" + HeaderText="Name" + DataField="CustomName" /> + <com:TActiveBoundColumn ID="CustomUrl" + HeaderText="URL" + DataField="CustomUrl" /> + <com:TActiveTemplateColumn ID="CustomImage" + HeaderText="Image"> + <prop:ItemTemplate> + <com:TImage> + <prop:ImageUrl><%# $this->Parent->Data->CustomImageUrl %></prop:ImageUrl> + </com:TImage> + </prop:ItemTemplate> + <prop:EditItemTemplate> + <com:TActiveTextBox ID="Value"> + <prop:Text><%# $this->Parent->Data->CustomImage %></prop:Text> + </com:TActiveTextBox><br /> + <com:SafeActiveFileUpload + OnFileUpload="SourceTemplateControl.uploadRowFile"> + <prop:CustomData><%# $this->Parent->Data->UID %></prop:CustomData> + </com:SafeActiveFileUpload> + </prop:EditItemTemplate> + </com:TActiveTemplateColumn> + <com:TActiveEditCommandColumn + HeaderText="Edit" + UpdateText="Save" + CancelText="Cancel" /> +</com:TActiveDataGrid> diff --git a/app/php/controls/HeaderMenu.php b/app/php/controls/HeaderMenu.php new file mode 100644 index 0000000..bffe4d2 --- /dev/null +++ b/app/php/controls/HeaderMenu.php @@ -0,0 +1,16 @@ +<?php + +Prado::using('System.Web.UI.ActiveControls.TActiveLinkButton'); + +class HeaderMenu extends TTemplateControl { + + public function logoutUser($sender, $param) { + $this->Application->getModule('auth')->logout(); + $this->Response->redirect( + $this->Service->ConstructUrl(NULL) + ); + } + +} + +?> diff --git a/app/php/controls/HeaderMenu.tpl b/app/php/controls/HeaderMenu.tpl new file mode 100644 index 0000000..603a231 --- /dev/null +++ b/app/php/controls/HeaderMenu.tpl @@ -0,0 +1,22 @@ +<nav role="navigation"> + <com:THyperLink Text="Login"> + <prop:NavigateUrl><%= $this->Service->constructUrl('Login') %></prop:NavigateUrl> + <prop:Visible><%= $this->User->IsGuest %></prop:Visible> + </com:THyperLink> + <com:THyperLink Text="Profile"> + <prop:NavigateUrl><%= $this->Service->constructUrl('Profile') %></prop:NavigateUrl> + <prop:Visible><%= !$this->User->IsGuest %></prop:Visible> + </com:THyperLink> + <com:TActiveLinkButton OnCommand="logoutUser"> + <prop:Text>Logout (<%= $this->User->Name %>)</prop:Text> + <prop:Visible><%= !$this->User->IsGuest %></prop:Visible> + </com:TActiveLinkButton> + <com:THyperLink Text="New user"> + <prop:NavigateUrl><%= $this->Service->constructUrl('Signup') %></prop:NavigateUrl> + <prop:Visible><%= $this->User->getIsAdmin() %></prop:Visible> + </com:THyperLink> + <com:THyperLink Text="Admin calendars"> + <prop:NavigateUrl><%= $this->Service->constructUrl('Admin') %></prop:NavigateUrl> + <prop:Visible><%= $this->User->getIsAdmin() %></prop:Visible> + </com:THyperLink> +</nav> diff --git a/app/php/controls/LoginBox.php b/app/php/controls/LoginBox.php new file mode 100644 index 0000000..33bbcc1 --- /dev/null +++ b/app/php/controls/LoginBox.php @@ -0,0 +1,23 @@ +<?php + +class LoginBox extends TTemplateControl { + + public function loginUser($sender, $param) { + if ($this->Page->IsValid) { + $this->Response->redirect( + $this->Application->getModule('auth')->ReturnUrl + ?: $this->Service->constructUrl(NULL) + ); + } + } + + public function validatePassword($sender, $param) { + $param->IsValid = $this->Application->getModule('auth')->login( + $this->Login->Text, + $this->Password->Text + ); + } + +} + +?> diff --git a/app/php/controls/LoginBox.tpl b/app/php/controls/LoginBox.tpl new file mode 100644 index 0000000..d3e1a1e --- /dev/null +++ b/app/php/controls/LoginBox.tpl @@ -0,0 +1,29 @@ +Username: +<com:TTextBox ID="Login" + ValidationGroup="LoginGroup" /> +<com:TRequiredFieldValidator + ControlToValidate="Login" + Display="Dynamic" + ErrorMessage="Username cannot be empty" + ValidationGroup="LoginGroup" /> +<br /> +Password: +<com:TTextBox ID="Password" + TextMode="Password" + ValidationGroup="LoginGroup" /> +<com:TRequiredFieldValidator + ControlToValidate="Password" + Display="Dynamic" + ErrorMessage="Password cannot be empty" + ValidationGroup="LoginGroup" /> +<com:TCustomValidator + ControlToValidate="Password" + OnServerValidate="validatePassword" + Display="Dynamic" + ErrorMessage="Username and password don't match" + ValidationGroup="LoginGroup" /> +<br /> +<com:TButton + Text="Login" + OnCommand="loginUser" + ValidationGroup="LoginGroup" /> diff --git a/app/php/controls/PasswordChange.php b/app/php/controls/PasswordChange.php new file mode 100644 index 0000000..9f2ac7f --- /dev/null +++ b/app/php/controls/PasswordChange.php @@ -0,0 +1,38 @@ +<?php + +Prado::using('Application.user.DbUser'); + +class PasswordChange extends TTemplateControl { + + public function getUserToChange() { + return $this->getControlState('user'); + } + + public function setUserToChange(DbUser $user) { + if ($user->IsGuest) { + throw new TInvalidDataValueException( + 'Password change impossible for guest user' + ); + } + $this->setControlState('user', $user); + } + + public function checkPassword($sender, $param) { + $param->IsValid = DbUser::verifyPassword( + $this->Password->Text, $this->UserToChange->getPassword() + ); + } + + public function changePassword($sender, $param) { + $this->SuccessMessage->Visible = FALSE; + if ($this->Page->IsValid) { + $this->UserToChange->changePassword( + $this->NewPassword->Text + ); + $this->SuccessMessage->Visible = TRUE; + } + } + +} + +?> diff --git a/app/php/controls/PasswordChange.tpl b/app/php/controls/PasswordChange.tpl new file mode 100644 index 0000000..915e8b3 --- /dev/null +++ b/app/php/controls/PasswordChange.tpl @@ -0,0 +1,52 @@ +Change password<br /> +Current password: +<com:TTextBox ID="Password" + TextMode="Password" + ValidationGroup="ChangePasswordGroup" /> +<com:TRequiredFieldValidator + ControlToValidate="Password" + Display="Dynamic" + ErrorMessage="Current password cannot be empty" + ValidationGroup="ChangePasswordGroup" /> +<com:TCustomValidator + ControlToValidate="Password" + OnServerValidate="checkPassword" + Display="Dynamic" + ErrorMessage="Password is incorrect" + ValidationGroup="ChangePasswordGroup" /> +<br /> +New password: +<com:TTextBox ID="NewPassword" + TextMode="Password" + ValidationGroup="ChangePasswordGroup" /> +<com:TRequiredFieldValidator + ControlToValidate="NewPassword" + Display="Dynamic" + ErrorMessage="New password cannot be empty" + ValidationGroup="ChangePasswordGroup" /> +<br /> +Repeat password: +<com:TTextBox ID="ReNewPassword" + TextMode="Password" + ValidationGroup="ChangePasswordGroup" /> +<com:TRequiredFieldValidator + ControlToValidate="ReNewPassword" + Display="Dynamic" + ErrorMessage="New password cannot be empty" + ValidationGroup="ChangePasswordGroup" /> +<com:TCompareValidator + ControlToValidate="ReNewPassword" + ControlToCompare="NewPassword" + DataType="String" + Operator="Equal" + Display="Dynamic" + ErrorMessage="Passwords don't match" + ValidationGroup="ChangePasswordGroup" /> +<br /> +<com:TButton + Text="Change password" + OnCommand="changePassword" + ValidationGroup="ChangePasswordGroup" /> +<com:TLabel ID="SuccessMessage" + Text="Your password has been changed" + Visible="false" /> diff --git a/app/php/controls/RegistrationForm.php b/app/php/controls/RegistrationForm.php new file mode 100644 index 0000000..71d4df1 --- /dev/null +++ b/app/php/controls/RegistrationForm.php @@ -0,0 +1,26 @@ +<?php + +Prado::using('Application.model.User'); + +class RegistrationForm extends TTemplateControl { + + public function checkUsername($sender, $param) { + $param->IsValid = !User::finder()->countByLogin($this->Login->SafeText); + } + + public function registerUser($sender, $param) { + if ($this->Page->IsValid) { + $newUser = new User(); + $newUser->Login = $this->Login->SafeText; + $newUser->Password = DbUser::generatePassword($this->Password->Text); + $newUser->IsAdmin = $this->Admin->Checked; + $newUser->save(); + $this->Response->redirect( + $this->Service->constructUrl(NULL) + ); + } + } + +} + +?> diff --git a/app/php/controls/RegistrationForm.tpl b/app/php/controls/RegistrationForm.tpl new file mode 100644 index 0000000..ffa4778 --- /dev/null +++ b/app/php/controls/RegistrationForm.tpl @@ -0,0 +1,59 @@ +Username: +<com:TTextBox ID="Login" + ValidationGroup="SignupGroup" /> +<com:TRequiredFieldValidator + ControlToValidate="Login" + Display="Dynamic" + ErrorMessage="Username cannot be empty" + ValidationGroup="SignupGroup" /> +<com:TRegularExpressionValidator + ControlToValidate="Login" + RegularExpression="[a-zA-Z0-9_]{6,255}" + Display="Dynamic" + ErrorMessage="Username must contain 6-255 characters, all Latin alphanumeric or underscore" + ValidationGroup="SignupGroup" /> +<com:TCustomValidator + ControlToValidate="Login" + OnServerValidate="checkUsername" + Display="Dynamic" + ErrorMessage="Username already exists" + ValidationGroup="SignupGroup" /> +<br /> +Password: +<com:TTextBox ID="Password" + TextMode="Password" + ValidationGroup="SignupGroup" /> +<com:TRequiredFieldValidator + ControlToValidate="Password" + Display="Dynamic" + ErrorMessage="Password cannot be empty" + ValidationGroup="SignupGroup" /> +<br /> +Repeat password: +<com:TTextBox ID="RePassword" + TextMode="Password" + ValidationGroup="SignupGroup" /> +<com:TRequiredFieldValidator + ControlToValidate="RePassword" + Display="Dynamic" + ErrorMessage="Password cannot be empty" + ValidationGroup="SignupGroup" /> +<com:TCompareValidator + ControlToValidate="RePassword" + ControlToCompare="Password" + DataType="String" + Operator="Equal" + Display="Dynamic" + ErrorMessage="Passwords don't match" + ValidationGroup="SignupGroup" /> +<br /> +Admin: +<com:TCheckBox ID="Admin" + ValidationGroup="SignupGroup" /> +<br /> +<com:TButton + Text="Create" + OnCommand="registerUser" + ValidationGroup="SignupGroup" /> +<com:TValidationSummary + ValidationGroup="SignupGroup" /> diff --git a/app/php/controls/SafeActiveFileUpload.php b/app/php/controls/SafeActiveFileUpload.php new file mode 100644 index 0000000..ada1e34 --- /dev/null +++ b/app/php/controls/SafeActiveFileUpload.php @@ -0,0 +1,12 @@ +<?php + +Prado::using('System.Web.UI.ActiveControls.TActiveFileUpload'); +Prado::using('Application.controls.SafeFileUpload'); + +class SafeActiveFileUpload extends TActiveFileUpload { + + use MimeTypeCheckForFileUpload; + +} + +?> diff --git a/app/php/controls/SafeFileUpload.php b/app/php/controls/SafeFileUpload.php new file mode 100644 index 0000000..98e120a --- /dev/null +++ b/app/php/controls/SafeFileUpload.php @@ -0,0 +1,34 @@ +<?php + +class SafeFileUpload extends TFileUpload { + + use MimeTypeCheckForFileUpload; + +} + +trait MimeTypeCheckForFileUpload { + + protected $_isSecure = TRUE; + + public function getIsSecure() { + return $this->_isSecure; + } + + public function setIsSecure($bool) { + $this->_isSecure = $bool; + } + + public function getFileType() { + $type = parent::getFileType(); + if ($this->getIsSecure()) { + $fileInfo = new finfo(FILEINFO_MIME_TYPE); + return $fileInfo->file($this->getLocalName()); + } + else { + return $type; + } + } + +} + +?> diff --git a/app/php/controls/TimezoneSelect.php b/app/php/controls/TimezoneSelect.php new file mode 100644 index 0000000..3302e2a --- /dev/null +++ b/app/php/controls/TimezoneSelect.php @@ -0,0 +1,49 @@ +<?php + +Prado::using('Application.user.DbUser'); +Prado::using('Application.dto.TimezoneDTO'); + +class TimezoneSelect extends TTemplateControl { + + public function getUserToChange() { + return $this->getControlState('user'); + } + + public function setUserToChange(DbUser $user) { + if ($user->IsGuest) { + throw new TInvalidDataValueException( + 'Timezone preference change impossible for guest user' + ); + } + $this->setControlState('user', $user); + } + + public function onPreRender($param) { + parent::onPreRender($param); + $this->Timezones->DataSource = $this->_getTimezones(); + $this->Timezones->DataValueField = 'Name'; + $this->Timezones->DataTextField = 'Label'; + $this->Timezones->dataBind(); + $this->Timezones->setSelectedValue( + $this->UserToChange->getTimezonePreference()->Name + ); + } + + public function saveTimezone($sender, $param) { + $this->UserToChange->setTimezonePreference($this->Timezones->SelectedValue); + } + + private function _getTimezones() { + $timezones = array_map( + function($tz) { + return new TimezoneDTO($tz); + }, + DateTimeZone::listIdentifiers() + ); + usort($timezones, ['TimezoneDTO', '__compare']); + return $timezones; + } + +} + +?> diff --git a/app/php/controls/TimezoneSelect.tpl b/app/php/controls/TimezoneSelect.tpl new file mode 100644 index 0000000..2d40014 --- /dev/null +++ b/app/php/controls/TimezoneSelect.tpl @@ -0,0 +1,4 @@ +<com:TDropDownList ID="Timezones" /> +<com:TButton + Text="Save timezone" + OnCommand="saveTimezone" /> diff --git a/app/php/controls/UpcomingEvents.php b/app/php/controls/UpcomingEvents.php new file mode 100644 index 0000000..27fa8c6 --- /dev/null +++ b/app/php/controls/UpcomingEvents.php @@ -0,0 +1,35 @@ +<?php + +Prado::using('Application.facades.EventFacade'); + +class UpcomingEvents extends TTemplateControl { + + public function getUserToDisplay() { + return $this->getControlState('user'); + } + + public function setUserToDisplay($user) { + $this->setControlState('user', $user); + } + + public function onPreRender($param) { + parent::onPreRender($param); + $this->Events->setDataSource( + $this->_getEventsForUser($this->UserToDisplay) + ); + $this->Events->dataBind(); + } + + private function _getEventsForUser(DbUser $user) { + $utc = new DateTimeZone('UTC'); + $dateFrom = new DateTime('now', $utc); + $dateTo = new DateTime('+7 days', $utc); + return EventFacade::getInstance()->getTimeframeListForUser( + $user, + $dateFrom, $dateTo + ); + } + +} + +?> diff --git a/app/php/controls/UpcomingEvents.tpl b/app/php/controls/UpcomingEvents.tpl new file mode 100644 index 0000000..d660f54 --- /dev/null +++ b/app/php/controls/UpcomingEvents.tpl @@ -0,0 +1,10 @@ +Upcoming events: +<br /> +<com:TRepeater ID="Events"> + <prop:ItemTemplate> + <%# $this->Data->DateString %> + <%# $this->Data->Name %> + (<%# $this->Data->Calendar->Name %>) + <br /> + </prop:ItemTemplate> +</com:TRepeater> diff --git a/app/php/controls/UserSelection.php b/app/php/controls/UserSelection.php new file mode 100644 index 0000000..6ae68e4 --- /dev/null +++ b/app/php/controls/UserSelection.php @@ -0,0 +1,39 @@ +<?php + +Prado::using('Application.facades.CalendarFacade'); + +class UserSelection extends TTemplateControl { + + public function getUserToDisplay() { + return $this->getControlState('user'); + } + + public function setUserToDisplay($user) { + $this->setControlState('user', $user); + } + + public function onPreRender($param) { + parent::onPreRender($param); + $this->Categories->setDataSource( + $this->_getUserSelection($this->UserToDisplay) + ); + $this->Categories->dataBind(); + } + + public function categoryDataBind($sender, $param) { + $param->Item->Calendars->setDataSource($param->Item->Data->Calendars); + $param->Item->Calendars->dataBind(); + } + + public function removeFromSelection($sender, $param) { + if (!$this->UserToDisplay->IsGuest) { + } + } + + private function _getUserSelection(DbUser $user) { + return CalendarFacade::getInstance()->getPreferenceList($user); + } + +} + +?> diff --git a/app/php/controls/UserSelection.tpl b/app/php/controls/UserSelection.tpl new file mode 100644 index 0000000..14035ca --- /dev/null +++ b/app/php/controls/UserSelection.tpl @@ -0,0 +1,25 @@ +Selected calendars: +<br /> +<com:TRepeater ID="Categories" OnItemDataBound="categoryDataBind"> + <prop:ItemTemplate> + <%# $this->Data->Name %><br /> + <com:TRepeater ID="Calendars"> + <prop:ItemTemplate> + <com:TLinkButton + Text="[X]" + OnCommand="SourceTemplateControl.removeFromSelection"> + <prop:CommandParameter><%# $this->Data->ID %></prop:CommandParameter> + <prop:Visible><%# !$this->SourceTemplateControl->UserToDisplay->IsGuest %></prop:Visible> + </com:TLinkButton> + <%# $this->Data->Name %> + <com:THyperLink + Text="(www)" + Target="_blank"> + <prop:NavigateUrl><%# $this->Data->Website %></prop:NavigateUrl> + </com:THyperLink> + <br /> + </prop:ItemTemplate> + </com:TRepeater> + <br /> + </prop:ItemTemplate> +</com:TRepeater> diff --git a/app/php/controls/config.xml b/app/php/controls/config.xml new file mode 100644 index 0000000..61d7e5b --- /dev/null +++ b/app/php/controls/config.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<configuration> + <paths> + <using namespace="Application.controls.*" /> + </paths> +</configuration> |