Browse files

Merge branch 'pennyarcade' of github.com:vanillaforums/Garden into pe…

…nnyarcade
  • Loading branch information...
2 parents bde8159 + af84a0b commit caf4e2ec4eccd6a74053e743eefbe662318038c5 root committed Mar 15, 2012
Showing with 588 additions and 374 deletions.
  1. +4 −1 applications/dashboard/controllers/class.modulecontroller.php
  2. +14 −9 applications/dashboard/controllers/class.profilecontroller.php
  3. +7 −17 applications/dashboard/controllers/class.settingscontroller.php
  4. +20 −0 applications/dashboard/design/admin.css
  5. +33 −88 applications/dashboard/design/style.css
  6. +10 −4 applications/dashboard/models/class.banmodel.php
  7. +79 −27 applications/dashboard/models/class.usermodel.php
  8. +4 −1 applications/dashboard/views/activity/all.php
  9. +3 −1 applications/dashboard/views/activity/index.php
  10. +1 −1 applications/dashboard/views/entry/passwordform.php
  11. +5 −5 applications/dashboard/views/entry/registerapproval.php
  12. +5 −5 applications/dashboard/views/entry/registerbasic.php
  13. +5 −5 applications/dashboard/views/entry/registercaptcha.php
  14. +4 −4 applications/dashboard/views/entry/registerinvitation.php
  15. +15 −7 applications/dashboard/views/modules/me.php
  16. +1 −5 applications/dashboard/views/modules/profileoptions.php
  17. +1 −1 applications/dashboard/views/profile/edit.php
  18. +1 −1 applications/dashboard/views/profile/invitations.php
  19. +1 −1 applications/dashboard/views/profile/picture.php
  20. +1 −1 applications/dashboard/views/rss.master
  21. +24 −28 applications/vanilla/controllers/class.discussioncontroller.php
  22. +2 −1 applications/vanilla/js/discussion.js
  23. +0 −21 applications/vanilla/js/options.js
  24. +20 −2 applications/vanilla/models/class.discussionmodel.php
  25. +1 −1 applications/vanilla/settings/structure.php
  26. +17 −0 applications/vanilla/views/discussion/announce.php
  27. +4 −1 applications/vanilla/views/discussion/discussion.php
  28. +64 −37 applications/vanilla/views/discussion/helper_functions.php
  29. +1 −1 applications/vanilla/views/discussion/index.php
  30. +20 −4 applications/vanilla/views/discussions/helper_functions.php
  31. +4 −4 applications/vanilla/views/discussions/index_rss.php
  32. +4 −1 applications/vanilla/views/discussions/table.php
  33. +10 −3 applications/vanilla/views/post/comment.php
  34. +1 −1 conf/config-defaults.php
  35. +1 −1 index.php
  36. +18 −3 js/embed.js
  37. +23 −6 js/global.js
  38. +1 −1 library/core/authenticators/class.passwordauthenticator.php
  39. +2 −0 library/core/class.controller.php
  40. +1 −1 library/core/class.cookieidentity.php
  41. +7 −4 library/core/class.form.php
  42. +30 −12 library/core/class.format.php
  43. +5 −1 library/core/class.proxyrequest.php
  44. +11 −22 library/core/class.session.php
  45. +3 −0 library/core/functions.general.php
  46. +2 −2 library/core/functions.render.php
  47. +41 −21 plugins/Emotify/class.emotify.plugin.php
  48. +9 −0 plugins/Emotify/design/emotify.css
  49. +3 −3 plugins/Facebook/class.facebook.plugin.php
  50. +1 −1 plugins/Flagging/class.flagging.plugin.php
  51. +1 −1 plugins/GoogleSignIn/class.googlesignin.plugin.php
  52. +26 −0 plugins/HtmLawed/class.htmlawed.plugin.php
  53. +1 −1 plugins/Tagging/class.tagging.plugin.php
  54. +1 −1 plugins/Twitter/class.twitter.plugin.php
  55. +15 −4 plugins/embedvanilla/class.embedvanilla.plugin.php
View
5 applications/dashboard/controllers/class.modulecontroller.php
@@ -14,7 +14,10 @@ class ModuleController extends Gdn_Controller {
/**
* Creates and renders an instance of a module.
*/
- public function Index($Module, $AppFolder = '') {
+ public function Index($Module, $AppFolder = '', $DeliveryType = '') {
+ if (!$DeliveryType)
+ $this->DeliveryType(DELIVERY_TYPE_VIEW);
+
$ModuleClassExists = class_exists($Module);
if ($ModuleClassExists) {
View
23 applications/dashboard/controllers/class.profilecontroller.php
@@ -294,8 +294,8 @@ public function Edit($UserReference = '', $Username = '') {
}
}
- $this->Title(T('Edit My Profile'));
- $this->_SetBreadcrumbs(T('Edit My Profile'), '/profile/edit');
+ $this->Title(T('Edit Account'));
+ $this->_SetBreadcrumbs(T('Edit Account'), '/profile/edit');
$this->Render();
}
@@ -335,9 +335,12 @@ public function Index($UserReference = '', $Username = '', $UserID = '', $Page =
* @since 2.0.0
* @access public
*/
- public function Invitations() {
+ public function Invitations($UserReference = '', $Username = '', $UserID = '') {
$this->Permission('Garden.SignIn.Allow');
- $this->GetUserInfo();
+ $this->EditMode(FALSE);
+ $this->GetUserInfo($UserReference, $Username, $UserID);
+ $this->SetTabView('Invitations');
+
$InvitationModel = new InvitationModel();
$this->Form->SetModel($InvitationModel);
if ($this->Form->AuthenticatedPostBack()) {
@@ -350,8 +353,7 @@ public function Invitations() {
$Session = Gdn::Session();
$this->InvitationCount = $this->UserModel->GetInvitationCount($Session->UserID);
$this->InvitationData = $InvitationModel->GetByUserID($Session->UserID);
- $this->Title(T('My Invitations'));
- $this->_SetBreadcrumbs(T('My Invitations'), '/profile/invitations');
+
$this->Render();
}
@@ -561,7 +563,7 @@ public function Picture($UserReference = '', $Username = '') {
if ($this->Form->ErrorCount() > 0)
$this->DeliveryType(DELIVERY_TYPE_ALL);
- $this->Title(T('Change My Picture'));
+ $this->Title(T('Change Picture'));
$this->_SetBreadcrumbs(T('Change My Picture'), '/profile/picture');
$this->Render();
}
@@ -966,6 +968,7 @@ public function AddSideMenu($CurrentUrl = '') {
$SideMenu = new SideMenuModule($this);
$this->EventArguments['SideMenu'] = &$SideMenu; // Doing this out here for backwards compatibility.
if ($this->EditMode) {
+ $this->AddModule('MeModule');
$this->BuildEditMenu($SideMenu, $CurrentUrl);
$this->FireEvent('AfterAddSideMenu');
$this->AddModule($SideMenu, 'Panel');
@@ -1026,8 +1029,6 @@ public function BuildEditMenu(&$Module, $CurrentUrl = '') {
$passwordLabel = T('Set A Password');
$Module->AddLink('Options', Sprite('SpPassword').$passwordLabel, '/profile/password', FALSE, array('class' => 'Popup PasswordLink'));
}
- if (Gdn::Config('Garden.Registration.Method') == 'Invitation')
- $Module->AddLink('Options', Sprite('SpInvitations').T('My Invitations'), '/profile/invitations', FALSE, array('class' => 'Popup InvitationsLink'));
$Module->AddLink('Options', Sprite('SpPreferences').T('Notification Preferences'), '/profile/preferences/'.$this->User->UserID.'/'.Gdn_Format::Url($this->User->Name), FALSE, array('class' => 'Popup PreferencesLink'));
if ($AllowImages)
@@ -1080,6 +1081,10 @@ public function BuildProfile() {
$this->AddProfileTab($Notifications, 'profile/notifications', 'Notifications', $NotificationsHtml);
}
+ // Show invitations?
+ if (C('Garden.Registration.Method') == 'Invitation')
+ $this->AddProfileTab(T('Invitations'), 'profile/invitations', 'InvitationsLink');
+
// Show activity?
if (C('Garden.Profile.ShowActivities', TRUE))
$this->AddProfileTab(T('Activity'), $ActivityUrl, 'Activity', Sprite('SpActivity').T('Activity'));
View
24 applications/dashboard/controllers/class.settingscontroller.php
@@ -370,11 +370,6 @@ public function Email() {
// Set the model on the form.
$this->Form->SetModel($ConfigurationModel);
- // Load the locales for the locale dropdown
- $Locale = Gdn::Locale();
- $AvailableLocales = $Locale->GetAvailableLocaleSources();
- $this->LocaleData = ArrayCombine($AvailableLocales, $AvailableLocales);
-
// If seeing the form for the first time...
if ($this->Form->AuthenticatedPostBack() === FALSE) {
// Apply the config settings to the form.
@@ -385,19 +380,8 @@ public function Email() {
$ConfigurationModel->Validation->ApplyRule('Garden.Email.SupportAddress', 'Required');
$ConfigurationModel->Validation->ApplyRule('Garden.Email.SupportAddress', 'Email');
- // If changing locale, redefine locale sources:
- /*
- $NewLocale = $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);
- }
- */
-
if ($this->Form->Save() !== FALSE)
$this->InformMessage(T("Your settings have been saved."));
-
}
$this->Render();
@@ -698,6 +682,8 @@ public function Plugins($Filter = '', $PluginName = '', $TransientKey = '') {
/**
* Configuration of registration settings.
*
+ * Events: BeforeRegistrationUpdate
+ *
* @since 2.0.0
* @access public
* @param string $RedirectUrl Where to send user after registration.
@@ -778,7 +764,7 @@ public function Registration($RedirectUrl = '') {
$ConfigurationModel->Validation->ApplyRule('Garden.Registration.Method', 'Required');
// if($this->Form->GetValue('Garden.Registration.Method') != 'Closed')
// $ConfigurationModel->Validation->ApplyRule('Garden.Registration.DefaultRoles', 'RequiredArray');
-
+
if ($this->Form->GetValue('Garden.Registration.ConfirmEmail'))
$ConfigurationModel->Validation->ApplyRule('Garden.Registration.ConfirmEmailRole', 'Required');
@@ -788,6 +774,10 @@ public function Registration($RedirectUrl = '') {
$this->ExistingRoleInvitations = ArrayCombine($InvitationRoleIDs, $InvitationCounts);
$ConfigurationModel->ForceSetting('Garden.Registration.InviteRoles', $this->ExistingRoleInvitations);
+ // Event hook
+ $this->EventArguments['ConfigurationModel'] = &$ConfigurationModel;
+ $this->FireEvent('BeforeRegistrationUpdate');
+
// Save!
if ($this->Form->Save() !== FALSE) {
$this->InformMessage(T("Your settings have been saved."));
View
20 applications/dashboard/design/admin.css
@@ -398,6 +398,16 @@ a.Button {
color: transparent !important;
text-shadow: none !important;
}
+.InProgress {
+ color: transparent !Important;
+ background: url('images/progress_sm.gif') center center no-repeat !important;
+ border-color: transparent !important;
+ -moz-box-shadow: none !important;
+ -webkit-box-shadow: none !important;
+ box-shadow: none !important;
+ color: transparent !important;
+ text-shadow: none !important;
+}
/* Note: Warning, Alert & Info are simple boxes that can be used to wrap message
strings & imply importance. */
@@ -2304,4 +2314,14 @@ span.InformSprite.Dice { background-position: -442px -586px; }
height: 42px;
width: 341px;
background: url('images/welcome-message.png') top left no-repeat transparent;
+}
+.Info ul,
+.Info ol {
+ margin: 1em 0 1em 3em;
+}
+.Info ol li {
+ list-style: decimal !important;
+}
+.Info ul li {
+ list-style: disc !important;
}
View
121 applications/dashboard/design/style.css
@@ -706,14 +706,13 @@ div.Discussion:hover .OptionsTitle:hover,
position: relative;
}
.ToggleFlyout.Open {
- z-index: 100;
+ z-index: 110;
}
.ToggleFlyout .Flyout {
position: absolute;
top: 100%;
right: -10px;
display: none;
- z-index: 100;
text-align: left;
}
.OptionsMenu .Flyout {
@@ -1001,7 +1000,7 @@ a.Bookmarking:hover {
#UserOptions {
margin-bottom: 10px;
}
-a.BigButton {
+.BigButton {
text-align: center;
display: block;
cursor: pointer;
@@ -1024,14 +1023,14 @@ a.BigButton {
-moz-box-shadow: 0px 0px 2px #999;
-webkit-box-shadow: 0px 0px 2px #999;
}
-a.BigButton:hover {
+.BigButton:hover {
color: #111;
border: 1px solid #666;
box-shadow: 0px 0px 5px #aaa;
-moz-box-shadow: 0px 0px 5px #aaa;
-webkit-box-shadow: 0px 0px 5px #aaa;
}
-a.BigButton:focus {
+.BigButton:focus {
background: #eee;
box-shadow: 0px 0px 2px #999;
-moz-box-shadow: 0px 0px 2px #999;
@@ -1326,6 +1325,7 @@ blockquote {
img.LeftAlign {
float: left;
margin: 0 10px 5px 0;
+ max-width: 300px;
}
.ClearFix {
clear: both;
@@ -1439,6 +1439,10 @@ body.Profile #Panel {
float: left;
width: 250px;
} */
+
+.Profile #Panel .MeBox.NotMe .MeMenu {
+ display: none;
+}
.ChangePicture span {
position: absolute;
background: #333;
@@ -1457,7 +1461,6 @@ body.Profile #Panel {
float: right;
}
/* Hiding form headings with CSS in case the forms get popped */
-body.Profile.EditMode h2,
body.Profile.picture .SmallPopup h1 {
display: none;
}
@@ -1530,7 +1533,6 @@ table.PreferenceGroup tbody td.PrefCheckBox {
/* About in content area */
dl.About dt,
dl.About dd {
- color: #666;
padding: 0;
margin: 0;
float: none;
@@ -1539,6 +1541,7 @@ dl.About dd {
display: inline;
}
dl.About dt {
+ color: #666;
background: url('images/profile-sprites.png') 2px -139px no-repeat transparent;
padding-left: 14px;
}
@@ -1550,7 +1553,6 @@ dl.About dt.Roles { background-position: 1px -81px; }
dl.About dt.Posts { background-position: 0 -113px; }
dl.About dd {
padding: 0 8px 0 0;
- color: #333;
}
/* ======================================================== Thumbnail Cropper */
.Popup .CurrentPicture {
@@ -1677,42 +1679,32 @@ div.Popup .Border {
}
div.Popup .Body {
background: #fff;
+ padding: 10px;
}
-div.Popup .Legal,
+/*div.Popup .Legal,
div.Popup .Content form {
max-height: 440px;
overflow: auto;
padding: 0 10px 10px;
-}
+}*/
div.Popup .Loading {
text-align: center;
}
-div.Popup h1,
-div.Popup h2 {
- font-size:120%;
- font-weight:bold;
- margin: 0;
- color: #fff;
- background: #38abe3;
- padding: 6px 9px 4px;
+div.Popup h1 {
+ margin-top: 0;
}
a.Close {
position: absolute;
top: 16px;
right: 20px;
line-height: 1;
- color: #fff;
- color: rgba(255, 255, 255, 0.9);
+ color: #000;
cursor: pointer;
font-family: arial;
font-size: 22px;
font-weight: bold;
padding: 0;
}
-a.Close:hover {
- color: #fff;
- color: rgba(255, 255, 255, 1);
-}
div.Popup .Footer {
border: none;
background: none;
@@ -1970,7 +1962,8 @@ tbody td.BigCount {
padding: 8px 4px;
}
-.DataTable .Meta {
+.DataTable .Meta,
+.DataTable .MItem {
font-size: 11px;
}
@@ -2034,9 +2027,12 @@ tr.CategoryHeading td {
}
/* ================================================================= Comments */
+/*
+This should be handled by a more generic class like #Content if it is really necessary.
body.Discussion #Content {
margin-bottom: 20px;
}
+*/
/* ================================= Conversation, Discussion & Comment Forms */
.SpNewConversation,
@@ -2356,11 +2352,6 @@ body.Entry form ul li label.RadioLabel {
font-weight: normal;
width: auto;
}
-body.Entry input.DateBox,
-body.Entry input.InputBox,
-body.Entry textarea {
- width: 310px;
-}
span.Incorrect {
display: block;
color: red;
@@ -2379,47 +2370,26 @@ body#dashboard_entry_signin #Content form {
padding: 0;
text-align:left;
}*/
-body#dashboard_entry_password #Content form,
-body#dashboard_entry_signin #Content form,
-body#dashboard_entry_index #Content form,
-.SignInPopup form {
- width: 270px;
-}
.SingleEntryMethod {
width: 290px;
margin: 0 auto;
}
.MultipleEntryMethods {
width: 500px;
margin: 0 auto;
+ overflow: hidden;
+}
+.MultipleEntryMethods .MainForm {
+ float: left;
+ width: 285px;
}
.MultipleEntryMethods .Methods {
border-left: solid 1px #BEC8CC;
+ padding: 0 15px 5px;
+ line-height: 1;
+ margin-left: 300px;
}
-body#dashboard_entry_handshake #Content input.InputBox,
-body#dashboard_entry_signin #Content input.InputBox,
-body#dashboard_entry_index #Content input.InputBox,
-body#dashboard_entry_password #Content input.InputBox,
-.SignInPopup input.DateBox,
-.SignInPopup input.InputBox,
-.SignInPopup textarea {
- width: 260px;
- padding: 3px;
-}
-.SignInPopup form ul li label,
-body#dashboard_entry_signin form ul li label,
-body#dashboard_entry_index form ul li label,
-body#dashboard_entry_password form ul li label,
-body#dashboard_entry_handshake form ul li label {
- font-size: 13px;
- line-height: 1.5;
- padding: 0;
-}
-body#dashboard_entry_password #Content form ul li input#Form_Email,
-body#dashboard_entry_signin #Content form ul li input#Form_Email,
-body#dashboard_entry_index #Content form ul li input#Form_Email {
- margin-bottom: 6px;
-}
+
body#dashboard_entry_password #Content input.Password,
body#dashboard_entry_signin #Content input.Password,
body#dashboard_entry_index #Content input.Password,
@@ -2446,28 +2416,9 @@ body.Entry li.Buttons {
text-align: left;
padding: 0 0 10px;
}
-.Entry {
- position: relative;
-}
-.Methods {
- text-align: left;
- position: absolute;
- top: 33px;
- bottom: 0;
- right: 0;
- padding: 12px 20px 6px;
- line-height: 1;
- width: 170px;
-}
-body#dashboard_entry_password .Methods,
-body#dashboard_entry_signin .Methods,
-body#dashboard_entry_index .Methods {
- padding: 10px 6px 6px;
- background: none;
-}
+
.Methods .Method {
- padding: 10px 0 0;
- text-align: left;
+ margin: 5px 0;
}
/* Handshake */
@@ -2570,13 +2521,6 @@ body#dashboard_entry_index form ul li label {
font-size: 11px;
color: #777;
}
-body#dashboard_entry_password input.InputBox,
-body#dashboard_entry_signin input.InputBox,
-body#dashboard_entry_index input.InputBox,
-.Connect input.InputBox,
-.SignInPopup input.InputBox {
- padding: 3px
-}
/*.Connect .ExistingUsername,
.SignInPopup .ExistingUsername {
font-weight: bold;
@@ -2955,6 +2899,7 @@ span.InformSprite.Dice { background-position: -442px -586px; }
display: inline-block;
height: 16px;
width: 16px;
+ vertical-align: top;
}
/* 16px Sprites White */
View
14 applications/dashboard/models/class.banmodel.php
@@ -152,19 +152,23 @@ public function _BeforeGet() {
* @param bool $UpdateBlocks
* @return bool Whether user is banned.
*/
- public static function CheckUser($User, $Validation = NULL, $UpdateBlocks = FALSE) {
+ public static function CheckUser($User, $Validation = NULL, $UpdateBlocks = FALSE, &$BansFound = NULL) {
$Bans = self::AllBans();
$Fields = array('Name' => 'Name', 'Email' => 'Email', 'IPAddress' => 'LastIPAddress');
$Banned = array();
+
+ if (!$BansFound)
+ $BansFound = array();
foreach ($Bans as $Ban) {
// Convert ban to regex.
$Parts = explode('*', $Ban['BanValue']);
$Parts = array_map('preg_quote', $Parts);
- $Regex = '`'.implode('.*', $Parts).'`i';
+ $Regex = '`^'.implode('.*', $Parts).'$`i';
if (preg_match($Regex, GetValue($Fields[$Ban['BanType']], $User))) {
$Banned[$Ban['BanType']] = TRUE;
+ $BansFound[] = $Ban;
if ($UpdateBlocks) {
Gdn::SQL()
@@ -177,8 +181,10 @@ public static function CheckUser($User, $Validation = NULL, $UpdateBlocks = FALS
}
// Add the validation results.
- foreach ($Banned as $BanType => $Value) {
- $Validation->AddValidationResult($BanType, 'ValidateBanned');
+ if ($Validation) {
+ foreach ($Banned as $BanType => $Value) {
+ $Validation->AddValidationResult($BanType, 'ValidateBanned');
+ }
}
return count($Banned) == 0;
}
View
106 applications/dashboard/models/class.usermodel.php
@@ -1626,50 +1626,85 @@ public function AddInsertFields(&$Fields) {
$Fields[$this->DateInserted] = $Now;
$Fields['DateFirstVisit'] = $Now;
$Fields['DateLastActive'] = $Now;
+ $Fields['InsertIPAddress'] = Gdn::Request()->IpAddress();
+ $Fields['LastIPAddress'] = Gdn::Request()->IpAddress();
}
/**
- * Update last visit.
- *
- * Regenerates other related user properties.
+ * Updates visit level information such as date last active and the user's ip address.
*
* @param int $UserID
- * @param array $Attributes
* @param string|int|float $ClientHour
*/
- function UpdateLastVisit($UserID, $Attributes, $ClientHour='') {
+ function UpdateVisit($UserID, $ClientHour = FALSE) {
$UserID = (int) $UserID;
if (!$UserID) {
- throw new Exception('A valid UserId is required.');
+ throw new Exception('A valid User ID is required.');
}
-// $User = Gdn::UserModel()->GetID($UserID, DATASET_TYPE_ARRAY);
-// $AllIPs = GetValue('AllIPAddresses', $User, array());
- $IP = Gdn::Request()->IpAddress();
-// if (!in_array($IP, $AllIPs)) {
-// $AllIPs[] = $IP;
-// SetValue('AllIPAddresses', $User, $AllIPs);
-// }
-
$User = Gdn::UserModel()->GetID($UserID, DATASET_TYPE_ARRAY);
- $Fields = array(
- 'DateLastActive' => Gdn_Format::ToDateTime(),
- 'LastIPAddress' => $IP,
- 'CountVisits' => GetValue('CountVisits', $User, 0) + 1);
-
- if (isset($Attributes) && is_array($Attributes)) {
- // Generate a new transient key for the user (used to authenticate postbacks).
- $Attributes['TransientKey'] = RandomString(12);
- $Fields['Attributes'] = serialize($Attributes);
+
+ $Fields = array();
+
+ if (Gdn_Format::ToTimestamp($User['DateLastActive']) < strtotime('5 minutes ago')) {
+ // We only update the last active date once every 5 minutes to cut down on DB activity.
+ $Fields['DateLastActive'] = Gdn_Format::ToDateTime();
}
+
+ // Update session level information if necessary.
+ if ($UserID == Gdn::Session()->UserID) {
+ $IP = Gdn::Request()->IpAddress();
+ $Fields['LastIPAddress'] = $IP;
+
+ if (Gdn::Session()->NewVisit()) {
+ $Fields['CountVisits'] = GetValue('CountVisits', $User, 0) + 1;
+ }
+ }
+
+ // Generate the AllIPs field.
+ $AllIPs = GetValue('AllIPAddresses', $User, array());
+ if (is_string($AllIPs)) {
+ $AllIPs = explode(',', $AllIPs);
+ SetValue('AllIPAddresses', $User, $AllIPs);
+ }
+ if (!is_array($AllIPs))
+ $AllIPs = array();
+ if ($IP = GetValue('InsertIPAddress', $User))
+ $AllIPs[] = $IP;
+ if ($IP = GetValue('LastIPAddress', $User))
+ $AllIPs[] = $IP;
+ $AllIPs = array_unique($AllIPs);
+ sort($AllIPs);
+ $Fields['AllIPAddresses'] = $AllIPs;
// Set the hour offset based on the client's clock.
if (is_numeric($ClientHour) && $ClientHour >= 0 && $ClientHour < 24) {
$HourOffset = $ClientHour - date('G', time());
- $this->SQL->Set('HourOffset', $HourOffset);
+ $Fields['HourOffset'] = $HourOffset;
+ }
+
+ // See if the fields have changed.
+ $Changed = FALSE;
+ foreach ($Fields as $Name => $Value) {
+ if (GetValue($Name, $User) != $Value) {
+ $Changed = TRUE;
+ break;
+ }
+ }
+
+ if ($Changed) {
+ $this->SetField($UserID, $Fields);
+ }
+
+ if ($User['LastIPAddress'] != $Fields['LastIPAddress']) {
+ $User = $this->GetID($UserID, DATASET_TYPE_ARRAY);
+ if (!BanModel::CheckUser($User, NULL, TRUE, $Bans)) {
+ $BanModel = new BanModel();
+ $Ban = array_pop($Bans);
+ $BanModel->SaveUser($User, TRUE, $Ban);
+ $BanModel->SetCounts($Ban);
+ }
}
-
- $this->SQL->Where('UserID', $UserID)->Put();
}
/**
@@ -2282,7 +2317,12 @@ public function SetCalculatedFields(&$User) {
SetValue('PhotoUrl', $User, $PhotoUrl);
}
if ($v = GetValue('AllIPAddresses', $User)) {
- SetValue('AllIPAddresses', $User, explode(',', $v));
+ $IPAddresses = explode(',', $v);
+ foreach ($IPAddresses as $i => $IPAddress) {
+ if (strpos($IPAddress, '.') === FALSE)
+ $IPAddresses[$i] = long2ip(hexdec($IPAddress));
+ }
+ SetValue('AllIPAddresses', $User, $IPAddresses);
}
}
@@ -2612,6 +2652,18 @@ public function PasswordReset($UserID, $Password) {
}
public function SetField($RowID, $Property, $Value = FALSE) {
+ if (!is_array($Property))
+ $Property = array($Property => $Value);
+
+ // Convert IP addresses to long.
+ if (isset($Property['AllIPAddresses'])) {
+// foreach ($Property['AllIPAddresses'] as &$IP) {
+// if (strpos($IP, '.') !== FALSE)
+// $IP = dechex(ip2long($IP));
+// }
+ $Property['AllIPAddresses'] = implode(',', $Property['AllIPAddresses']);
+ }
+
$this->SQL
->Update($this->Name)
->Set($Property, $Value)
View
5 applications/dashboard/views/activity/all.php
@@ -20,7 +20,10 @@
$Activities = $this->Data('Activities', array());
if (count($Activities) > 0) {
include($this->FetchViewLocation('activities', 'activity', 'dashboard'));
- echo PagerModule::Write(array('CurrentRecords' => count($Activities)));
+
+ echo '<div class="P">';
+ PagerModule::Write(array('CurrentRecords' => count($Activities)));
+ echo '</div>';
} else {
?>
<li><div class="Empty"><?php echo T('Not much happening here, yet.'); ?></div></li>
View
4 applications/dashboard/views/activity/index.php
@@ -2,7 +2,9 @@
echo '<ul class="DataList Activities">';
if (count($this->Data('Activities')) > 0) {
include($this->FetchViewLocation('activities', 'activity', 'dashboard'));
- echo PagerModule::Write(array('CurrentRecords' => count($this->Data('Activities'))));
+ echo '<div class="P">';
+ PagerModule::Write(array('CurrentRecords' => count($this->Data('Activities'))));
+ echo '</div>';
} else {
?>
<li><div class="Empty"><?php echo T('Not much happening here, yet.'); ?></div></li>
View
2 applications/dashboard/views/entry/passwordform.php
@@ -10,7 +10,7 @@
<li>
<?php
echo $this->Form->Label('Email/Username', 'Email');
- echo $this->Form->TextBox('Email', array('autocorrect' => 'off', 'autocapitalize' => 'off'));
+ echo $this->Form->TextBox('Email', array('autocorrect' => 'off', 'autocapitalize' => 'off', 'Wrap' => TRUE));
?>
</li>
<li>
View
10 applications/dashboard/views/entry/registerapproval.php
@@ -15,28 +15,28 @@
<li>
<?php
echo $this->Form->Label('Email', 'Email');
- echo $this->Form->TextBox('Email');
+ echo $this->Form->TextBox('Email', array('type' => 'email', 'Wrap' => TRUE));
echo '<span id="EmailUnavailable" class="Incorrect" style="display: none;">'.T('Email Unavailable').'</span>';
?>
</li>
<li>
<?php
echo $this->Form->Label('Username', 'Name');
- echo $this->Form->TextBox('Name');
+ echo $this->Form->TextBox('Name', array('Wrap' => TRUE));
echo '<span id="NameUnavailable" class="Incorrect" style="display: none;">'.T('Name Unavailable').'</span>';
?>
</li>
<?php $this->FireEvent('RegisterBeforePassword'); ?>
<li>
<?php
echo $this->Form->Label('Password', 'Password');
- echo $this->Form->Input('Password', 'password');
+ echo $this->Form->Input('Password', 'password', array('Wrap' => TRUE));
?>
</li>
<li>
<?php
echo $this->Form->Label('Confirm Password', 'PasswordMatch');
- echo $this->Form->Input('PasswordMatch', 'password');
+ echo $this->Form->Input('PasswordMatch', 'password', array('Wrap' => TRUE));
echo '<span id="PasswordsDontMatch" class="Incorrect" style="display: none;">'.T("Passwords don't match").'</span>';
?>
</li>
@@ -49,7 +49,7 @@
<li>
<?php
echo $this->Form->Label('Why do you want to join?', 'DiscoveryText');
- echo $this->Form->TextBox('DiscoveryText', array('MultiLine' => TRUE));
+ echo $this->Form->TextBox('DiscoveryText', array('MultiLine' => TRUE, 'Wrap' => TRUE));
?>
</li>
<?php $this->FireEvent('RegisterBeforeTerms'); ?>
View
10 applications/dashboard/views/entry/registerbasic.php
@@ -14,28 +14,28 @@
<li>
<?php
echo $this->Form->Label('Email', 'Email');
- echo $this->Form->TextBox('Email', array('type' => 'email'));
+ echo $this->Form->TextBox('Email', array('type' => 'email', 'Wrap' => TRUE));
echo '<span id="EmailUnavailable" class="Incorrect" style="display: none;">'.T('Email Unavailable').'</span>';
?>
</li>
<li>
<?php
echo $this->Form->Label('Username', 'Name');
- echo $this->Form->TextBox('Name', array('autocorrect' => 'off', 'autocapitalize' => 'off'));
+ echo $this->Form->TextBox('Name', array('Wrap' => TRUE, 'autocorrect' => 'off', 'autocapitalize' => 'off'));
echo '<span id="NameUnavailable" class="Incorrect" style="display: none;">'.T('Name Unavailable').'</span>';
?>
</li>
<?php $this->FireEvent('RegisterBeforePassword'); ?>
<li>
<?php
echo $this->Form->Label('Password', 'Password');
- echo $this->Form->Input('Password', 'password');
+ echo $this->Form->Input('Password', 'password', array('Wrap' => TRUE));
?>
</li>
<li>
<?php
echo $this->Form->Label('Confirm Password', 'PasswordMatch');
- echo $this->Form->Input('PasswordMatch', 'password');
+ echo $this->Form->Input('PasswordMatch', 'password', array('Wrap' => TRUE));
echo '<span id="PasswordsDontMatch" class="Incorrect" style="display: none;">'.T("Passwords don't match").'</span>';
?>
</li>
@@ -49,7 +49,7 @@
<li>
<?php
echo $this->Form->Label('Why do you want to join?', 'DiscoveryText');
- echo $this->Form->TextBox('DiscoveryText', array('MultiLine' => TRUE));
+ echo $this->Form->TextBox('DiscoveryText', array('MultiLine' => TRUE, 'Wrap' => TRUE));
?>
</li>
<?php endif; ?>
View
10 applications/dashboard/views/entry/registercaptcha.php
@@ -18,28 +18,28 @@
<li>
<?php
echo $this->Form->Label('Email', 'Email');
- echo $this->Form->TextBox('Email', array('type' => 'email'));
+ echo $this->Form->TextBox('Email', array('type' => 'email', 'Wrap' => TRUE));
echo '<span id="EmailUnavailable" class="Incorrect" style="display: none;">'.T('Email Unavailable').'</span>';
?>
</li>
<li>
<?php
echo $this->Form->Label('Username', 'Name');
- echo $this->Form->TextBox('Name', array('autocorrect' => 'off', 'autocapitalize' => 'off'));
+ echo $this->Form->TextBox('Name', array('autocorrect' => 'off', 'autocapitalize' => 'off', 'Wrap' => TRUE));
echo '<span id="NameUnavailable" class="Incorrect" style="display: none;">'.T('Name Unavailable').'</span>';
?>
</li>
<?php $this->FireEvent('RegisterBeforePassword'); ?>
<li>
<?php
echo $this->Form->Label('Password', 'Password');
- echo $this->Form->Input('Password', 'password');
+ echo $this->Form->Input('Password', 'password', array('Wrap' => TRUE));
?>
</li>
<li>
<?php
echo $this->Form->Label('Confirm Password', 'PasswordMatch');
- echo $this->Form->Input('PasswordMatch', 'password');
+ echo $this->Form->Input('PasswordMatch', 'password', array('Wrap' => TRUE));
echo '<span id="PasswordsDontMatch" class="Incorrect" style="display: none;">'.T("Passwords don't match").'</span>';
?>
</li>
@@ -53,7 +53,7 @@
<li>
<?php
echo $this->Form->Label('Why do you want to join?', 'DiscoveryText');
- echo $this->Form->TextBox('DiscoveryText', array('MultiLine' => TRUE));
+ echo $this->Form->TextBox('DiscoveryText', array('MultiLine' => TRUE, 'Wrap' => TRUE));
?>
</li>
<?php endif; ?>
View
8 applications/dashboard/views/entry/registerinvitation.php
@@ -15,27 +15,27 @@
<li>
<?php
echo $this->Form->Label('Invitation Code', 'InvitationCode');
- echo $this->Form->TextBox('InvitationCode', array('value' => $this->InvitationCode, 'autocorrect' => 'off', 'autocapitalize' => 'off'));
+ echo $this->Form->TextBox('InvitationCode', array('value' => $this->InvitationCode, 'autocorrect' => 'off', 'autocapitalize' => 'off', 'Wrap' => TRUE));
?>
</li>
<li>
<?php
echo $this->Form->Label('Username', 'Name');
- echo $this->Form->TextBox('Name', array('autocorrect' => 'off', 'autocapitalize' => 'off'));
+ echo $this->Form->TextBox('Name', array('autocorrect' => 'off', 'autocapitalize' => 'off', 'Wrap' => TRUE));
echo '<span id="NameUnavailable" class="Incorrect" style="display: none;">'.T('Name Unavailable').'</span>';
?>
</li>
<?php $this->FireEvent('RegisterBeforePassword'); ?>
<li>
<?php
echo $this->Form->Label('Password', 'Password');
- echo $this->Form->Input('Password', 'password');
+ echo $this->Form->Input('Password', 'password', array('Wrap' => TRUE));
?>
</li>
<li>
<?php
echo $this->Form->Label('Confirm Password', 'PasswordMatch');
- echo $this->Form->Input('PasswordMatch', 'password');
+ echo $this->Form->Input('PasswordMatch', 'password', array('Wrap' => TRUE));
echo '<span id="PasswordsDontMatch" class="Incorrect" style="display: none;">'.T("Passwords don't match").'</span>';
?>
</li>
View
22 applications/dashboard/views/modules/me.php
@@ -1,20 +1,28 @@
<?php if (!defined('APPLICATION')) exit();
$Session = Gdn::Session();
+$User = $Session->User;
-if ($Session->IsValid()):
- echo '<div class="MeBox">';
+if (property_exists($this->_Sender, 'User'))
+ $User = $this->_Sender->User;
+if ($Session->IsValid()):
+
+ $NotMe = '';
+ if ($User->UserID != Gdn::Session()->UserID)
+ $NotMe = 'NotMe';
+
+ echo "<div class=\"MeBox {$NotMe}\">";
- $Name = $Session->User->Name;
+ $Name = $User->Name;
- echo UserPhoto($Session->User);
+ echo UserPhoto($User);
echo '<div class="WhoIs">';
- echo UserAnchor($Session->User, 'Username');
+ echo UserAnchor($User, 'Username');
echo '<div class="MeMenu">';
// Notifications
- $CountNotifications = $Session->User->CountNotifications;
+ $CountNotifications = $User->CountNotifications;
$CNotifications = is_numeric($CountNotifications) && $CountNotifications > 0 ? '<span class="Alert">'.$CountNotifications.'</span>' : '';
- $ProfileSlug = urlencode($Session->User->Name) == $Session->User->Name ? $Session->User->Name : $Session->UserID.'/'.urlencode($Session->User->Name);
+ $ProfileSlug = urlencode($User->Name) == $User->Name ? $User->Name : $UserID.'/'.urlencode($User->Name);
echo Anchor(Sprite('SpNotifications', 'Sprite16').Wrap(T('Notifications'), 'em').$CNotifications, '/profile/'.$ProfileSlug, array('title' => T('Notifications')));
// Inbox
View
6 applications/dashboard/views/modules/profileoptions.php
@@ -6,7 +6,7 @@
<?php
$Controller->FireEvent('BeforeProfileOptions');
if ($Controller->EditMode) {
- echo UserAnchor($Controller->User, 'Button', array('Text' => T('Back to Profile')));
+ echo UserAnchor($Controller->User, 'BackToProfile Button', array('Text' => T('Back to Profile')));
} else {
$Session = Gdn::Session();
@@ -29,7 +29,3 @@
$Controller->FireEvent('AfterProfileOptions');
?>
</div>
-<?php
-if ($Controller->EditMode)
- echo Wrap(sprintf(T('Edit Profile: %s'), htmlentities($Controller->User->Name)), 'h1');
-
View
2 applications/dashboard/views/profile/edit.php
@@ -1,5 +1,5 @@
<?php if (!defined('APPLICATION')) exit(); ?>
-<h2><?php echo T('Edit My Account'); ?></h2>
+<h2><?php echo $this->Data('Title'); ?></h2>
<?php
echo $this->Form->Open();
echo $this->Form->Errors();
View
2 applications/dashboard/views/profile/invitations.php
@@ -1,5 +1,5 @@
<?php if (!defined('APPLICATION')) exit(); ?>
-<h2><?php echo T('My Invitations'); ?></h2>
+<h2><?php echo T('Invitations'); ?></h2>
<?php
echo $this->Form->Open();
echo $this->Form->Errors();
View
2 applications/dashboard/views/profile/picture.php
@@ -27,7 +27,7 @@
$Thumbnail = Img($Thumbnail, array('alt' => T('Thumbnail')));
?>
<div class="SmallPopup">
-<h1><?php echo T('Change My Picture'); ?></h1>
+<h2><?php echo $this->Data('Title'); ?></h2>
<?php
echo $this->Form->Open(array('enctype' => 'multipart/form-data'));
echo $this->Form->Errors();
View
2 applications/dashboard/views/rss.master
@@ -7,7 +7,7 @@
<channel>
<title><?php echo $this->Head->Title(); ?></title>
<link><?php echo htmlspecialchars(Url('', TRUE, TRUE)); ?></link>
- <pubDate><?php echo date(DATE_RFC822); ?></pubDate>
+ <pubDate><?php echo date('r'); ?></pubDate>
<?php
$this->RenderAsset('RssHead');
View
52 applications/vanilla/controllers/class.discussioncontroller.php
@@ -416,37 +416,33 @@ public function Bookmark($DiscussionID = '', $TransientKey = '') {
* @param int $DiscussionID Unique discussion ID.
* @param string $TransientKey Single-use hash to prove intent.
*/
- public function Announce($DiscussionID = '', $TransientKey = '') {
- $this->_DeliveryType = DELIVERY_TYPE_BOOL;
- $Session = Gdn::Session();
- $State = FALSE;
- if (
- is_numeric($DiscussionID)
- && $DiscussionID > 0
- && $Session->UserID > 0
- && $Session->ValidateTransientKey($TransientKey)
- ) {
- $Discussion = $this->DiscussionModel->GetID($DiscussionID);
- if ($Discussion && $Session->CheckPermission('Vanilla.Discussions.Announce', TRUE, 'Category', $Discussion->PermissionCategoryID)) {
-
- $CacheKeys = array('Announcements', 'Announcements_'.GetValue('CategoryID', $Discussion));
-
- $Announce = GetValue('Announce', $Discussion);
- $this->DiscussionModel->SQL->Cache($CacheKeys);
- $this->DiscussionModel->SetProperty($DiscussionID, 'Announce', (int)!$Announce);
- } else {
- $this->Form->AddError('ErrPermission');
- }
+ public function Announce($DiscussionID = '', $Target = '') {
+ $Discussion = $this->DiscussionModel->GetID($DiscussionID);
+ if (!$Discussion)
+ throw NotFoundException('Discussion');
+ $this->Permission('Vanilla.Discussions.Announce', TRUE, 'Category', $Discussion->PermissionCategoryID);
+
+ if ($this->Form->IsPostBack()) {
+ // Save the property.
+ $CacheKeys = array('Announcements', 'Announcements_'.GetValue('CategoryID', $Discussion));
+ $this->DiscussionModel->SQL->Cache($CacheKeys);
+ $this->DiscussionModel->SetProperty($DiscussionID, 'Announce', (int)$this->Form->GetFormValue('Announce', 0));
+
+ if ($Target)
+ $this->RedirectUrl = Url($Target);
+ } else {
+ if (!$Discussion->Announce)
+ $Discussion->Announce = 2;
+ $this->Form->SetData($Discussion);
}
- $Target = $this->Request->Get('Target', 'discussions');
+ $Discussion = (array)$Discussion;
+ $Category = CategoryModel::Categories($Discussion['CategoryID']);
- // Redirect to the front page
- if ($this->_DeliveryType === DELIVERY_TYPE_ALL)
- Redirect($Target);
-
- $this->RedirectUrl = Url($Target);
- $this->InformMessage(T('Your changes have been saved.'));
+ $this->SetData('Discussion', $Discussion);
+ $this->SetData('Category', $Category);
+
+ $this->Title(T('Announce'));
$this->Render();
}
View
3 applications/vanilla/js/discussion.js
@@ -369,7 +369,8 @@ jQuery(document).ready(function($) {
else
$('.DataList .AdminCheck :checkbox').removeAttr('checked');
});
- $('.AdminCheck :checkbox').click(function() {
+ $('.AdminCheck :checkbox').click(function(e) {
+ e.stopPropagation();
// retrieve all checked ids
var checkIDs = $('.DataList .AdminCheck :checkbox');
var aCheckIDs = new Array();
View
21 applications/vanilla/js/options.js
@@ -27,27 +27,6 @@ jQuery(document).ready(function($) {
});
return false;
});
-
- // 2. Announce discussion
- $('a.AnnounceDiscussion').livequery('click', function() {
- var btn = this;
- var row = $(btn).parents('li.Item');
- $.ajax({
- type: "POST",
- url: $(btn).attr('href'),
- data: 'DeliveryType=BOOL&DeliveryMethod=JSON',
- dataType: 'json',
- error: function(XMLHttpRequest, textStatus, errorThrown) {
- $.popup({}, XMLHttpRequest.responseText);
- },
- success: function(json) {
- gdn.inform(json);
- if (json.RedirectUrl)
- setTimeout("document.location='" + json.RedirectUrl + "';", 300);
- }
- });
- return false;
- });
// 3. Sink discussion
$('a.SinkDiscussion').popup({
View
22 applications/vanilla/models/class.discussionmodel.php
@@ -223,7 +223,12 @@ public function RemoveAnnouncements($Data) {
$Unset = FALSE;
foreach($Result as $Key => &$Discussion) {
- if ($Discussion->Announce == 1 && $Discussion->Dismissed == 0) {
+ if (isset($this->_AnnouncementIDs)) {
+ if (in_array($Discussion->DiscussionID, $this->_AnnouncementIDs)) {
+ unset($Result[$Key]);
+ $Unset = TRUE;
+ }
+ } elseif ($Discussion->Announce == 1 && $Discussion->Dismissed == 0) {
// Unset discussions that are announced and not dismissed
unset($Result[$Key]);
$Unset = TRUE;
@@ -341,7 +346,7 @@ public function GetAnnouncements($Wheres = '') {
->Cache($CacheKey)
->Select('d.DiscussionID')
->From('Discussion d')
- ->Where('d.Announce', '1');
+ ->Where('d.Announce >', '0');
if (is_array($Wheres) && count($Wheres) > 0)
$this->SQL->Where($Wheres);
@@ -374,6 +379,11 @@ public function GetAnnouncements($Wheres = '') {
// ->Where('d.Announce', '1');
$this->SQL->WhereIn('d.DiscussionID', $AnnouncementIDs);
+
+ // If we aren't viewing announcements in a category then only show global announcements.
+ if (!$Wheres) {
+ $this->SQL->Where('d.Announce', 1);
+ }
// If we allow users to dismiss discussions, skip ones this user dismissed
if (C('Vanilla.Discussions.Dismiss', 1) && $UserID) {
@@ -386,6 +396,13 @@ public function GetAnnouncements($Wheres = '') {
->Limit($Limit, $Offset);
$Data = $this->SQL->Get();
+
+ // Save the announcements that were fetched for later removal.
+ $AnnouncementIDs = array();
+ foreach ($Data as $Row) {
+ $AnnouncementIDs[] = GetValue('DiscussionID', $Row);
+ }
+ $this->_AnnouncementIDs = $AnnouncementIDs;
$this->AddDiscussionColumns($Data);
@@ -604,6 +621,7 @@ public function GetID($DiscussionID) {
if (!$Data)
return $Data;
+ $Data->Name = Gdn_Format::Text($Data->Name);
$Data->Attributes = @unserialize($Data->Attributes);
$Data->Url = Url('/discussion/'.$Data->DiscussionID.'/'.Gdn_Format::Url($Data->Name), TRUE);
View
2 applications/vanilla/settings/structure.php
@@ -409,7 +409,7 @@
if (!$DateInsertedExists) {
$SQL->Update('TagDiscussion td')
->Join('Discussion d', 'td.DiscussionID = d.DiscussionID')
- ->Set('td.DateInserted', 'd.DateInserted')
+ ->Set('td.DateInserted', 'd.DateInserted', FALSE, FALSE)
->Put();
}
View
17 applications/vanilla/views/discussion/announce.php
@@ -0,0 +1,17 @@
+<?php if (!defined('APPLICATION')) exit(); ?>
+
+<h1><?php echo $this->Data('Title'); ?></h1>
+
+<?php
+echo $this->Form->Open();
+echo $this->Form->Errors();
+
+echo '<div class="P">'.T('Where do you want to announce this discussion?').'</div>';
+
+echo '<div class="P">', $this->Form->Radio('Announce', sprintf('In <b>%s.</b>', $this->Data('Category.Name')), array('Value' => '2')), '</div>';
+echo '<div class="P">', $this->Form->Radio('Announce', sprintf('In <b>%s</b> and recent discussions.', $this->Data('Category.Name')), array('Value' => '1')), '</div>';
+echo '<div class="P">', $this->Form->Radio('Announce', "Don't announce.", array('Value' => '0')), '</div>';
+
+echo $this->Form->Button('OK');
+echo $this->Form->Close();
+?>
View
5 applications/vanilla/views/discussion/discussion.php
@@ -45,5 +45,8 @@
echo FormatBody($Discussion);
?>
</div>
- <?php $this->FireEvent('AfterDiscussionBody'); ?>
+ <?php
+ $this->FireEvent('AfterDiscussionBody');
+ WriteReactions($Discussion);
+ ?>
</div>
View
101 applications/vanilla/views/discussion/helper_functions.php
@@ -13,6 +13,10 @@ function CssClass($Object, $CurrentOffset = 0) {
$CssClass = 'Item Item'.$Type;
$CssClass .= (GetValue('InsertUserID', $Object) == Gdn::Session()->UserID) ? ' Mine' : '';
+ if ($_CssClss = GetValue('_CssClass', $Object)) {
+ $CssClass .= ' '.$_CssClss;
+ }
+
if ($Type == 'Comment')
$CssClass .= ($CurrentOffset % 2) ? ' Alt' : '';
@@ -75,6 +79,7 @@ function WriteComment($Comment, $Sender, $Session, $CurrentOffset) {
$Sender->CanEditComments = $Session->CheckPermission('Vanilla.Comments.Edit', TRUE, 'Category', 'any') && C('Vanilla.AdminCheckboxes.Use');
// Prep event args
+ $CssClass = CssClass($Comment, $CurrentOffset);
$Sender->EventArguments['Comment'] = &$Comment;
$Sender->EventArguments['Author'] = &$Author;
$Sender->EventArguments['CssClass'] = &$CssClass;
@@ -85,54 +90,76 @@ function WriteComment($Comment, $Sender, $Session, $CurrentOffset) {
// First comment template event
$Sender->FireEvent('BeforeCommentDisplay'); ?>
-<li class="<?php echo CssClass($Comment, $CurrentOffset); ?>" id="<?php echo 'Comment_'.$Comment->CommentID; ?>">
+<li class="<?php echo $CssClass; ?>" id="<?php echo 'Comment_'.$Comment->CommentID; ?>">
<div class="Comment">
- <div class="Meta">
- <?php $Sender->FireEvent('BeforeCommentMeta'); ?>
- <span class="Author">
- <?php
- echo UserPhoto($Author);
- echo UserAnchor($Author);
- ?>
- </span>
- <span class="MItem DateCreated">
- <?php echo Anchor(Gdn_Format::Date($Comment->DateInserted, 'html'), $Permalink, 'Permalink', array('name' => 'Item_'.($CurrentOffset), 'rel' => 'nofollow')); ?>
- </span>
+ <?php $Sender->FireEvent('BeforeCommentMeta'); ?>
+ <span class="Author">
<?php
- // Include source if one was set
- if ($Source = GetValue('Source', $Comment))
- echo Wrap(sprintf(T('via %s'), T($Source.' Source', $Source)), 'span', array('class' => 'MItem Source'));
-
- // Add your own options or data as spans with 'MItem' class
- $Sender->FireEvent('InsideCommentMeta');
-
- ?>
- <div class="Options">
- <?php WriteCommentOptions($Comment); ?>
- </div>
- <div class="CommentInfo">
+ echo UserPhoto($Author);
+ echo UserAnchor($Author, 'Username');
+ ?>
+ </span>
+
+ <div class="Item-BodyWrap">
+ <div class="Meta">
+ <span class="MItem DateCreated">
+ <?php echo Anchor(Gdn_Format::Date($Comment->DateInserted, 'html'), $Permalink, 'Permalink', array('name' => 'Item_'.($CurrentOffset), 'rel' => 'nofollow')); ?>
+ </span>
<?php
- $Sender->FireEvent('CommentInfo');
-
- // Include IP Address if we have permission
- if ($Session->CheckPermission('Garden.Moderation.Manage'))
- echo Wrap(IPAnchor($Comment->InsertIPAddress), 'span', array('class' => 'MItem IPAddress'));
+ // Include source if one was set
+ if ($Source = GetValue('Source', $Comment))
+ echo Wrap(sprintf(T('via %s'), T($Source.' Source', $Source)), 'span', array('class' => 'MItem Source'));
+
+ // Add your own options or data as spans with 'MItem' class
+ $Sender->FireEvent('InsideCommentMeta');
+
?>
+ <div class="Options">
+ <?php WriteCommentOptions($Comment); ?>
+ </div>
+ <div class="CommentInfo">
+ <?php
+ $Sender->FireEvent('CommentInfo');
+
+ // Include IP Address if we have permission
+ if ($Session->CheckPermission('Garden.Moderation.Manage'))
+ echo Wrap(IPAnchor($Comment->InsertIPAddress), 'span', array('class' => 'MItem IPAddress'));
+ ?>
+ </div>
+ <?php $Sender->FireEvent('AfterCommentMeta'); ?>
+ </div>
+ <div class="Item-Body">
+ <div class="Message">
+ <?php
+ echo FormatBody($Comment);
+ ?>
+ </div>
+ <?php $Sender->FireEvent('AfterCommentBody'); ?>
+ <?php WriteReactions($Comment); ?>
</div>
- <?php $Sender->FireEvent('AfterCommentMeta'); ?>
</div>
- <div class="Message">
- <?php
- echo FormatBody($Comment);
- ?>
- </div>
- <?php $Sender->FireEvent('AfterCommentBody'); ?>
</div>
</li>
<?php
$Sender->FireEvent('AfterComment');
}
+if (!function_exists('WriteReactions')):
+
+function WriteReactions($Row, $Type = 'Comment') {
+ // noop
+}
+
+endif;
+
+if (!function_exists('WriteReactions')):
+
+function WriteReactions($Row, $Type = 'Comment') {
+ // noop
+}
+
+endif;
+
/**
* Get options for the current discussion.
*
@@ -170,7 +197,7 @@ function GetDiscussionOptions($Discussion = NULL) {
// Can the user announce?
if ($Session->CheckPermission('Vanilla.Discussions.Announce', TRUE, 'Category', $PermissionCategoryID))
- $Options['AnnounceDiscussion'] = array('Label' => T($Discussion->Announce ? 'Unannounce' : 'Announce'), 'Url' => 'vanilla/discussion/announce/'.$Discussion->DiscussionID.'/'.$Session->TransientKey().'?Target='.urlencode($Sender->SelfUrl.'#Head'), 'Class' => 'Hijack');
+ $Options['AnnounceDiscussion'] = array('Label' => T('Announce...'), 'Url' => 'vanilla/discussion/announce?discussionid='.$Discussion->DiscussionID.'&Target='.urlencode($Sender->SelfUrl.'#Head'), 'Class' => 'Popup');
// Can the user sink?
if ($Session->CheckPermission('Vanilla.Discussions.Sink', TRUE, 'Category', $PermissionCategoryID))
View
2 applications/vanilla/views/discussion/index.php
@@ -4,7 +4,7 @@
include $this->FetchViewLocation('helper_functions', 'discussion');
// Wrap the discussion related content in a div.
-echo '<div class="MessageList Discussion '.CssClass($this->Data('Discussion')).'">';
+echo '<div class="MessageList Discussion">';
// Write the page title.
echo '<!-- Page Title -->
View
24 applications/vanilla/views/discussions/helper_functions.php
@@ -64,6 +64,22 @@ function BookmarkButton($Discussion) {
}
}
+if (!function_exists('CategoryLink')):
+
+function CategoryLink($Discussion, $Prefix = ' ', $Force = FALSE) {
+ if (!$Force && Gdn::Controller()->Data('Category')) {
+ return;
+ }
+
+ $Category = CategoryModel::Categories(GetValue('CategoryID', $Discussion));
+
+ if ($Category) {
+ return Wrap($Prefix.Anchor($Category['Name'], $Category['Url']), 'span', array('class' => 'MItem Category'));
+ }
+}
+
+endif;
+
if (!function_exists('WriteDiscussion')):
function WriteDiscussion($Discussion, &$Sender, &$Session, $Alt2) {
$CssClass = CssClass($Discussion);
@@ -195,7 +211,7 @@ function CssClass($Discussion) {
$CssClass .= $Discussion->Bookmarked == '1' ? ' Bookmarked' : '';
$CssClass .= $Alt ? ' Alt ' : '';
$Alt = !$Alt;
- $CssClass .= $Discussion->Announce == '1' ? ' Announcement' : '';
+ $CssClass .= $Discussion->Announce ? ' Announcement' : '';
$CssClass .= $Discussion->Closed == '1' ? ' Closed' : '';
$CssClass .= $Discussion->Dismissed == '1' ? ' Dismissed' : '';
$CssClass .= $Discussion->InsertUserID == Gdn::Session()->UserID ? ' Mine' : '';
@@ -335,7 +351,7 @@ function OptionsList($Discussion) {
// Announce discussion
if ($Session->CheckPermission('Vanilla.Discussions.Announce', TRUE, 'Category', $Discussion->PermissionCategoryID))
- $Sender->Options .= '<li>'.Anchor(T($Discussion->Announce == '1' ? 'Unannounce' : 'Announce'), 'vanilla/discussion/announce/'.$Discussion->DiscussionID.'/'.$Session->TransientKey().'?Target='.urlencode($Sender->SelfUrl), 'AnnounceDiscussion') . '</li>';
+ $Sender->Options .= '<li>'.Anchor(T('Announce...'), '/discussion/announce?discussionid='.$Discussion->DiscussionID.'&Target='.urlencode($Sender->SelfUrl), 'Popup AnnounceDiscussion') . '</li>';
// Sink discussion
if ($Session->CheckPermission('Vanilla.Discussions.Sink', TRUE, 'Category', $Discussion->PermissionCategoryID))
@@ -360,9 +376,9 @@ function OptionsList($Discussion) {
$Sender->Options.
'</ul>'.
'</span>';
+
+ return $Result;
}
-
- return $Result;
}
return '';
View
8 applications/vanilla/views/discussions/index_rss.php
@@ -1,17 +1,17 @@
<?php if (!defined('APPLICATION')) exit(); ?>
<description><?php echo Gdn_Format::Text($this->Head->Title()); ?></description>
<language><?php echo Gdn::Config('Garden.Locale', 'en-US'); ?></language>
- <atom:link href="<?php echo Url('discussions/feed.rss'); ?>" rel="self" type="application/rss+xml" />
+ <atom:link href="<?php echo htmlspecialchars(Url($this->SelfUrl, TRUE)); ?>" rel="self" type="application/rss+xml" />
<?php
foreach ($this->DiscussionData->Result() as $Discussion) {
?>
<item>
<title><?php echo Gdn_Format::Text($Discussion->Name); ?></title>
- <link><?php echo Url('/discussion/'.$Discussion->DiscussionID.'/'.Gdn_Format::Url($Discussion->Name), TRUE); ?></link>
- <pubDate><?php echo date(DATE_RSS, Gdn_Format::ToTimeStamp($Discussion->DateInserted)); ?></pubDate>
+ <link><?php echo $Discussion->Url; ?></link>
+ <pubDate><?php echo date('r', Gdn_Format::ToTimeStamp($Discussion->DateInserted)); ?></pubDate>
<dc:creator><?php echo Gdn_Format::Text($Discussion->FirstName); ?></dc:creator>
<guid isPermaLink="false"><?php echo $Discussion->DiscussionID . '@' . Url('/discussions'); ?></guid>
- <description><![CDATA[<?php echo Gdn_Format::To($Discussion->Body, $Discussion->Format); ?>]]></description>
+ <description><![CDATA[<?php echo Gdn_Format::RssHtml($Discussion->Body, $Discussion->Format); ?>]]></description>
</item>
<?php
}
View
5 applications/vanilla/views/discussions/table.php
@@ -61,9 +61,12 @@ function WriteDiscussionRow($Discussion, &$Sender, &$Session, $Alt2) {
echo Anchor($DiscussionName, $DiscussionUrl, 'Title').' ';
+ $Sender->FireEvent('AfterDiscussionTitle');
+
WriteMiniPager($Discussion);
echo NewComments($Discussion);
- $Sender->FireEvent('AfterDiscussionTitle');
+ echo CategoryLink($Discussion, ' '.T('in').' ');
+
// Other stuff that was in the standard view that you may want to display:
echo '<div class="Meta">';
WriteTags($Discussion);
View
13 applications/vanilla/views/post/comment.php
@@ -34,9 +34,16 @@
$CancelClass = 'MItem Cancel';
}
- echo ' '.Gdn_Theme::Link('forumroot', $CancelText, NULL, array(
- 'class' => $CancelClass
- )).' ';
+ echo '<span class="'.$CancelClass.'">';
+ echo Anchor(T('Home'), '/');
+
+ if ($CategoryID = $this->Data('Discussion.CategoryID')) {
+ $Category = CategoryModel::Categories($CategoryID);
+ if ($Category)
+ echo ' <span class="Bullet">•</span> '.Anchor($Category['Name'], $Category['Url']);
+ }
+
+ echo '</span>';
$ButtonOptions = array('class' => 'Button CommentButton');
$ButtonOptions['tabindex'] = 2;
View
2 conf/config-defaults.php
@@ -99,7 +99,7 @@
$Configuration['Garden']['VanillaUrl'] = 'http://vanillaforums.org';
$Configuration['Garden']['AllowSSL'] = TRUE;
$Configuration['Garden']['PrivateCommunity'] = FALSE;
-$Configuration['Garden']['EditContentTimeout'] = -1; // -1 means no timeout. 0 means immediate timeout. > 0 is in seconds.
+$Configuration['Garden']['EditContentTimeout'] = 3600; // -1 means no timeout. 0 means immediate timeout. > 0 is in seconds. 60 * 60 = 3600 (aka 1hr)
$Configuration['Garden']['Profile']['EditUsernames'] = FALSE;
$Configuration['Garden']['Modules']['ShowGuestModule'] = TRUE;
$Configuration['Garden']['Modules']['ShowSignedInModule'] = FALSE;
View
2 index.php
@@ -10,7 +10,7 @@
*/
define('APPLICATION', 'Vanilla');
-define('APPLICATION_VERSION', '2.1a10');
+define('APPLICATION_VERSION', '2.1a10p1');
// Report and track all errors.
error_reporting(E_ERROR | E_PARSE | E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR | E_RECOVERABLE_ERROR);
View
21 js/embed.js
@@ -31,12 +31,17 @@ window.vanilla.embed = function(host) {
if (typeof(host) == 'undefined') {
host = '';
+ host_base_url = '';
for (i = 0; i < scripts.length; i++) {
if (scripts[i].src.indexOf(jsPath) > 0) {
host = scripts[i].src;
host = host.replace('http://', '').replace('https://', '');
host = host.substr(0, host.indexOf(jsPath));
host += '/index.php?p=';
+
+ host_base_url = scripts[i].src;
+ host_base_url = host_base_url.substr(0, host_base_url.indexOf(jsPath));
+
}
}
}
@@ -200,13 +205,19 @@ window.vanilla.embed = function(host) {
vanillaIframe.style.height = "300px";
vanillaIframe.style.border = "0";
vanillaIframe.style.display = "block";
- (document.getElementById('vanilla-comments')).appendChild(vanillaIframe);
-
+ var container = document.getElementById('vanilla-comments');
+ // Couldn't find the container, so dump it out and try again.
+ if (!container)
+ document.write('<div id="vanilla-comments"></div>');
+ container = document.getElementById('vanilla-comments');
+ if (container)
+ container.appendChild(vanillaIframe);
+
// Include our embed css into the page
var vanilla_embed_css = document.createElement('link');
vanilla_embed_css.rel = 'stylesheet';
vanilla_embed_css.type = 'text/css';
- vanilla_embed_css.href = vanilla_forum_url + (vanilla_forum_url.substring(vanilla_forum_url.length-1) == '/' ? '' : '/') +'applications/dashboard/design/embed.css';
+ vanilla_embed_css.href = host_base_url + (host_base_url.substring(host_base_url.length-1) == '/' ? '' : '/') +'applications/dashboard/design/embed.css';
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(vanilla_embed_css);
return this;
@@ -215,6 +226,8 @@ try {
if (window.location.hash.substr(0, 6) != "#poll:")
window.vanilla.embed();
} catch(e) {
+ alert(e);
+ /*
var error = document.createElement('div');
error.style.padding = "10px";
error.style.fontSize = "12px";
@@ -223,4 +236,6 @@ try {
error.style.color = "#000000";
error.appendChild(document.createTextNode("Failed to embed Vanilla: " + e));
(document.getElementById('vanilla-comments')).appendChild(error);
+*/
+
}
View
29 js/global.js
@@ -542,11 +542,13 @@ jQuery(document).ready(function($) {
var hijackClick = function(e) {
var $elem = $(this);
+ var $flyout = $elem.closest('.ToggleFlyout');
var href = $elem.attr('href');
if (!href)
return;
gdn.disable(this);
-
+ e.stopPropagation();
+
$.ajax({
type: "POST",
url: href,
@@ -556,6 +558,9 @@ jQuery(document).ready(function($) {
gdn.enable(this);
$elem.removeClass('InProgress');
$elem.attr('href', href);
+
+ // If we are in a flyout, close it.
+ $flyout.removeClass('Open').find('.Flyout').hide();
},
error: function(xhr) {
gdn.informError(xhr);
@@ -581,8 +586,17 @@ jQuery(document).ready(function($) {
// Activate ToggleFlyout menus
var lastOpen = null;
- $(document).delegate('.ToggleFlyout', 'click', function() {