/** * Write a button drop down control. * * @param array $Links An array of arrays with the following keys: * - Text: The text of the link. * - Url: The url of the link. * @param string|array $CssClass The css class of the link. This can be a two-item array where the second element will be added to the buttons. * @param string $Label The text of the button. * @since 2.1 */ function buttonDropDown($Links, $CssClass = 'Button', $Label = false) { if (!is_array($Links) || count($Links) < 1) { return; } $ButtonClass = ''; if (is_array($CssClass)) { list($CssClass, $ButtonClass) = $CssClass; } if (count($Links) < 2) { $Link = array_pop($Links); if (strpos(GetValue('CssClass', $Link, ''), 'Popup') !== false) { $CssClass .= ' Popup'; } echo Anchor($Link['Text'], $Link['Url'], GetValue('ButtonCssClass', $Link, $CssClass)); } else { // NavButton or Button? $ButtonClass = ConcatSep(' ', $ButtonClass, strpos($CssClass, 'NavButton') !== false ? 'NavButton' : 'Button'); if (strpos($CssClass, 'Primary') !== false) { $ButtonClass .= ' Primary'; } // Strip "Button" or "NavButton" off the group class. echo '<div class="ButtonGroup' . str_replace(array('NavButton', 'Button'), array('', ''), $CssClass) . '">'; // echo Anchor($Text, $Url, $ButtonClass); echo '<ul class="Dropdown MenuItems">'; foreach ($Links as $Link) { echo wrap(Anchor($Link['Text'], $Link['Url'], val('CssClass', $Link, '')), 'li'); } echo '</ul>'; echo anchor($Label . ' ' . sprite('SpDropdownHandle'), '#', $ButtonClass . ' Handle'); echo '</div>'; } }
public function Edit($Reference = 0, $ParentID = '') { $Session = Gdn::Session(); $Model = new SectionModel(); $this->Form->SetModel($Model); if ($ParentID) { $this->Form->AddHidden('ParentID', $ParentID); } $Section = False; if ($Reference) { $Section = $Model->GetID($Reference); if (!IsContentOwner($Section, 'Candy.Sections.Edit')) { $Section = False; } if ($Section) { $this->Form->AddHidden('SectionID', $Section->SectionID); $this->Form->SetData($Section); } } if (!$Section) { $this->Permission('Candy.Sections.Add'); } if ($this->Form->AuthenticatedPostBack()) { $this->Form->Save($Section); if ($this->Form->ErrorCount() == 0) { $this->InformMessage(T('Saved'), array('Sprite' => 'Check', 'CssClass' => 'Dismissable AutoDismiss')); } } $this->Title(ConcatSep(' - ', T('Section'), GetValue('Name', $Section))); $this->Render(); }
/** * Takes a route and prepends the web root (expects "/controller/action/params" as $Path). * * @param array The parameters passed into the function. * The parameters that can be passed to this function are as follows. * - <b>path</b>: The relative path for the url. There are some special paths that can be used to return "intelligent" links: * - <b>signinout</b>: This will return a signin/signout url that will toggle depending on whether or not the user is already signed in. When this path is given the text is automaticall set. * - <b>withdomain</b>: Whether or not to add the domain to the url. * - <b>text</b>: Html text to be put inside an anchor. If this value is set then an html <a></a> is returned rather than just a url. * - <b>id, class, etc.></b>: When an anchor is generated then any other attributes are passed through and will be written in the resulting tag. * @param Smarty The smarty object rendering the template. * @return The url. */ function smarty_function_link($Params, &$Smarty) { $Path = GetValue('path', $Params, '', TRUE); $WithDomain = GetValue('withdomain', $Params, FALSE, TRUE); $RemoveSyndication = GetValue('removeSyndication', $Params, FALSE, TRUE); $Text = GetValue('text', $Params, '', TRUE); $NoTag = GetValue('notag', $Params, FALSE, TRUE); $Class = GetValue('class', $Params, '', TRUE); $Session = Gdn::Session(); $Authenticator = Gdn::Authenticator(); // Use some logic to expan special urls. switch (strtolower($Path)) { case "signinout": // The destination is the signin/signout toggle link. if ($Session->IsValid()) { if (!$Text && !$NoTag) { $Text = T('Sign Out'); } $Path = $Authenticator->SignOutUrl(); $Class = ConcatSep(' ', $Class, 'SignOut'); } else { if (!$Text && !$NoTag) { $Text = T('Sign In'); } $Attribs = array(); $Path = $Authenticator->SignInUrl(''); if (Gdn::Config('Garden.SignIn.Popup')) { $Class = ConcatSep(' ', $Class, 'SignInPopup'); } } break; } $Url = Url($Path, $WithDomain, $RemoveSyndication); $Url = str_replace('{Session_TransientKey}', $Session->TransientKey(), $Url); if (!$Text) { $NoTag = TRUE; } if ($NoTag) { $Result = $Url; } else { $Result = '<a'; // Add the standard attrbutes to the anchor. $ID = GetValue('id', $Params, '', TRUE); if ($ID) { $Result .= ' id="' . urlencode($ID) . '"'; } $Result .= ' href="' . $Url . '"'; if ($Class) { $Result .= ' class="' . urlencode($Class) . '"'; } // Add anything that's left over. foreach ($Params as $Key => $Value) { $Result .= ' ' . $Key . '="' . urlencode($Value) . '"'; } // Add the link text. $Result .= '>' . $Text . '</a>'; } return $Result; }
/** * Load discussions for a specific tag. */ public function DiscussionsController_Tagged_Create($Sender) { $Offset = GetValue('1', $Sender->RequestArgs, 'p1'); list($Offset, $Limit) = OffsetLimit($Offset, Gdn::Config('Vanilla.Discussions.PerPage', 30)); $Sender->Tag = GetValue('0', $Sender->RequestArgs, ''); $Sender->Title(T('Tagged with ') . $Sender->Tag); $Sender->Head->Title($Sender->Head->Title()); $Sender->CanonicalUrl(Url(ConcatSep('/', 'discussions/tagged/' . $Sender->Tag, PageNumber($Offset, $Limit, TRUE)), TRUE)); if ($Sender->Head) { $Sender->AddJsFile('discussions.js'); $Sender->AddJsFile('bookmark.js'); $Sender->AddJsFile('js/library/jquery.menu.js'); $Sender->AddJsFile('options.js'); $Sender->Head->AddRss($Sender->SelfUrl . '/feed.rss', $Sender->Head->Title()); } if (!is_numeric($Offset) || $Offset < 0) { $Offset = 0; } // Add Modules $Sender->AddModule('NewDiscussionModule'); $BookmarkedModule = new BookmarkedModule($Sender); $BookmarkedModule->GetData(); $Sender->AddModule($BookmarkedModule); $Sender->SetData('Category', FALSE, TRUE); $DiscussionModel = new DiscussionModel(); $Tag = $DiscussionModel->SQL->Select()->From('Tag')->Where('Name', $Sender->Tag)->Get()->FirstRow(); $TagID = $Tag ? $Tag->TagID : 0; $CountDiscussions = $Tag ? $Tag->CountDiscussions : 0; $Sender->SetData('CountDiscussions', $CountDiscussions); $Sender->AnnounceData = FALSE; $Sender->SetData('Announcements', array(), TRUE); $DiscussionModel->FilterToTagID = $TagID; $Sender->DiscussionData = $DiscussionModel->Get($Offset, $Limit); $Sender->SetData('Discussions', $Sender->DiscussionData, TRUE); $Sender->SetJson('Loading', $Offset . ' to ' . $Limit); // Build a pager. $PagerFactory = new Gdn_PagerFactory(); $Sender->Pager = $PagerFactory->GetPager('Pager', $Sender); $Sender->Pager->ClientID = 'Pager'; $Sender->Pager->Configure($Offset, $Limit, $CountDiscussions, 'discussions/tagged/' . $Sender->Tag . '/%1$s'); // Deliver json data if necessary if ($Sender->DeliveryType() != DELIVERY_TYPE_ALL) { $Sender->SetJson('LessRow', $Sender->Pager->ToString('less')); $Sender->SetJson('MoreRow', $Sender->Pager->ToString('more')); $Sender->View = 'discussions'; } // Set a definition of the user's current timezone from the db. jQuery // will pick this up, compare to the browser, and update the user's // timezone if necessary. $CurrentUser = Gdn::Session()->User; if (is_object($CurrentUser)) { $ClientHour = $CurrentUser->HourOffset + date('G', time()); $Sender->AddDefinition('SetClientHour', $ClientHour); } // Render the controller $Sender->Render(PATH_PLUGINS . '/Tagging/views/taggeddiscussions.php'); }
/** * Default all discussions view: chronological by most recent comment. * * @since 2.0.0 * @access public * * @param int $Page Multiplied by PerPage option to determine offset. */ public function Index($Page = '0') { // Determine offset from $Page list($Page, $Limit) = OffsetLimit($Page, Gdn::Config('Vanilla.Discussions.PerPage', 30)); $this->CanonicalUrl(Url(ConcatSep('/', 'discussions', PageNumber($Page, $Limit, TRUE)), TRUE)); // Validate $Page if (!is_numeric($Page) || $Page < 0) { $Page = 0; } // Setup head $this->Title(T('All Discussions')); if ($this->Head) { $this->Head->AddRss(Url('/discussions/feed.rss', TRUE), $this->Head->Title()); } // Add modules $this->AddModule('NewDiscussionModule'); $this->AddModule('CategoriesModule'); $BookmarkedModule = new BookmarkedModule($this); $BookmarkedModule->GetData(); $this->AddModule($BookmarkedModule); // Set criteria & get discussions data $this->SetData('Category', FALSE, TRUE); $DiscussionModel = new DiscussionModel(); $CountDiscussions = $DiscussionModel->GetCount(); $this->SetData('CountDiscussions', $CountDiscussions); $this->AnnounceData = $Page == 0 ? $DiscussionModel->GetAnnouncements() : FALSE; $this->SetData('Announcements', $this->AnnounceData !== FALSE ? $this->AnnounceData : array(), TRUE); $this->DiscussionData = $DiscussionModel->Get($Page, $Limit); $this->SetData('Discussions', $this->DiscussionData, TRUE); $this->SetJson('Loading', $Page . ' to ' . $Limit); // Build a pager $PagerFactory = new Gdn_PagerFactory(); $this->EventArguments['PagerType'] = 'Pager'; $this->FireEvent('BeforeBuildPager'); $this->Pager = $PagerFactory->GetPager($this->EventArguments['PagerType'], $this); $this->Pager->ClientID = 'Pager'; $this->Pager->Configure($Page, $Limit, $CountDiscussions, 'discussions/%1$s'); $this->FireEvent('AfterBuildPager'); // Deliver JSON data if necessary if ($this->_DeliveryType != DELIVERY_TYPE_ALL) { $this->SetJson('LessRow', $this->Pager->ToString('less')); $this->SetJson('MoreRow', $this->Pager->ToString('more')); $this->View = 'discussions'; } // Set a definition of the user's current timezone from the db. jQuery // will pick this up, compare to the browser, and update the user's // timezone if necessary. $CurrentUser = Gdn::Session()->User; if (is_object($CurrentUser)) { $ClientHour = $CurrentUser->HourOffset + date('G', time()); $this->AddDefinition('SetClientHour', $ClientHour); } // Render default view (discussions/index.php) $this->Render(); }
public function CheckMollom($RecordType, $Data) { $UserID = $this->UserID(); if (!$UserID) { return FALSE; } $Mollom = self::Mollom(); if (!$Mollom) { return FALSE; } $Result = $Mollom->checkContent(array('checks' => array('spam'), 'postTitle' => GetValue('Name', $Data), 'postBody' => ConcatSep("\n\n", GetValue('Body', $Data), GetValue('Story', $Data)), 'authorName' => $Data['Username'], 'authorEmail' => $Data['Email'], 'authorIp' => $Data['IPAddress'])); return $Result['spamClassification'] == 'spam' ? true : false; }
public function Index($Offset = '0') { list($Offset, $Limit) = OffsetLimit($Offset, Gdn::Config('Vanilla.Discussions.PerPage', 30)); $this->CanonicalUrl(Url(ConcatSep('/', 'discussions', PageNumber($Offset, $Limit, TRUE)), TRUE)); $this->Title(T('All Discussions')); if ($this->Head) { $this->Head->AddRss($this->SelfUrl . '/feed.rss', $this->Head->Title()); } if (!is_numeric($Offset) || $Offset < 0) { $Offset = 0; } // Add Modules $this->AddModule('NewDiscussionModule'); $this->AddModule('CategoriesModule'); $BookmarkedModule = new BookmarkedModule($this); $BookmarkedModule->GetData(); $this->AddModule($BookmarkedModule); $this->SetData('Category', FALSE, TRUE); $DiscussionModel = new DiscussionModel(); $CountDiscussions = $DiscussionModel->GetCount(); $this->SetData('CountDiscussions', $CountDiscussions); $this->AnnounceData = $Offset == 0 ? $DiscussionModel->GetAnnouncements() : FALSE; $this->SetData('Announcements', $this->AnnounceData !== FALSE ? $this->AnnounceData : array(), TRUE); $this->DiscussionData = $DiscussionModel->Get($Offset, $Limit); $this->SetData('Discussions', $this->DiscussionData, TRUE); $this->SetJson('Loading', $Offset . ' to ' . $Limit); // Build a pager. $PagerFactory = new Gdn_PagerFactory(); $this->Pager = $PagerFactory->GetPager('Pager', $this); $this->Pager->ClientID = 'Pager'; $this->Pager->Configure($Offset, $Limit, $CountDiscussions, 'discussions/%1$s'); // Deliver json data if necessary if ($this->_DeliveryType != DELIVERY_TYPE_ALL) { $this->SetJson('LessRow', $this->Pager->ToString('less')); $this->SetJson('MoreRow', $this->Pager->ToString('more')); $this->View = 'discussions'; } // Set a definition of the user's current timezone from the db. jQuery // will pick this up, compare to the browser, and update the user's // timezone if necessary. $CurrentUser = Gdn::Session()->User; if (is_object($CurrentUser)) { $ClientHour = $CurrentUser->HourOffset + date('G', time()); $this->AddDefinition('SetClientHour', $ClientHour); } // Render the controller $this->Render(); }
function CountString($Number, $Url = '', $Options = array()) { if (is_string($Options)) $Options = array('cssclass' => $Options); $Options = array_change_key_case($Options); $CssClass = GetValue('cssclass', $Options, ''); if ($Number === NULL && $Url) { $CssClass = ConcatSep(' ', $CssClass, 'Popin TinyProgress'); $Url = htmlspecialchars($Url); $Result = "<span class=\"$CssClass\" rel=\"$Url\"></span>"; } elseif ($Number) { $Result = " <span class=\"Count\">$Number</span>"; } else { $Result = ''; } return $Result; }
public function CheckAkismet($RecordType, $Data) { $UserID = $this->UserID(); if (!$UserID) { return FALSE; } $Akismet = self::Akismet(); if (!$Akismet) { return FALSE; } $Akismet->setCommentAuthor($Data['Username']); $Akismet->setCommentAuthorEmail($Data['Email']); $Body = ConcatSep("\n\n", GetValue('Name', $Data), GetValue('Body', $Data), GetValue('Story', $Data)); $Akismet->setCommentContent($Body); $Akismet->setUserIP($Data['IPAddress']); $Result = $Akismet->isCommentSpam(); return $Result; }
public function Update($Reference = '', $PostBackKey = '') { $this->Permission('Candy.Chunks.Edit'); $Content = False; $Session = Gdn::Session(); $this->AddJsFile('jquery.textpandable.js'); $this->AddJsFile('editform.js'); $this->Form->SetModel($this->ChunkModel); if ($Reference != '') { $Content = $this->ChunkModel->GetID($Reference); if ($Content) { $this->Form->AddHidden('ChunkID', $Content->ChunkID); $this->Editing = True; $this->Form->SetData($Content); } } $IsFormPostBack = $this->Form->AuthenticatedPostBack(); $PostAuthenticatedByKey = $Session->ValidateTransientKey($PostBackKey) && $this->Form->IsPostBack(); if ($IsFormPostBack || $PostAuthenticatedByKey) { if ($PostAuthenticatedByKey) { // AJAX, set form values. $this->Form->SetFormValue('ChunkID', $Content->ChunkID); $this->Form->SetFormValue('Body', GetPostValue('Body')); } $SavedID = $this->Form->Save($Content); if ($SavedID) { $Message = T('Saved'); $this->InformMessage($Message, array('Sprite' => 'Check', 'CssClass' => 'Dismissable AutoDismiss')); if ($this->DeliveryType() == DELIVERY_TYPE_BOOL) { //$this->SetData('Content', $Content); //$this->SetData('NewBody', Gdn_Format::To($this->Form->GetFormValue('Body'), $Content->Format)); $this->SetJson('NewBody', Gdn_Format::To($this->Form->GetFormValue('Body'), $Content->Format)); } } } else { $this->SetData('Content', $Content); $this->Form->SetData($Content); } $this->Title(ConcatSep(' - ', T('Chunk'), GetValue('Name', $Content))); $this->Render(); }
public function Base_BeforeCommentDisplay_Handler($Sender, $Args) { $QnA = GetValueR('Comment.QnA', $Args); if ($QnA && isset($Args['CssClass'])) { $Args['CssClass'] = ConcatSep(' ', $Args['CssClass'], "QnA-Item-{$QnA}"); } }
/** * Allows the configuration of basic setup information in Garden. This * should not be functional after the application has been set up. * * @since 2.0.0 * @access public * @param string $RedirectUrl Where to send user afterward. */ public function Configure($RedirectUrl = '') { // Create a model to save configuration settings $Validation = new Gdn_Validation(); $ConfigurationModel = new Gdn_ConfigurationModel($Validation); $ConfigurationModel->SetField(array('Garden.Locale', 'Garden.Title', 'Garden.RewriteUrls', 'Garden.WebRoot', 'Garden.Cookie.Salt', 'Garden.Cookie.Domain', 'Database.Name', 'Database.Host', 'Database.User', 'Database.Password', 'Garden.Registration.ConfirmEmail', 'Garden.Email.SupportName')); // Set the models on the forms. $this->Form->SetModel($ConfigurationModel); // Load the locales for the locale dropdown // $Locale = Gdn::Locale(); // $AvailableLocales = $Locale->GetAvailableLocaleSources(); // $this->LocaleData = array_combine($AvailableLocales, $AvailableLocales); // If seeing the form for the first time... if (!$this->Form->IsPostback()) { // Force the webroot using our best guesstimates $ConfigurationModel->Data['Database.Host'] = 'localhost'; $this->Form->SetData($ConfigurationModel->Data); } else { // Define some validation rules for the fields being saved $ConfigurationModel->Validation->ApplyRule('Database.Name', 'Required', 'You must specify the name of the database in which you want to set up Vanilla.'); // Let's make some user-friendly custom errors for database problems $DatabaseHost = $this->Form->GetFormValue('Database.Host', '~~Invalid~~'); $DatabaseName = $this->Form->GetFormValue('Database.Name', '~~Invalid~~'); $DatabaseUser = $this->Form->GetFormValue('Database.User', '~~Invalid~~'); $DatabasePassword = $this->Form->GetFormValue('Database.Password', '~~Invalid~~'); $ConnectionString = GetConnectionString($DatabaseName, $DatabaseHost); try { $Connection = new PDO($ConnectionString, $DatabaseUser, $DatabasePassword); } catch (PDOException $Exception) { switch ($Exception->getCode()) { case 1044: $this->Form->AddError(T('The database user you specified does not have permission to access the database. Have you created the database yet? The database reported: <code>%s</code>'), strip_tags($Exception->getMessage())); break; case 1045: $this->Form->AddError(T('Failed to connect to the database with the username and password you entered. Did you mistype them? The database reported: <code>%s</code>'), strip_tags($Exception->getMessage())); break; case 1049: $this->Form->AddError(T('It appears as though the database you specified does not exist yet. Have you created it yet? Did you mistype the name? The database reported: <code>%s</code>'), strip_tags($Exception->getMessage())); break; case 2005: $this->Form->AddError(T("Are you sure you've entered the correct database host name? Maybe you mistyped it? The database reported: <code>%s</code>"), strip_tags($Exception->getMessage())); break; default: $this->Form->AddError(sprintf(T('ValidateConnection'), strip_tags($Exception->getMessage()))); break; } } $ConfigurationModel->Validation->ApplyRule('Garden.Title', 'Required'); $ConfigurationFormValues = $this->Form->FormValues(); if ($ConfigurationModel->Validate($ConfigurationFormValues) !== TRUE || $this->Form->ErrorCount() > 0) { // Apply the validation results to the form(s) $this->Form->SetValidationResults($ConfigurationModel->ValidationResults()); } else { $Host = array_shift(explode(':', Gdn::Request()->RequestHost())); $Domain = Gdn::Request()->Domain(); // Set up cookies now so that the user can be signed in. $ExistingSalt = C('Garden.Cookie.Salt', FALSE); $ConfigurationFormValues['Garden.Cookie.Salt'] = $ExistingSalt ? $ExistingSalt : RandomString(10); $ConfigurationFormValues['Garden.Cookie.Domain'] = ''; // Don't set this to anything by default. # Tim - 2010-06-23 // Additional default setup values. $ConfigurationFormValues['Garden.Registration.ConfirmEmail'] = TRUE; $ConfigurationFormValues['Garden.Email.SupportName'] = $ConfigurationFormValues['Garden.Title']; $ConfigurationModel->Save($ConfigurationFormValues, TRUE); // If changing locale, redefine locale sources: $NewLocale = 'en-CA'; // $this->Form->GetFormValue('Garden.Locale', FALSE); if ($NewLocale !== FALSE && Gdn::Config('Garden.Locale') != $NewLocale) { $ApplicationManager = new Gdn_ApplicationManager(); $Locale = Gdn::Locale(); $Locale->Set($NewLocale, $ApplicationManager->EnabledApplicationFolders(), Gdn::PluginManager()->EnabledPluginFolders(), TRUE); } // Install db structure & basic data. $Database = Gdn::Database(); $Database->Init(); $Drop = FALSE; // Gdn::Config('Garden.Version') === FALSE ? TRUE : FALSE; $Explicit = FALSE; try { include PATH_APPLICATIONS . DS . 'dashboard' . DS . 'settings' . DS . 'structure.php'; } catch (Exception $ex) { $this->Form->AddError($ex); } if ($this->Form->ErrorCount() > 0) { return FALSE; } // Create the administrative user $UserModel = Gdn::UserModel(); $UserModel->DefineSchema(); $UsernameError = T('UsernameError', 'Username can only contain letters, numbers, underscores, and must be between 3 and 20 characters long.'); $UserModel->Validation->ApplyRule('Name', 'Username', $UsernameError); $UserModel->Validation->ApplyRule('Name', 'Required', T('You must specify an admin username.')); $UserModel->Validation->ApplyRule('Password', 'Required', T('You must specify an admin password.')); $UserModel->Validation->ApplyRule('Password', 'Match'); $UserModel->Validation->ApplyRule('Email', 'Email'); if (!($AdminUserID = $UserModel->SaveAdminUser($ConfigurationFormValues))) { $this->Form->SetValidationResults($UserModel->ValidationResults()); } else { // The user has been created successfully, so sign in now. SaveToConfig('Garden.Installed', TRUE, array('Save' => FALSE)); Gdn::Session()->Start($AdminUserID, TRUE); SaveToConfig('Garden.Installed', FALSE, array('Save' => FALSE)); } if ($this->Form->ErrorCount() > 0) { return FALSE; } // Assign some extra settings to the configuration file if everything succeeded. $ApplicationInfo = array(); include CombinePaths(array(PATH_APPLICATIONS . DS . 'dashboard' . DS . 'settings' . DS . 'about.php')); // Detect rewrite abilities try { $Query = ConcatSep('/', Gdn::Request()->Domain(), Gdn::Request()->WebRoot(), 'dashboard/setup'); $Results = ProxyHead($Query, array(), 3); $CanRewrite = FALSE; if (in_array(ArrayValue('StatusCode', $Results, 404), array(200, 302)) && ArrayValue('X-Garden-Version', $Results, 'None') != 'None') { $CanRewrite = TRUE; } } catch (Exception $e) { // cURL and fsockopen arent supported... guess? $CanRewrite = function_exists('apache_get_modules') && in_array('mod_rewrite', apache_get_modules()) ? TRUE : FALSE; } SaveToConfig(array('Garden.Version' => ArrayValue('Version', GetValue('Dashboard', $ApplicationInfo, array()), 'Undefined'), 'Garden.RewriteUrls' => $CanRewrite, 'Garden.CanProcessImages' => function_exists('gd_info'), 'EnabledPlugins.GettingStarted' => 'GettingStarted', 'EnabledPlugins.HtmLawed' => 'HtmLawed')); } } return $this->Form->ErrorCount() == 0 ? TRUE : FALSE; }
/** * Fetches the location of a view into a string and returns it. Returns * false on failure. * * @param string $View The name of the view to fetch. If not specified, it will use the value * of $this->View. If $this->View is not specified, it will use the value * of $this->RequestMethod (which is defined by the dispatcher class). * @param string $ControllerName The name of the controller that owns the view if it is not $this. * - If the controller name is FALSE then the name of the current controller will be used. * - If the controller name is an empty string then the view will be looked for in the base views folder. * @param string $ApplicationFolder The name of the application folder that contains the requested controller if it is not $this->ApplicationFolder. */ public function FetchViewLocation($View = '', $ControllerName = FALSE, $ApplicationFolder = FALSE, $ThrowError = TRUE) { // Accept an explicitly defined view, or look to the method that was called on this controller if ($View == '') { $View = $this->View; } if ($View == '') { $View = $this->RequestMethod; } if ($ControllerName === FALSE) { $ControllerName = $this->ControllerName; } // Munge the controller folder onto the controller name if it is present. if ($this->ControllerFolder != '') { $ControllerName = $this->ControllerFolder . DS . $ControllerName; } if (StringEndsWith($ControllerName, 'controller', TRUE)) { $ControllerName = substr($ControllerName, 0, -10); } if (strtolower(substr($ControllerName, 0, 4)) == 'gdn_') { $ControllerName = substr($ControllerName, 4); } if (!$ApplicationFolder) { $ApplicationFolder = $this->ApplicationFolder; } //$ApplicationFolder = strtolower($ApplicationFolder); $ControllerName = strtolower($ControllerName); if (strpos($View, DS) === FALSE) { // keep explicit paths as they are. $View = strtolower($View); } // If this is a syndication request, append the method to the view if ($this->SyndicationMethod == SYNDICATION_ATOM) { $View .= '_atom'; } else { if ($this->SyndicationMethod == SYNDICATION_RSS) { $View .= '_rss'; } } $LocationName = ConcatSep('/', strtolower($ApplicationFolder), $ControllerName, $View); $ViewPath = ArrayValue($LocationName, $this->_ViewLocations, FALSE); if ($ViewPath === FALSE) { // Define the search paths differently depending on whether or not we are in a plugin or application. $ApplicationFolder = trim($ApplicationFolder, '/'); if (StringBeginsWith($ApplicationFolder, 'plugins/')) { $KeyExplode = explode('/', $ApplicationFolder); $PluginName = array_pop($KeyExplode); $PluginInfo = Gdn::PluginManager()->GetPluginInfo($PluginName); $BasePath = GetValue('SearchPath', $PluginInfo); $ApplicationFolder = GetValue('Folder', $PluginInfo); } else { $BasePath = PATH_APPLICATIONS; $ApplicationFolder = strtolower($ApplicationFolder); } $SubPaths = array(); // Define the subpath for the view. // The $ControllerName used to default to '' instead of FALSE. // This extra search is added for backwards-compatibility. if (strlen($ControllerName) > 0) { $SubPaths[] = "views/{$ControllerName}/{$View}"; } else { $SubPaths[] = "views/{$View}"; $SubPaths[] = "views/{$this->ControllerName}/{$View}"; } // Views come from one of four places: $ViewPaths = array(); foreach ($SubPaths as $SubPath) { // 1. An explicitly defined path to a view if (strpos($View, DS) !== FALSE) { $ViewPaths[] = $View; } if ($this->Theme) { // 2. Application-specific theme view. eg. /path/to/application/themes/theme_name/app_name/views/controller_name/ $ViewPaths[] = PATH_THEMES . "/{$this->Theme}/{$ApplicationFolder}/{$SubPath}.*"; // $ViewPaths[] = CombinePaths(array(PATH_THEMES, $this->Theme, $ApplicationFolder, 'views', $ControllerName, $View . '.*')); // 3. Garden-wide theme view. eg. /path/to/application/themes/theme_name/views/controller_name/ $ViewPaths[] = PATH_THEMES . "/{$this->Theme}/{$SubPath}.*"; //$ViewPaths[] = CombinePaths(array(PATH_THEMES, $this->Theme, 'views', $ControllerName, $View . '.*')); } // 4. Application/plugin default. eg. /path/to/application/app_name/views/controller_name/ $ViewPaths[] = "{$BasePath}/{$ApplicationFolder}/{$SubPath}.*"; //$ViewPaths[] = CombinePaths(array(PATH_APPLICATIONS, $ApplicationFolder, 'views', $ControllerName, $View . '.*')); } // Find the first file that matches the path. $ViewPath = FALSE; foreach ($ViewPaths as $Glob) { $Paths = SafeGlob($Glob); if (is_array($Paths) && count($Paths) > 0) { $ViewPath = $Paths[0]; break; } } //$ViewPath = Gdn_FileSystem::Exists($ViewPaths); $this->_ViewLocations[$LocationName] = $ViewPath; } // echo '<div>['.$LocationName.'] RETURNS ['.$ViewPath.']</div>'; if ($ViewPath === FALSE && $ThrowError) { trigger_error(ErrorMessage("Could not find a '{$View}' view for the '{$ControllerName}' controller in the '{$ApplicationFolder}' application.", $this->ClassName, 'FetchViewLocation'), E_USER_ERROR); } return $ViewPath; }
public function ToString($HighlightRoute = '') { if ($HighlightRoute == '') { $HighlightRoute = $this->_HighlightRoute; } if ($HighlightRoute == '') { $HighlightRoute = Gdn_Url::Request(); } $HighlightUrl = Url($HighlightRoute); // Apply a sort to the items if given. if (is_array($this->Sort)) { $Sort = array_flip($this->Sort); foreach ($this->Items as $Group => &$Item) { if (isset($Sort[$Group])) { $Item['Sort'] = $Sort[$Group]; } else { $Item['_Sort'] += count($Sort); } foreach ($Item['Links'] as $Url => &$Link) { if (isset($Sort[$Url])) { $Link['Sort'] = $Sort[$Url]; } elseif (isset($Sort[$Link['Text']])) { $Link['Sort'] = $Sort[$Link['Text']]; } else { $Link['_Sort'] += count($Sort); } } } } // Sort the groups. $this->_Compare($this->Items); uasort($this->Items, array($this, '_Compare')); // Sort the items within the groups. foreach ($this->Items as &$Item) { $this->_Compare($Item['Links']); uasort($Item['Links'], array($this, '_Compare')); // Highlight the group. if (GetValue('Url', $Item) && Url($Item['Url']) == $HighlightUrl) { $Item['Attributes']['class'] = ConcatSep(' ', GetValue('class', $Item['Attributes']), 'Active'); } // Hightlight the correct item in the group. foreach ($Item['Links'] as &$Link) { if (GetValue('Url', $Link) && Url($Link['Url']) == $HighlightUrl) { $Link['Attributes']['class'] = ConcatSep(' ', GetValue('class', $Link['Attributes']), 'Active'); $Item['Attributes']['class'] = ConcatSep(' ', GetValue('class', $Item['Attributes']), 'Active'); } } } return parent::ToString(); }
/** * Display discussions the user has bookmarked. * * @since 2.0.0 * @access public * * @param int $Offset Number of discussions to skip. */ public function Bookmarked($Page = '0') { $this->Permission('Garden.SignIn.Allow'); Gdn_Theme::Section('DiscussionList'); // Figure out which discussions layout to choose (Defined on "Homepage" settings page). $Layout = C('Vanilla.Discussions.Layout'); switch ($Layout) { case 'table': if ($this->SyndicationMethod == SYNDICATION_NONE) { $this->View = 'table'; } break; default: $this->View = 'index'; break; } // Determine offset from $Page list($Page, $Limit) = OffsetLimit($Page, C('Vanilla.Discussions.PerPage', 30)); $this->CanonicalUrl(Url(ConcatSep('/', 'discussions', 'bookmarked', PageNumber($Page, $Limit, TRUE, FALSE)), TRUE)); // Validate $Page if (!is_numeric($Page) || $Page < 0) { $Page = 0; } $DiscussionModel = new DiscussionModel(); $Wheres = array('w.Bookmarked' => '1', 'w.UserID' => Gdn::Session()->UserID); $this->DiscussionData = $DiscussionModel->Get($Page, $Limit, $Wheres); $this->SetData('Discussions', $this->DiscussionData); $CountDiscussions = $DiscussionModel->GetCount($Wheres); $this->SetData('CountDiscussions', $CountDiscussions); $this->Category = FALSE; $this->SetJson('Loading', $Page . ' to ' . $Limit); // Build a pager $PagerFactory = new Gdn_PagerFactory(); $this->EventArguments['PagerType'] = 'Pager'; $this->FireEvent('BeforeBuildBookmarkedPager'); $this->Pager = $PagerFactory->GetPager($this->EventArguments['PagerType'], $this); $this->Pager->ClientID = 'Pager'; $this->Pager->Configure($Page, $Limit, $CountDiscussions, 'discussions/bookmarked/%1$s'); if (!$this->Data('_PagerUrl')) { $this->SetData('_PagerUrl', 'discussions/bookmarked/{Page}'); } $this->SetData('_Page', $Page); $this->SetData('_Limit', $Limit); $this->FireEvent('AfterBuildBookmarkedPager'); // Deliver JSON data if necessary if ($this->_DeliveryType != DELIVERY_TYPE_ALL) { $this->SetJson('LessRow', $this->Pager->ToString('less')); $this->SetJson('MoreRow', $this->Pager->ToString('more')); $this->View = 'discussions'; } // Add modules $this->AddModule('DiscussionFilterModule'); $this->AddModule('NewDiscussionModule'); $this->AddModule('CategoriesModule'); // Render default view (discussions/bookmarked.php) $this->SetData('Title', T('My Bookmarks')); $this->SetData('Breadcrumbs', array(array('Name' => T('My Bookmarks'), 'Url' => '/discussions/bookmarked'))); $this->Render(); }
$Message = nl2br(SliceString(Gdn_Format::Text(Gdn_Format::To($Conversation->LastMessage, $Conversation->Format), FALSE), 100)); if (StringIsNullOrEmpty(trim($Message))) $Message = T('Blank Message'); $this->EventArguments['Conversation'] = $Conversation; ?> <li class="<?php echo $CssClass; ?>"> <?php $Names = ''; $PhotoUser = NULL; foreach ($Conversation->Participants as $User) { if (GetValue('UserID', $User) == Gdn::Session()->UserID) continue; $Names = ConcatSep(', ', $Names, GetValue('Name', $User)); if (!$PhotoUser && GetValue('Photo', $User)) $PhotoUser = $User; } ?> <?php if ($PhotoUser) { ?> <div class="Photo"><?php echo UserPhoto($PhotoUser); ?></div> <?php } ?> <div class="ItemContent Conversation"> <?php $Url = '/messages/'.$Conversation->ConversationID.'/#Item_'.$JumpToItem; if ($Names) { echo '<h3 class="Users">', Anchor(htmlspecialchars($Names), $Url), '</h3>'; } if ($SubjectsVisible && $Subject = GetValue('Subject', $Conversation)) {
/** * Load discussions for a specific tag. * @param DiscussionsController $Sender */ public function DiscussionsController_Tagged_Create($Sender) { Gdn_Theme::Section('DiscussionList'); $Args = $Sender->RequestArgs; $Get = array_change_key_case($Sender->Request->Get()); if ($UseCategories = C('Plugins.Tagging.UseCategories')) { // The url is in the form /category/tag/p1 $CategoryCode = GetValue(0, $Args); $Tag = GetValue(1, $Args); $Page = GetValue(2, $Args); } else { // The url is in the form /tag/p1 $CategoryCode = ''; $Tag = GetValue(0, $Args); $Page = GetValue(1, $Args); } // Look for explcit values. $CategoryCode = GetValue('category', $Get, $CategoryCode); $Tag = GetValue('tag', $Get, $Tag); $Page = GetValue('page', $Get, $Page); $Category = CategoryModel::Categories($CategoryCode); $Tag = StringEndsWith($Tag, '.rss', TRUE, TRUE); list($Offset, $Limit) = OffsetLimit($Page, C('Vanilla.Discussions.PerPage', 30)); $MultipleTags = strpos($Tag, ',') !== FALSE; $Sender->SetData('Tag', $Tag, TRUE); $TagModel = TagModel::instance(); $RecordCount = FALSE; if (!$MultipleTags) { $Tags = $TagModel->GetWhere(array('Name' => $Tag))->ResultArray(); if (count($Tags) == 0) { throw NotFoundException('Page'); } if (count($Tags) > 1) { foreach ($Tags as $TagRow) { if ($TagRow['CategoryID'] == GetValue('CategoryID', $Category)) { break; } } } else { $TagRow = array_pop($Tags); } $Tags = $TagModel->getRelatedTags($TagRow); $RecordCount = $TagRow['CountDiscussions']; $Sender->SetData('CountDiscussions', $RecordCount); $Sender->SetData('Tags', $Tags); $Sender->SetData('Tag', $TagRow); $ChildTags = $TagModel->getChildTags($TagRow['TagID']); $Sender->SetData('ChildTags', $ChildTags); } $Sender->Title(htmlspecialchars($TagRow['FullName'])); $UrlTag = rawurlencode($Tag); if (urlencode($Tag) == $Tag) { $Sender->CanonicalUrl(Url(ConcatSep('/', "/discussions/tagged/{$UrlTag}", PageNumber($Offset, $Limit, TRUE)), TRUE)); $FeedUrl = Url(ConcatSep('/', "/discussions/tagged/{$UrlTag}/feed.rss", PageNumber($Offset, $Limit, TRUE, FALSE)), '//'); } else { $Sender->CanonicalUrl(Url(ConcatSep('/', 'discussions/tagged', PageNumber($Offset, $Limit, TRUE)) . '?Tag=' . $UrlTag, TRUE)); $FeedUrl = Url(ConcatSep('/', 'discussions/tagged', PageNumber($Offset, $Limit, TRUE, FALSE), 'feed.rss') . '?Tag=' . $UrlTag, '//'); } if ($Sender->Head) { $Sender->AddJsFile('discussions.js'); $Sender->Head->AddRss($FeedUrl, $Sender->Head->Title()); } if (!is_numeric($Offset) || $Offset < 0) { $Offset = 0; } // Add Modules $Sender->AddModule('NewDiscussionModule'); $Sender->AddModule('DiscussionFilterModule'); $Sender->AddModule('BookmarkedModule'); $Sender->SetData('Category', FALSE, TRUE); $Sender->AnnounceData = FALSE; $Sender->SetData('Announcements', array(), TRUE); $DiscussionModel = new DiscussionModel(); $TagModel->SetTagSql($DiscussionModel->SQL, $Tag, $Limit, $Offset, $Sender->Request->Get('op', 'or')); $Sender->DiscussionData = $DiscussionModel->Get($Offset, $Limit, array('Announce' => 'all')); $Sender->SetData('Discussions', $Sender->DiscussionData, TRUE); $Sender->SetJson('Loading', $Offset . ' to ' . $Limit); // Build a pager. $PagerFactory = new Gdn_PagerFactory(); $Sender->Pager = $PagerFactory->GetPager('Pager', $Sender); $Sender->Pager->ClientID = 'Pager'; $Sender->Pager->Configure($Offset, $Limit, $RecordCount, ''); $Sender->View = C('Vanilla.Discussions.Layout'); /* // If these don't equal, then there is a category that should be inserted. if ($UseCategories && $Category && $TagRow['FullName'] != GetValue('Name', $Category)) { $Sender->Data['Breadcrumbs'][] = array('Name' => $Category['Name'], 'Url' => TagUrl($TagRow)); } $Sender->Data['Breadcrumbs'][] = array('Name' => $TagRow['FullName'], 'Url' => ''); */ // Render the controller. $this->View = C('Vanilla.Discussions.Layout') == 'table' ? 'table' : 'index'; $Sender->Render($this->View, 'discussions', 'vanilla'); }
public function Title($Title = '') { if ($Title != '') { // Apply $Title to $this->_Title and return it; $this->_Title = $Title; $this->_Sender->Title($Title); return $Title; } else if ($this->_Title != '') { // Return $this->_Title if set; return $this->_Title; } else { // Default Return title from controller's Data.Title + banner title; return ConcatSep(' - ', GetValueR('Data.Title', $this->_Sender, ''), C('Garden.Title')); } }
/** * Returns the XHTML for a list of checkboxes. * * @param string $FieldName Name of the field being posted with this input. * * @param mixed $DataSet Data to fill the checkbox list. Either an associative * array or a database dataset. ex: RoleID, Name from GDN_Role. * * @param mixed $ValueDataSet Values to be pre-checked in $DataSet. Either an associative array * or a database dataset. ex: RoleID from GDN_UserRole for a single user. * * @param array $Attributes An associative array of attributes for the select. Here is a list of * "special" attributes and their default values: * Attribute Options Default * ------------------------------------------------------------------------ * ValueField The name of the field in 'value' * $DataSet that contains the * option values. * TextField The name of the field in 'text' * $DataSet that contains the * option text. * * @return string */ public function CheckBoxList($FieldName, $DataSet, $ValueDataSet = NULL, $Attributes = FALSE) { // Never display individual inline errors for these CheckBoxes $Attributes['InlineErrors'] = FALSE; $Return = ''; // If the form hasn't been posted back, use the provided $ValueDataSet if ($this->IsPostBack() === FALSE) { if ($ValueDataSet === NULL) { $CheckedValues = $this->GetValue($FieldName); } else { $CheckedValues = $ValueDataSet; if (is_object($ValueDataSet)) { $CheckedValues = ConsolidateArrayValuesByKey($ValueDataSet->ResultArray(), $FieldName); } } } else { $CheckedValues = $this->GetFormValue($FieldName, array()); } $i = 1; if (is_object($DataSet)) { $ValueField = ArrayValueI('ValueField', $Attributes, 'value'); $TextField = ArrayValueI('TextField', $Attributes, 'text'); foreach ($DataSet->Result() as $Data) { $Instance = $Attributes; $Instance = RemoveKeyFromArray($Instance, array('TextField', 'ValueField')); $Instance['value'] = $Data->{$ValueField}; $Instance['id'] = $FieldName . $i; if (is_array($CheckedValues) && in_array($Data->{$ValueField}, $CheckedValues)) { $Instance['checked'] = 'checked'; } $Return .= '<li>' . $this->CheckBox($FieldName . '[]', $Data->{$TextField}, $Instance) . "</li>\n"; ++$i; } } elseif (is_array($DataSet)) { foreach ($DataSet as $Text => $ID) { // Set attributes for this instance $Instance = $Attributes; $Instance = RemoveKeyFromArray($Instance, array('TextField', 'ValueField')); $Instance['id'] = $FieldName . $i; if (is_array($ID)) { $ValueField = ArrayValueI('ValueField', $Attributes, 'value'); $TextField = ArrayValueI('TextField', $Attributes, 'text'); $Text = GetValue($TextField, $ID, ''); $ID = GetValue($ValueField, $ID, ''); } else { if (is_numeric($Text)) { $Text = $ID; } } $Instance['value'] = $ID; if (is_array($CheckedValues) && in_array($ID, $CheckedValues)) { $Instance['checked'] = 'checked'; } $Return .= '<li>' . $this->CheckBox($FieldName . '[]', $Text, $Instance) . "</li>\n"; ++$i; } } return '<ul class="' . ConcatSep(' ', 'CheckBoxList', GetValue('listclass', $Attributes)) . '">' . $Return . '</ul>'; }
/** * Default profile page. * * If current user's profile, get notifications. Otherwise show their activity (if available) or discussions. * * @since 2.0.0 * @access public * @param mixed $UserReference Unique identifier, possible ID or username. * @param string $Username. * @param int $UserID Unique ID. */ public function Index($UserReference = '', $Username = '', $UserID = '') { $this->GetUserInfo($UserReference, $Username, $UserID); if ($this->User->Admin == 2 && $this->Head) { // Don't index internal accounts. This is in part to prevent vendors from getting endless Google alerts. $this->Head->AddTag('meta', array('name' => 'robots', 'content' => 'noindex')); $this->Head->AddTag('meta', array('name' => 'googlebot', 'content' => 'noindex')); } if ($this->User->UserID == Gdn::Session()->UserID) { return $this->Notifications(); } elseif (C('Garden.Profile.ShowActivities', TRUE)) { return $this->Activity($UserReference, $Username, $UserID); } else { return Gdn::Dispatcher()->Dispatch('/profile/discussions/' . ConcatSep('/', rawurlencode($UserReference), rawurlencode($Username), rawurlencode($UserID))); } }
function DoQuote($bbcode, $action, $name, $default, $params, $content) { if ($action == BBCODE_CHECK) { return true; } if (is_string($default)) { $defaultParts = explode(';', $default); // support vbulletin style quoting. $Url = array_pop($defaultParts); if (count($defaultParts) == 0) { $params['name'] = $Url; } else { $params['name'] = implode(';', $defaultParts); $params['url'] = $Url; } } $title = ''; if (isset($params['name'])) { $username = trim($params['name']); $username = html_entity_decode($username, ENT_QUOTES, 'UTF-8'); $User = Gdn::UserModel()->GetByUsername($username); if ($User) { $UserAnchor = UserAnchor($User); } else { $UserAnchor = Anchor(htmlspecialchars($username, NULL, 'UTF-8'), '/profile/' . rawurlencode($username)); } $title = ConcatSep(' ', $title, $UserAnchor, T('Quote wrote', 'wrote')); } if (isset($params['date'])) { $title = ConcatSep(' ', $title, T('Quote on', 'on'), htmlspecialchars(trim($params['date']))); } if ($title) { $title = $title . ':'; } if (isset($params['url'])) { $url = trim($params['url']); if (is_numeric($url)) { $url = "/discussion/comment/{$url}#Comment_{$url}"; } elseif (!$bbcode->IsValidURL($url)) { $url = ''; } if ($url) { $title = ConcatSep(' ', $title, Anchor('<span class="ArrowLink">»</span>', $url, array('class' => 'QuoteLink'))); } } if ($title) { $title = "<div class=\"QuoteAuthor\">{$title}</div>"; } return "\n<blockquote class=\"Quote UserQuote\">\n" . $title . "\n<div class=\"QuoteText\">" . $content . "</div>\n</blockquote>\n"; }
/** * Write a button group control. * * @param array $Links An array of arrays with the following keys: * - Text: The text of the link. * - Url: The url of the link. * @param string|array $CssClass The css class of the link. This can be a two-item array where the second element will be added to the buttons. * @param string|false $Default The url of the default link. * @since 2.1 */ function buttonGroup($Links, $CssClass = 'Button', $Default = false) { if (!is_array($Links) || count($Links) < 1) { return; } $Text = $Links[0]['Text']; $Url = $Links[0]['Url']; $ButtonClass = ''; if (is_array($CssClass)) { list($CssClass, $ButtonClass) = $CssClass; } if ($Default && count($Links) > 1) { if (is_array($Default)) { $DefaultText = $Default['Text']; $Default = $Default['Url']; } // Find the default button. $Default = ltrim($Default, '/'); foreach ($Links as $Link) { if (StringBeginsWith(ltrim($Link['Url'], '/'), $Default)) { $Text = $Link['Text']; $Url = $Link['Url']; break; } } if (isset($DefaultText)) { $Text = $DefaultText; } } if (count($Links) < 2) { echo Anchor($Text, $Url, $CssClass); } else { // NavButton or Button? $ButtonClass = ConcatSep(' ', $ButtonClass, strpos($CssClass, 'NavButton') !== false ? 'NavButton' : 'Button'); if (strpos($CssClass, 'Primary') !== false) { $ButtonClass .= ' Primary'; } // Strip "Button" or "NavButton" off the group class. echo '<div class="ButtonGroup Multi ' . str_replace(array('NavButton', 'Button'), array('', ''), $CssClass) . '">'; echo Anchor($Text, $Url, $ButtonClass); echo '<ul class="Dropdown MenuItems">'; foreach ($Links as $Link) { echo Wrap(Anchor($Link['Text'], $Link['Url'], GetValue('CssClass', $Link, '')), 'li'); } echo '</ul>'; echo Anchor(Sprite('SpDropdownHandle', 'Sprite', T('Expand for more options.')), '#', $ButtonClass . ' Handle'); echo '</div>'; } }
/** * Save message from form submission. * * @since 2.0.0 * @access public * * @param array $FormPostValues Values submitted via form. * @return int Unique ID of message created or updated. */ public function Save($FormPostValues, $Conversation = NULL) { $Session = Gdn::Session(); // Define the primary key in this model's table. $this->DefineSchema(); // Add & apply any extra validation rules: $this->Validation->ApplyRule('Body', 'Required'); $this->AddInsertFields($FormPostValues); // Validate the form posted values $MessageID = FALSE; if ($this->Validate($FormPostValues)) { $Fields = $this->Validation->SchemaValidationFields(); // All fields on the form that relate to the schema TouchValue('Format', $Fields, C('Garden.InputFormatter', 'Html')); $MessageID = $this->SQL->Insert($this->Name, $Fields); $this->LastMessageID = $MessageID; $ConversationID = ArrayValue('ConversationID', $Fields, 0); if (!$Conversation) { $Conversation = $this->SQL->GetWhere('Conversation', array('ConversationID' => $ConversationID))->FirstRow(DATASET_TYPE_ARRAY); } // Get the new message count for the conversation. $SQLR = $this->SQL->Select('MessageID', 'count', 'CountMessages')->Select('MessageID', 'max', 'LastMessageID')->From('ConversationMessage')->Where('ConversationID', $ConversationID)->Get()->FirstRow(DATASET_TYPE_ARRAY); if (sizeof($SQLR)) { list($CountMessages, $LastMessageID) = array_values($SQLR); } else { return; } // Update the conversation's DateUpdated field. $DateUpdated = Gdn_Format::ToDateTime(); $this->SQL->Update('Conversation c')->Set('CountMessages', $CountMessages)->Set('LastMessageID', $LastMessageID)->Set('UpdateUserID', Gdn::Session()->UserID)->Set('DateUpdated', $DateUpdated)->Where('ConversationID', $ConversationID)->Put(); // Update the last message of the users that were previously up-to-date on their read messages. $this->SQL->Update('UserConversation uc')->Set('uc.LastMessageID', $MessageID)->Set('uc.DateConversationUpdated', $DateUpdated)->Where('uc.ConversationID', $ConversationID)->Where('uc.Deleted', '0')->Where('uc.CountReadMessages', $CountMessages - 1)->Where('uc.UserID <>', $Session->UserID)->Put(); // Update the date updated of the users that were not up-to-date. $this->SQL->Update('UserConversation uc')->Set('uc.DateConversationUpdated', $DateUpdated)->Where('uc.ConversationID', $ConversationID)->Where('uc.Deleted', '0')->Where('uc.CountReadMessages <>', $CountMessages - 1)->Where('uc.UserID <>', $Session->UserID)->Put(); // Update the sending user. $this->SQL->Update('UserConversation uc')->Set('uc.CountReadMessages', $CountMessages)->Set('Deleted', 0)->Set('uc.DateConversationUpdated', $DateUpdated)->Where('ConversationID', $ConversationID)->Where('UserID', $Session->UserID)->Put(); // Find users involved in this conversation $UserData = $this->SQL->Select('UserID')->Select('LastMessageID')->Select('Deleted')->From('UserConversation')->Where('ConversationID', $ConversationID)->Get()->Result(DATASET_TYPE_ARRAY); $UpdateCountUserIDs = array(); $NotifyUserIDs = array(); // Collapse for call to UpdateUserCache and ActivityModel. $InsertUserFound = FALSE; foreach ($UserData as $UpdateUser) { $LastMessageID = GetValue('LastMessageID', $UpdateUser); $UserID = GetValue('UserID', $UpdateUser); $Deleted = GetValue('Deleted', $UpdateUser); if ($UserID == GetValue('InsertUserID', $Fields)) { $InsertUserFound = TRUE; if ($Deleted) { $this->SQL->Put('UserConversation', array('Deleted' => 0, 'DateConversationUpdated' => $DateUpdated), array('ConversationID' => $ConversationID, 'UserID' => $UserID)); } } // Update unread for users that were up to date if ($LastMessageID == $MessageID) { $UpdateCountUserIDs[] = $UserID; } // Send activities to users that have not deleted the conversation if (!$Deleted) { $NotifyUserIDs[] = $UserID; } } if (!$InsertUserFound) { $UserConversation = array('UserID' => GetValue('InsertUserID', $Fields), 'ConversationID' => $ConversationID, 'LastMessageID' => $LastMessageID, 'CountReadMessages' => $CountMessages, 'DateConversationUpdated' => $DateUpdated); $this->SQL->Insert('UserConversation', $UserConversation); } if (sizeof($UpdateCountUserIDs)) { $ConversationModel = new ConversationModel(); $ConversationModel->UpdateUserUnreadCount($UpdateCountUserIDs, TRUE); } $ActivityModel = new ActivityModel(); foreach ($NotifyUserIDs as $NotifyUserID) { if ($Session->UserID == $NotifyUserID) { continue; } // don't notify self. // Notify the users of the new message. $ActivityID = $ActivityModel->Add($Session->UserID, 'ConversationMessage', '', $NotifyUserID, '', "/messages/{$ConversationID}#{$MessageID}", FALSE); $Story = GetValue('Body', $Fields, ''); if (C('Conversations.Subjects.Visible')) { $Story = ConcatSep("\n\n", GetValue('Subject', $Conversation, ''), $Story); } $ActivityModel->SendNotification($ActivityID, $Story); } } return $MessageID; }
</li> <?php if (count($this->Data('Conversations'))) { ?> <?php foreach ($this->Data('Conversations') as $Row) { $Subject = ''; if ($Row['Subject']) { $Subject = Gdn_Format::Text($Row['Subject']); } else { $Subject = ''; foreach ($Row['Participants'] as $User) { if (!isset($PhotoUser)) { $PhotoUser = $User; } $Subject = ConcatSep(', ', $Subject, FormatUsername($User, 'You')); } } if (!isset($PhotoUser)) { $PhotoUser = UserBuilder($Row, 'LastMessage'); } ?> <li class="Item" rel="<?php echo Url("/messages/{$Row['ConversationID']}#latest"); ?> "> <div class="Author Photo"><?php echo UserPhoto($PhotoUser); ?> </div> <div class="ItemContent">
<?php } ?> <td style="max-width: 200px;"> <?php $Roles = GetValue('Roles', $User, array()); $RolesString = ''; if ($User->Banned && !in_array('Banned', $Roles)) { $RolesString = T('Banned'); } if ($User->Admin > 1) { $RolesString = ConcatSep(', ', $RolesString, T('System')); } foreach ($Roles as $RoleID => $RoleName) { $Query = http_build_query(array('Keywords' => $RoleName)); $RolesString = ConcatSep(', ', $RolesString, '<a href="' . Url('/user/browse?' . $Query) . '">' . htmlspecialchars($RoleName) . '</a>'); } echo $RolesString; ?> </td> <td class="Alt"><?php echo Gdn_Format::Date($User->DateFirstVisit, 'html'); ?> </td> <td><?php echo Gdn_Format::Date($User->DateLastActive, 'html'); ?> </td> <?php if ($ViewPersonalInfo) { ?>
/** * Takes a user object, and writes out an anchor of the user's icon to the user's profile. * * @param object|array $User A user object or array. * @param array $Options */ function userPhoto($User, $Options = array()) { if (is_string($Options)) { $Options = array('LinkClass' => $Options); } if ($Px = GetValue('Px', $Options)) { $User = UserBuilder($User, $Px); } else { $User = (object) $User; } $LinkClass = ConcatSep(' ', GetValue('LinkClass', $Options, ''), 'PhotoWrap'); $ImgClass = GetValue('ImageClass', $Options, 'ProfilePhoto'); $Size = GetValue('Size', $Options); if ($Size) { $LinkClass .= " PhotoWrap{$Size}"; $ImgClass .= " {$ImgClass}{$Size}"; } else { $ImgClass .= " {$ImgClass}Medium"; // backwards compat } $FullUser = Gdn::UserModel()->GetID(GetValue('UserID', $User), DATASET_TYPE_ARRAY); $UserCssClass = GetValue('_CssClass', $FullUser); if ($UserCssClass) { $LinkClass .= ' ' . $UserCssClass; } $LinkClass = $LinkClass == '' ? '' : ' class="' . $LinkClass . '"'; $Photo = GetValue('Photo', $User); $Name = GetValue('Name', $User); $Title = htmlspecialchars(GetValue('Title', $Options, $Name)); if ($FullUser && $FullUser['Banned']) { $Photo = C('Garden.BannedPhoto', 'http://cdn.vanillaforums.com/images/banned_large.png'); $Title .= ' (' . T('Banned') . ')'; } if (!$Photo && function_exists('UserPhotoDefaultUrl')) { $Photo = UserPhotoDefaultUrl($User, $ImgClass); } if ($Photo) { if (!isUrl($Photo)) { $PhotoUrl = Gdn_Upload::Url(ChangeBasename($Photo, 'n%s')); } else { $PhotoUrl = $Photo; } $Href = Url(UserUrl($User)); return '<a title="' . $Title . '" href="' . $Href . '"' . $LinkClass . '>' . Img($PhotoUrl, array('alt' => $Name, 'class' => $ImgClass)) . '</a>'; } else { return ''; } }
public function Index($DiscussionID = '', $DiscussionStub = '', $Offset = '', $Limit = '') { $this->AddCssFile('vanilla.css'); $Session = Gdn::Session(); $this->AddJsFile('jquery.resizable.js'); $this->AddJsFile('jquery.ui.packed.js'); $this->AddJsFile('jquery.autogrow.js'); // $this->AddJsFile('jquery.gardenmorepager.js'); $this->AddJsFile('options.js'); $this->AddJsFile('bookmark.js'); $this->AddJsFile('discussion.js'); $this->AddJsFile('autosave.js'); // Load the discussion record $DiscussionID = is_numeric($DiscussionID) && $DiscussionID > 0 ? $DiscussionID : 0; $this->SetData('Discussion', $this->DiscussionModel->GetID($DiscussionID), TRUE); if (!is_object($this->Discussion)) { return Gdn::Dispatcher()->Dispatch('Default404'); } // Check Permissions $this->Permission('Vanilla.Discussions.View', TRUE, 'Category', $this->Discussion->CategoryID); $this->SetData('CategoryID', $this->CategoryID = $this->Discussion->CategoryID, TRUE); // Setup $this->Title($this->Discussion->Name); // Actual number of comments, excluding the discussion itself $ActualResponses = $this->Discussion->CountComments - 1; // Define the query offset & limit if (!is_numeric($Limit) || $Limit < 0) { $Limit = C('Vanilla.Comments.PerPage', 50); } $OffsetProvided = $Offset != ''; list($Offset, $Limit) = OffsetLimit($Offset, $Limit); // If $Offset isn't defined, assume that the user has not clicked to // view a next or previous page, and this is a "view" to be counted. if ($Offset == '') { $this->DiscussionModel->AddView($DiscussionID); } $this->Offset = $Offset; if (C('Vanilla.Comments.AutoOffset')) { if (!is_numeric($this->Offset) || $this->Offset < 0 || !$OffsetProvided) { // Round down to the appropriate offset based on the user's read comments & comments per page $CountCommentWatch = $this->Discussion->CountCommentWatch > 0 ? $this->Discussion->CountCommentWatch : 0; if ($CountCommentWatch > $ActualResponses) { $CountCommentWatch = $ActualResponses; } // (((67 comments / 10 perpage) = 6.7) rounded down = 6) * 10 perpage = offset 60; $this->Offset = floor($CountCommentWatch / $Limit) * $Limit; } if ($ActualResponses <= $Limit) { $this->Offset = 0; } if ($this->Offset == $ActualResponses) { $this->Offset -= $Limit; } } else { if ($this->Offset == '') { $this->Offset = 0; } } if ($this->Offset < 0) { $this->Offset = 0; } // Set the canonical url to have the proper page title. $this->CanonicalUrl(Url(ConcatSep('/', 'discussion/' . $this->Discussion->DiscussionID . '/' . Gdn_Format::Url($this->Discussion->Name), PageNumber($this->Offset, $Limit, TRUE)), TRUE)); // Make sure to set the user's discussion watch records $this->CommentModel->SetWatch($this->Discussion, $Limit, $this->Offset, $this->Discussion->CountComments); // Load the comments $this->SetData('CommentData', $this->CommentModel->Get($DiscussionID, $Limit, $this->Offset), TRUE); $this->SetData('Comments', $this->CommentData); // Build a pager $PagerFactory = new Gdn_PagerFactory(); $this->Pager = $PagerFactory->GetPager('Pager', $this); $this->Pager->ClientID = 'Pager'; $this->Pager->Configure($this->Offset, $Limit, $ActualResponses, 'discussion/' . $DiscussionID . '/' . Gdn_Format::Url($this->Discussion->Name) . '/%1$s'); // $this->Pager->MoreCode = '%1$s more comments'; // $this->Pager->LessCode = '%1$s older comments'; // $this->Pager->ClientID = 'Pager'; // $this->Pager->Configure( // $this->Offset, // $Limit, // $ActualResponses, // 'discussion/'.$DiscussionID.'/'.Gdn_Format::Url($this->Discussion->Name).'/%1$s/%2$s/' // ); // Define the form for the comment input $this->Form = Gdn::Factory('Form', 'Comment'); $this->Form->Action = Url('/vanilla/post/comment/'); $this->DiscussionID = $this->Discussion->DiscussionID; $this->Form->AddHidden('DiscussionID', $this->DiscussionID); $this->Form->AddHidden('CommentID', ''); // Retrieve & apply the draft if there is one: $DraftModel = new DraftModel(); $Draft = $DraftModel->Get($Session->UserID, 0, 1, $this->Discussion->DiscussionID)->FirstRow(); $this->Form->AddHidden('DraftID', $Draft ? $Draft->DraftID : ''); if ($Draft) { $this->Form->SetFormValue('Body', $Draft->Body); } // Deliver json data if necessary if ($this->_DeliveryType != DELIVERY_TYPE_ALL) { $this->SetJson('LessRow', $this->Pager->ToString('less')); $this->SetJson('MoreRow', $this->Pager->ToString('more')); $this->View = 'comments'; } // Add Modules $this->AddModule('NewDiscussionModule'); $this->AddModule('CategoriesModule'); $BookmarkedModule = new BookmarkedModule($this); $BookmarkedModule->GetData(); $this->AddModule($BookmarkedModule); $this->FireEvent('BeforeDiscussionRender'); $this->Render(); }
/** * * * @param string $Type * @return string */ public function toStringPrevNext($Type = 'more') { $this->CssClass = ConcatSep(' ', $this->CssClass, 'PrevNextPager'); $CurrentPage = PageNumber($this->Offset, $this->Limit); $Pager = ''; if ($CurrentPage > 1) { $PageParam = 'p' . ($CurrentPage - 1); $Pager .= anchor(t('Previous'), $this->PageUrl($CurrentPage - 1), 'Previous', array('rel' => 'prev')); } $HasNext = true; if ($this->CurrentRecords !== false && $this->CurrentRecords < $this->Limit) { $HasNext = false; } if ($HasNext) { $PageParam = 'p' . ($CurrentPage + 1); $Pager = ConcatSep(' ', $Pager, anchor(t('Next'), $this->PageUrl($CurrentPage + 1), 'Next', array('rel' => 'next'))); } $ClientID = $this->ClientID; $ClientID = $Type == 'more' ? $ClientID . 'After' : $ClientID . 'Before'; if (isset($this->HtmlBefore)) { $Pager = $this->HtmlBefore . $Pager; } return $Pager == '' ? '' : sprintf($this->Wrapper, Attribute(array('id' => $ClientID, 'class' => $this->CssClass)), $Pager); }
public function DiscussionController_BeforeCommentDisplay_Handler($Sender, $Args) { if (!isset($Args['Comment'])) { return; } $Comment = $Args['Comment']; if (!GetValue('Type', $Comment) == 'Whisper') { return; } $Args['CssClass'] = ConcatSep(' ', $Args['CssClass'], 'Whisper'); }
public function PathAndQuery($PathAndQuery = NULL) { // Set the path and query if it is supplied. if ($PathAndQuery) { // Parse out the path into parts. $Parts = parse_url($PathAndQuery); $Path = GetValue('path', $Parts, ''); // Check for a filename. $Filename = basename($Path); if (strpos($Filename, '.') !== FALSE) { $Path = substr($Path, 0, -strlen($Filename)); } else { $Filename = ''; } $Path = trim($Path, '/'); $Query = GetValue('query', $Parts, ''); if (strlen($Query) > 0) { $GetParts = explode('&', $Query); $Get = array(); foreach ($GetParts as $GetPart) { $GetTuple = explode('=', $GetPart); $Get[urldecode($GetTuple[0])] = urldecode(GetValue(1, $GetTuple, '')); } } else { $Get = array(); } // Set the parts of the query here. $this->_ParsedRequest['Path'] = $Path; $this->_ParsedRequest['Filename'] = $Filename; $this->_RequestArguments[self::INPUT_GET] = $Get; } // Construct the path and query. $Result = $this->Path(); $Filename = $this->Filename(); if ($Filename && $Filename != 'default') { $Result .= ConcatSep('/', $Result, $Filename); } $Get = $this->GetRequestArguments(self::INPUT_GET); if (count($Get) > 0) { $Result .= '?' . http_build_query($Get); } return $Result; }