From 1b7b58192bd34f7d34ae6712ac1b09130bca6bd0 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Fri, 16 Jan 2009 22:29:13 +0000 Subject: Split avatar upload to its own page --- actions/avatarsettings.php | 306 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 306 insertions(+) create mode 100644 actions/avatarsettings.php (limited to 'actions/avatarsettings.php') diff --git a/actions/avatarsettings.php b/actions/avatarsettings.php new file mode 100644 index 000000000..de5473d9f --- /dev/null +++ b/actions/avatarsettings.php @@ -0,0 +1,306 @@ +. + * + * @category Settings + * @package Laconica + * @author Evan Prodromou + * @author Zach Copley + * @copyright 2008-2009 Control Yourself, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + */ + +if (!defined('LACONICA')) { + exit(1); +} + +require_once INSTALLDIR.'/lib/settingsaction.php'; + +/** + * Upload an avatar + * + * We use jQuery to crop the image after upload. + * + * @category Settings + * @package Laconica + * @author Evan Prodromou + * @author Zach Copley + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + */ + +class AvatarsettingsAction extends SettingsAction +{ + /** + * Title of the page + * + * @return string Title of the page + */ + + function title() + { + return _('Avatar'); + } + + /** + * Instructions for use + * + * @return instructions for use + */ + + function getInstructions() + { + return _('Set your personal avatar.'); + } + + /** + * Content area of the page + * + * Shows a form for uploading an avatar. + * + * @return void + */ + + function showContent() + { + $user = common_current_user(); + + $profile = $user->getProfile(); + + if (!$profile) { + common_log_db_error($user, 'SELECT', __FILE__); + $this->serverError(_('User without matching profile')); + return; + } + + $original = $profile->getOriginalAvatar(); + + $this->elementStart('form', array('enctype' => 'multipart/form-data', + 'method' => 'POST', + 'id' => 'avatar', + 'action' => + common_local_url('avatarsettings'))); + $this->hidden('token', common_session_token()); + + if ($original) { + $this->elementStart('div', + array('id' => 'avatar_original', + 'class' => 'avatar_view')); + $this->element('h3', null, _("Original:")); + $this->elementStart('div', array('id'=>'avatar_original_view')); + $this->element('img', array('src' => $original->url, + 'class' => 'avatar original', + 'width' => $original->width, + 'height' => $original->height, + 'alt' => $user->nickname)); + $this->elementEnd('div'); + $this->elementEnd('div'); + } + + $avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE); + + if ($avatar) { + $this->elementStart('div', + array('id' => 'avatar_preview', + 'class' => 'avatar_view')); + $this->element('h3', null, _("Preview:")); + $this->elementStart('div', array('id'=>'avatar_preview_view')); + $this->element('img', array('src' => $original->url,//$avatar->url, + 'class' => 'avatar profile', + 'width' => AVATAR_PROFILE_SIZE, + 'height' => AVATAR_PROFILE_SIZE, + 'alt' => $user->nickname)); + $this->elementEnd('div'); + $this->elementEnd('div'); + + foreach (array('avatar_crop_x', 'avatar_crop_y', + 'avatar_crop_w', 'avatar_crop_h') as $crop_info) { + $this->element('input', array('name' => $crop_info, + 'type' => 'hidden', + 'id' => $crop_info)); + } + $this->submit('crop', _('Crop')); + } + + $this->element('input', array('name' => 'MAX_FILE_SIZE', + 'type' => 'hidden', + 'id' => 'MAX_FILE_SIZE', + 'value' => MAX_AVATAR_SIZE)); + + $this->elementStart('p'); + + $this->element('input', array('name' => 'avatarfile', + 'type' => 'file', + 'id' => 'avatarfile')); + $this->elementEnd('p'); + + $this->submit('upload', _('Upload')); + $this->elementEnd('form'); + + } + + /** + * Handle a post + * + * We mux on the button name to figure out what the user actually wanted. + * + * @return void + */ + + function handlePost() + { + // CSRF protection + + $token = $this->trimmed('token'); + if (!$token || $token != common_session_token()) { + $this->show_form(_('There was a problem with your session token. '. + 'Try again, please.')); + return; + } + + if ($this->arg('upload')) { + $this->uploadAvatar(); + } else if ($this->arg('crop')) { + $this->cropAvatar(); + } else { + $this->showForm(_('Unexpected form submission.')); + } + } + + /** + * Handle an image upload + * + * Does all the magic for handling an image upload, and crops the + * image by default. + * + * @return void + */ + + function uploadAvatar() + { + switch ($_FILES['avatarfile']['error']) { + case UPLOAD_ERR_OK: // success, jump out + break; + case UPLOAD_ERR_INI_SIZE: + case UPLOAD_ERR_FORM_SIZE: + $this->showForm(_('That file is too big.')); + return; + case UPLOAD_ERR_PARTIAL: + @unlink($_FILES['avatarfile']['tmp_name']); + $this->showForm(_('Partial upload.')); + return; + default: + $this->showForm(_('System error uploading file.')); + return; + } + + $info = @getimagesize($_FILES['avatarfile']['tmp_name']); + + if (!$info) { + @unlink($_FILES['avatarfile']['tmp_name']); + $this->showForm(_('Not an image or corrupt file.')); + return; + } + + switch ($info[2]) { + case IMAGETYPE_GIF: + case IMAGETYPE_JPEG: + case IMAGETYPE_PNG: + break; + default: + $this->showForm(_('Unsupported image file format.')); + return; + } + + $user = common_current_user(); + + $profile = $user->getProfile(); + + if ($profile->setOriginal($_FILES['avatarfile']['tmp_name'])) { + $this->showForm(_('Avatar updated.'), true); + } else { + $this->showForm(_('Failed updating avatar.')); + } + + @unlink($_FILES['avatarfile']['tmp_name']); + } + + /** + * Handle the results of jcrop. + * + * @return void + */ + + function cropAvatar() + { + $user = common_current_user(); + + $profile = $user->getProfile(); + + $x = $this->arg('avatar_crop_x'); + $y = $this->arg('avatar_crop_y'); + $w = $this->arg('avatar_crop_w'); + $h = $this->arg('avatar_crop_h'); + + if ($profile->crop_avatars($x, $y, $w, $h)) { + $this->showForm(_('Avatar updated.'), true); + } else { + $this->showForm(_('Failed updating avatar.')); + } + } + + /** + * Add the jCrop stylesheet + * + * @return void + */ + + function showStylesheets() + { + parent::showStylesheets(); + $jcropStyle = + common_path('js/jcrop/jquery.Jcrop.css?version='.LACONICA_VERSION); + + $this->element('link', array('rel' => 'stylesheet', + 'type' => 'text/css', + 'href' => $jcropStyle, + 'media' => 'screen, projection, tv')); + } + + /** + * Add the jCrop scripts + * + * @return void + */ + + function showScripts() + { + parent::showScripts(); + + $jcropPack = common_path('js/jcrop/jquery.Jcrop.pack.js'); + $jcropGo = common_path('js/jcrop/jquery.Jcrop.go.js'); + + $this->element('script', array('type' => 'text/javascript', + 'src' => $jcropPack)); + $this->element('script', array('type' => 'text/javascript', + 'src' => $jcropGo)); + } +} -- cgit v1.2.3-54-g00ecf From 97c98cf59ace088e487e130182ff4dc99d2d408b Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 17 Jan 2009 22:30:44 +0000 Subject: Break up settings into two tabset Made two tabsets: account and connect. Removed "Invite" from the global nav to make room. --- actions/avatarsettings.php | 4 +- actions/emailsettings.php | 7 +- actions/imsettings.php | 4 +- actions/openidsettings.php | 4 +- actions/othersettings.php | 4 +- actions/passwordsettings.php | 161 ++++++++++++++++++ actions/profilesettings.php | 378 ++++++++++++------------------------------ actions/smssettings.php | 5 +- actions/twittersettings.php | 7 +- lib/accountsettingsaction.php | 134 +++++++++++++++ lib/action.php | 82 ++++----- lib/connectsettingsaction.php | 129 ++++++++++++++ lib/rssaction.php | 97 ++++++++--- lib/settingsaction.php | 15 -- lib/settingsgroupnav.php | 112 ------------- lib/util.php | 4 + 16 files changed, 665 insertions(+), 482 deletions(-) create mode 100644 actions/passwordsettings.php create mode 100644 lib/accountsettingsaction.php create mode 100644 lib/connectsettingsaction.php delete mode 100644 lib/settingsgroupnav.php (limited to 'actions/avatarsettings.php') diff --git a/actions/avatarsettings.php b/actions/avatarsettings.php index de5473d9f..a9b381b0a 100644 --- a/actions/avatarsettings.php +++ b/actions/avatarsettings.php @@ -32,7 +32,7 @@ if (!defined('LACONICA')) { exit(1); } -require_once INSTALLDIR.'/lib/settingsaction.php'; +require_once INSTALLDIR.'/lib/accountsettingsaction.php'; /** * Upload an avatar @@ -47,7 +47,7 @@ require_once INSTALLDIR.'/lib/settingsaction.php'; * @link http://laconi.ca/ */ -class AvatarsettingsAction extends SettingsAction +class AvatarsettingsAction extends AccountSettingsAction { /** * Title of the page diff --git a/actions/emailsettings.php b/actions/emailsettings.php index 355470815..b1f13c18c 100644 --- a/actions/emailsettings.php +++ b/actions/emailsettings.php @@ -32,7 +32,7 @@ if (!defined('LACONICA')) { exit(1); } -require_once INSTALLDIR.'/lib/settingsaction.php'; +require_once INSTALLDIR.'/lib/accountsettingsaction.php'; /** * Settings for email @@ -47,7 +47,7 @@ require_once INSTALLDIR.'/lib/settingsaction.php'; * @see Widget */ -class EmailsettingsAction extends SettingsAction +class EmailsettingsAction extends AccountSettingsAction { /** * Title of the page @@ -103,7 +103,7 @@ class EmailsettingsAction extends SettingsAction $confirm = $this->getConfirmation(); if ($confirm) { $this->element('p', array('id' => 'email_unconfirmed'), $confirm->address); - $this->element('p', array('class' => 'form_note'), + $this->element('p', array('class' => 'form_note'), _('Awaiting confirmation on this address. '. 'Check your inbox (and spam box!) for a message '. 'with further instructions.')); @@ -143,7 +143,6 @@ class EmailsettingsAction extends SettingsAction $this->elementEnd('fieldset'); } - $this->elementStart('fieldset', array('id' => 'settings_email_preferences')); $this->element('legend', null, _('Preferences')); diff --git a/actions/imsettings.php b/actions/imsettings.php index 3e578b307..98951ac30 100644 --- a/actions/imsettings.php +++ b/actions/imsettings.php @@ -31,7 +31,7 @@ if (!defined('LACONICA')) { exit(1); } -require_once INSTALLDIR.'/lib/settingsaction.php'; +require_once INSTALLDIR.'/lib/connectsettingsaction.php'; require_once INSTALLDIR.'/lib/jabber.php'; /** @@ -46,7 +46,7 @@ require_once INSTALLDIR.'/lib/jabber.php'; * @see SettingsAction */ -class ImsettingsAction extends SettingsAction +class ImsettingsAction extends ConnectSettingsAction { /** * Title of the page diff --git a/actions/openidsettings.php b/actions/openidsettings.php index 6f17f154c..257aac8d0 100644 --- a/actions/openidsettings.php +++ b/actions/openidsettings.php @@ -31,7 +31,7 @@ if (!defined('LACONICA')) { exit(1); } -require_once INSTALLDIR.'/lib/settingsaction.php'; +require_once INSTALLDIR.'/lib/accountsettingsaction.php'; require_once INSTALLDIR.'/lib/openid.php'; /** @@ -46,7 +46,7 @@ require_once INSTALLDIR.'/lib/openid.php'; * @link http://laconi.ca/ */ -class OpenidsettingsAction extends SettingsAction +class OpenidsettingsAction extends AccountSettingsAction { /** * Title of the page diff --git a/actions/othersettings.php b/actions/othersettings.php index 51f6f8197..a7664d74e 100644 --- a/actions/othersettings.php +++ b/actions/othersettings.php @@ -19,9 +19,9 @@ if (!defined('LACONICA')) { exit(1); } -require_once(INSTALLDIR.'/lib/settingsaction.php'); +require_once(INSTALLDIR.'/lib/accountsettingsaction.php'); -class OthersettingsAction extends SettingsAction +class OthersettingsAction extends AccountSettingsAction { function get_instructions() diff --git a/actions/passwordsettings.php b/actions/passwordsettings.php new file mode 100644 index 000000000..f96da13bd --- /dev/null +++ b/actions/passwordsettings.php @@ -0,0 +1,161 @@ +. + * + * @category Settings + * @package Laconica + * @author Evan Prodromou + * @author Zach Copley + * @copyright 2008-2009 Control Yourself, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + */ + +if (!defined('LACONICA')) { + exit(1); +} + +require_once INSTALLDIR.'/lib/accountsettingsaction.php'; + +/** + * Change password + * + * @category Settings + * @package Laconica + * @author Evan Prodromou + * @author Zach Copley + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + */ + +class PasswordsettingsAction extends AccountSettingsAction +{ + /** + * Title of the page + * + * @return string Title of the page + */ + + function title() + { + return _('Change password'); + } + + /** + * Instructions for use + * + * @return instructions for use + */ + + function getInstructions() + { + return _('Change your password.'); + } + + /** + * Content area of the page + * + * Shows a form for changing the password + * + * @return void + */ + + function showContent() + { + $user = common_current_user(); + $this->elementStart('form', array('method' => 'POST', + 'id' => 'password', + 'action' => + common_local_url('profilesettings'))); + + $this->hidden('token', common_session_token()); + + // Users who logged in with OpenID won't have a pwd + if ($user->password) { + $this->password('oldpassword', _('Old password')); + } + $this->password('newpassword', _('New password'), + _('6 or more characters')); + $this->password('confirm', _('Confirm'), + _('same as password above')); + $this->submit('changepass', _('Change')); + $this->elementEnd('form'); + } + + /** + * Handle a post + * + * Validate input and save changes. Reload the form with a success + * or error message. + * + * @return void + */ + + function handlePost() + { + // CSRF protection + + $token = $this->trimmed('token'); + if (!$token || $token != common_session_token()) { + $this->showForm(_('There was a problem with your session token. '. + 'Try again, please.')); + return; + } + + $user = common_current_user(); + assert(!is_null($user)); // should already be checked + + // FIXME: scrub input + + $newpassword = $this->arg('newpassword'); + $confirm = $this->arg('confirm'); + + if (0 != strcmp($newpassword, $confirm)) { + $this->showForm(_('Passwords don\'t match.')); + return; + } + + if ($user->password) { + $oldpassword = $this->arg('oldpassword'); + + if (!common_check_user($user->nickname, $oldpassword)) { + $this->showForm(_('Incorrect old password')); + return; + } + } + + $original = clone($user); + + $user->password = common_munge_password($newpassword, $user->id); + + $val = $user->validate(); + if ($val !== true) { + $this->showForm(_('Error saving user; invalid.')); + return; + } + + if (!$user->update($original)) { + $this->serverError(_('Can\'t save new password.')); + return; + } + + $this->showForm(_('Password saved.'), true); + } +} \ No newline at end of file diff --git a/actions/profilesettings.php b/actions/profilesettings.php index 6ad3f2ef5..c31f76227 100644 --- a/actions/profilesettings.php +++ b/actions/profilesettings.php @@ -1,9 +1,12 @@ . + * + * @category Settings + * @package Laconica + * @author Evan Prodromou + * @author Zach Copley + * @copyright 2008-2009 Control Yourself, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ */ -if (!defined('LACONICA')) { exit(1); } +if (!defined('LACONICA')) { + exit(1); +} + +require_once INSTALLDIR.'/lib/accountsettingsaction.php'; -require_once(INSTALLDIR.'/lib/settingsaction.php'); +/** + * Change profile settings + * + * @category Settings + * @package Laconica + * @author Evan Prodromou + * @author Zach Copley + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + */ -class ProfilesettingsAction extends SettingsAction +class ProfilesettingsAction extends AccountSettingsAction { + /** + * Title of the page + * + * @return string Title of the page + */ - function get_instructions() + function title() { - return _('You can update your personal profile info here '. - 'so people know more about you.'); + return _('Profile settings'); } - function show_form($msg=null, $success=false) - { - $this->form_header(_('Profile settings'), $msg, $success); - $this->show_settings_form(); - $this->element('h2', null, _('Avatar')); - $this->show_avatar_form(); - $this->element('h2', null, _('Change password')); - $this->show_password_form(); -// $this->element('h2', null, _('Delete my account')); -// $this->show_delete_form(); - common_show_footer(); - } + /** + * Instructions for use + * + * @return instructions for use + */ - function handle_post() + function getInstructions() { - - # CSRF protection - - $token = $this->trimmed('token'); - if (!$token || $token != common_session_token()) { - $this->show_form(_('There was a problem with your session token. Try again, please.')); - return; - } - - if ($this->arg('save')) { - $this->save_profile(); - } else if ($this->arg('upload')) { - $this->upload_avatar(); - } else if ($this->arg('crop')) { - $this->crop_avatar(); - } else if ($this->arg('changepass')) { - $this->change_password(); - } else { - $this->show_form(_('Unexpected form submission.')); - } - + return _('You can update your personal profile info here '. + 'so people know more about you.'); } - function show_settings_form() - { + /** + * Content area of the page + * + * Shows a form for uploading an avatar. + * + * @return void + */ + function showContent() + { $user = common_current_user(); $profile = $user->getProfile(); @@ -78,9 +87,9 @@ class ProfilesettingsAction extends SettingsAction 'id' => 'profilesettings', 'action' => common_local_url('profilesettings'))); $this->hidden('token', common_session_token()); - + # too much common patterns here... abstractable? - + $this->input('nickname', _('Nickname'), ($this->arg('nickname')) ? $this->arg('nickname') : $profile->nickname, _('1-64 lowercase letters or numbers, no punctuation or spaces')); @@ -100,16 +109,24 @@ class ProfilesettingsAction extends SettingsAction _('Tags for yourself (letters, numbers, -, ., and _), comma- or space- separated')); $language = common_language(); - $this->dropdown('language', _('Language'), get_nice_language_list(), _('Preferred language'), true, $language); + $this->dropdown('language', _('Language'), + get_nice_language_list(), _('Preferred language'), + true, $language); + $timezone = common_timezone(); $timezones = array(); foreach(DateTimeZone::listIdentifiers() as $k => $v) { $timezones[$v] = $v; } - $this->dropdown('timezone', _('Timezone'), $timezones, _('What timezone are you normally in?'), true, $timezone); + $this->dropdown('timezone', _('Timezone'), + $timezones, _('What timezone are you normally in?'), + true, $timezone); - $this->checkbox('autosubscribe', _('Automatically subscribe to whoever subscribes to me (best for non-humans)'), - ($this->arg('autosubscribe')) ? $this->boolean('autosubscribe') : $user->autosubscribe); + $this->checkbox('autosubscribe', + _('Automatically subscribe to whoever '. + 'subscribes to me (best for non-humans)'), + ($this->arg('autosubscribe')) ? + $this->boolean('autosubscribe') : $user->autosubscribe); $this->submit('save', _('Save')); @@ -117,105 +134,26 @@ class ProfilesettingsAction extends SettingsAction } - function show_avatar_form() - { - - $user = common_current_user(); - $profile = $user->getProfile(); - - if (!$profile) { - common_log_db_error($user, 'SELECT', __FILE__); - $this->serverError(_('User without matching profile')); - return; - } - - $original = $profile->getOriginalAvatar(); - - - $this->elementStart('form', array('enctype' => 'multipart/form-data', - 'method' => 'POST', - 'id' => 'avatar', - 'action' => - common_local_url('profilesettings'))); - $this->hidden('token', common_session_token()); - - if ($original) { - $this->elementStart('div', array('id'=>'avatar_original', 'class'=>'avatar_view')); - $this->element('h3', null, _("Original:")); - $this->elementStart('div', array('id'=>'avatar_original_view')); - $this->element('img', array('src' => $original->url, - 'class' => 'avatar original', - 'width' => $original->width, - 'height' => $original->height, - 'alt' => $user->nickname)); - $this->elementEnd('div'); - $this->elementEnd('div'); - } - - $avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE); - - if ($avatar) { - $this->elementStart('div', array('id'=>'avatar_preview', 'class'=>'avatar_view')); - $this->element('h3', null, _("Preview:")); - $this->elementStart('div', array('id'=>'avatar_preview_view')); - $this->element('img', array('src' => $original->url,//$avatar->url, - 'class' => 'avatar profile', - 'width' => AVATAR_PROFILE_SIZE, - 'height' => AVATAR_PROFILE_SIZE, - 'alt' => $user->nickname)); - $this->elementEnd('div'); - $this->elementEnd('div'); - - foreach(array('avatar_crop_x', 'avatar_crop_y', 'avatar_crop_w', 'avatar_crop_h') as $crop_info) { - $this->element('input', array('name' => $crop_info, - 'type' => 'hidden', - 'id' => $crop_info)); - } - $this->submit('crop', _('Crop')); - } - - $this->element('input', array('name' => 'MAX_FILE_SIZE', - 'type' => 'hidden', - 'id' => 'MAX_FILE_SIZE', - 'value' => MAX_AVATAR_SIZE)); - - $this->elementStart('p'); - - $this->element('input', array('name' => 'avatarfile', - 'type' => 'file', - 'id' => 'avatarfile')); - $this->elementEnd('p'); + /** + * Handle a post + * + * Validate input and save changes. Reload the form with a success + * or error message. + * + * @return void + */ - $this->submit('upload', _('Upload')); - $this->elementEnd('form'); - - } - - function show_password_form() + function handlePost() { + # CSRF protection - $user = common_current_user(); - $this->elementStart('form', array('method' => 'POST', - 'id' => 'password', - 'action' => - common_local_url('profilesettings'))); - - $this->hidden('token', common_session_token()); - - # Users who logged in with OpenID won't have a pwd - if ($user->password) { - $this->password('oldpassword', _('Old password')); + $token = $this->trimmed('token'); + if (!$token || $token != common_session_token()) { + $this->showForm(_('There was a problem with your session token. '. + 'Try again, please.')); + return; } - $this->password('newpassword', _('New password'), - _('6 or more characters')); - $this->password('confirm', _('Confirm'), - _('same as password above')); - $this->submit('changepass', _('Change')); - $this->elementEnd('form'); - } - function save_profile() - { $nickname = $this->trimmed('nickname'); $fullname = $this->trimmed('fullname'); $homepage = $this->trimmed('homepage'); @@ -225,38 +163,38 @@ class ProfilesettingsAction extends SettingsAction $language = $this->trimmed('language'); $timezone = $this->trimmed('timezone'); $tagstring = $this->trimmed('tags'); - + # Some validation if (!Validate::string($nickname, array('min_length' => 1, 'max_length' => 64, 'format' => VALIDATE_NUM . VALIDATE_ALPHA_LOWER))) { - $this->show_form(_('Nickname must have only lowercase letters and numbers and no spaces.')); + $this->showForm(_('Nickname must have only lowercase letters and numbers and no spaces.')); return; } else if (!User::allowed_nickname($nickname)) { - $this->show_form(_('Not a valid nickname.')); + $this->showForm(_('Not a valid nickname.')); return; } else if (!is_null($homepage) && (strlen($homepage) > 0) && !Validate::uri($homepage, array('allowed_schemes' => array('http', 'https')))) { - $this->show_form(_('Homepage is not a valid URL.')); + $this->showForm(_('Homepage is not a valid URL.')); return; } else if (!is_null($fullname) && strlen($fullname) > 255) { - $this->show_form(_('Full name is too long (max 255 chars).')); + $this->showForm(_('Full name is too long (max 255 chars).')); return; } else if (!is_null($bio) && strlen($bio) > 140) { - $this->show_form(_('Bio is too long (max 140 chars).')); + $this->showForm(_('Bio is too long (max 140 chars).')); return; } else if (!is_null($location) && strlen($location) > 255) { - $this->show_form(_('Location is too long (max 255 chars).')); + $this->showForm(_('Location is too long (max 255 chars).')); return; } else if (is_null($timezone) || !in_array($timezone, DateTimeZone::listIdentifiers())) { - $this->show_form(_('Timezone not selected.')); + $this->showForm(_('Timezone not selected.')); return; - } else if ($this->nickname_exists($nickname)) { - $this->show_form(_('Nickname already in use. Try another one.')); + } else if ($this->nicknameExists($nickname)) { + $this->showForm(_('Nickname already in use. Try another one.')); return; } else if (!is_null($language) && strlen($language) > 50) { - $this->show_form(_('Language is too long (max 50 chars).')); + $this->showForm(_('Language is too long (max 50 chars).')); return; } @@ -265,14 +203,14 @@ class ProfilesettingsAction extends SettingsAction } else { $tags = array(); } - + foreach ($tags as $tag) { if (!common_valid_profile_tag($tag)) { - $this->show_form(sprintf(_('Invalid tag: "%s"'), $tag)); + $this->showForm(sprintf(_('Invalid tag: "%s"'), $tag)); return; } } - + $user = common_current_user(); $user->query('BEGIN'); @@ -346,139 +284,29 @@ class ProfilesettingsAction extends SettingsAction } # Set the user tags - + $result = $user->setSelfTags($tags); if (!$result) { $this->serverError(_('Couldn\'t save tags.')); return; } - + $user->query('COMMIT'); common_broadcast_profile($profile); - $this->show_form(_('Settings saved.'), true); + $this->showForm(_('Settings saved.'), true); } - - function upload_avatar() - { - switch ($_FILES['avatarfile']['error']) { - case UPLOAD_ERR_OK: # success, jump out - break; - case UPLOAD_ERR_INI_SIZE: - case UPLOAD_ERR_FORM_SIZE: - $this->show_form(_('That file is too big.')); - return; - case UPLOAD_ERR_PARTIAL: - @unlink($_FILES['avatarfile']['tmp_name']); - $this->show_form(_('Partial upload.')); - return; - default: - $this->show_form(_('System error uploading file.')); - return; - } - - $info = @getimagesize($_FILES['avatarfile']['tmp_name']); - - if (!$info) { - @unlink($_FILES['avatarfile']['tmp_name']); - $this->show_form(_('Not an image or corrupt file.')); - return; - } - - switch ($info[2]) { - case IMAGETYPE_GIF: - case IMAGETYPE_JPEG: - case IMAGETYPE_PNG: - break; - default: - $this->show_form(_('Unsupported image file format.')); - return; - } - - $user = common_current_user(); - $profile = $user->getProfile(); - - if ($profile->setOriginal($_FILES['avatarfile']['tmp_name'])) { - $this->show_form(_('Avatar updated.'), true); - } else { - $this->show_form(_('Failed updating avatar.')); - } - - @unlink($_FILES['avatarfile']['tmp_name']); - } - - function crop_avatar() { - - $user = common_current_user(); - $profile = $user->getProfile(); - - $x = $this->arg('avatar_crop_x'); - $y = $this->arg('avatar_crop_y'); - $w = $this->arg('avatar_crop_w'); - $h = $this->arg('avatar_crop_h'); - - if ($profile->crop_avatars($x, $y, $w, $h)) { - $this->show_form(_('Avatar updated.'), true); - } else { - $this->show_form(_('Failed updating avatar.')); - } - } - - function nickname_exists($nickname) + function nicknameExists($nickname) { $user = common_current_user(); $other = User::staticGet('nickname', $nickname); if (!$other) { - return false; + return false; } else { return $other->id != $user->id; } } - - function change_password() - { - - $user = common_current_user(); - assert(!is_null($user)); # should already be checked - - # FIXME: scrub input - - $newpassword = $this->arg('newpassword'); - $confirm = $this->arg('confirm'); - $token = $this->arg('token'); - - if (0 != strcmp($newpassword, $confirm)) { - $this->show_form(_('Passwords don\'t match.')); - return; - } - - if ($user->password) { - $oldpassword = $this->arg('oldpassword'); - - if (!common_check_user($user->nickname, $oldpassword)) { - $this->show_form(_('Incorrect old password')); - return; - } - } - - $original = clone($user); - - $user->password = common_munge_password($newpassword, $user->id); - - $val = $user->validate(); - if ($val !== true) { - $this->show_form(_('Error saving user; invalid.')); - return; - } - - if (!$user->update($original)) { - $this->serverError(_('Can\'t save new password.')); - return; - } - - $this->show_form(_('Password saved.'), true); - } } diff --git a/actions/smssettings.php b/actions/smssettings.php index 6d3c54942..845266d18 100644 --- a/actions/smssettings.php +++ b/actions/smssettings.php @@ -31,7 +31,7 @@ if (!defined('LACONICA')) { exit(1); } -require_once INSTALLDIR.'/lib/settingsaction.php'; +require_once INSTALLDIR.'/lib/connectsettingsaction.php'; /** * Settings for SMS @@ -45,7 +45,7 @@ require_once INSTALLDIR.'/lib/settingsaction.php'; * @see SettingsAction */ -class SmssettingsAction extends SettingsAction +class SmssettingsAction extends ConnectSettingsAction { /** * Title of the page @@ -151,7 +151,6 @@ class SmssettingsAction extends SettingsAction $this->elementStart('fieldset', array('id' => 'settings_sms_preferences')); $this->element('legend', null, _('Preferences')); - $this->elementStart('ul', 'form_datas'); $this->elementStart('li'); $this->checkbox('smsnotify', diff --git a/actions/twittersettings.php b/actions/twittersettings.php index cd070cb45..597623c80 100644 --- a/actions/twittersettings.php +++ b/actions/twittersettings.php @@ -31,7 +31,7 @@ if (!defined('LACONICA')) { exit(1); } -require_once INSTALLDIR.'/lib/settingsaction.php'; +require_once INSTALLDIR.'/lib/connectsettingsaction.php'; define('SUBSCRIPTIONS', 80); @@ -47,7 +47,7 @@ define('SUBSCRIPTIONS', 80); * @see SettingsAction */ -class TwittersettingsAction extends SettingsAction +class TwittersettingsAction extends ConnectSettingsAction { /** * Title of the page @@ -129,7 +129,8 @@ class TwittersettingsAction extends SettingsAction $this->elementEnd('ul'); $this->elementEnd('fieldset'); - $this->elementStart('fieldset', array('id' => 'settings_twitter_preferences')); + $this->elementStart('fieldset', + array('id' => 'settings_twitter_preferences')); $this->element('legend', null, _('Preferences')); $this->elementStart('ul'); diff --git a/lib/accountsettingsaction.php b/lib/accountsettingsaction.php new file mode 100644 index 000000000..46090b8c1 --- /dev/null +++ b/lib/accountsettingsaction.php @@ -0,0 +1,134 @@ +. + * + * @category Settings + * @package Laconica + * @author Evan Prodromou + * @copyright 2008-2009 Control Yourself, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + */ + +if (!defined('LACONICA')) { + exit(1); +} + +require_once INSTALLDIR.'/lib/settingsaction.php'; + +/** + * Base class for account settings actions + * + * @category Settings + * @package Laconica + * @author Evan Prodromou + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + * + * @see Widget + */ + +class AccountSettingsAction extends SettingsAction +{ + /** + * Show the local navigation menu + * + * This is the same for all settings, so we show it here. + * + * @return void + */ + + function showLocalNav() + { + $menu = new AccountSettingsNav($this); + $menu->show(); + } +} + +/** + * A widget for showing the settings group local nav menu + * + * @category Widget + * @package Laconica + * @author Evan Prodromou + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + * + * @see HTMLOutputter + */ + +class AccountSettingsNav extends Widget +{ + var $action = null; + + /** + * Construction + * + * @param Action $action current action, used for output + */ + + function __construct($action=null) + { + parent::__construct($action); + $this->action = $action; + } + + /** + * Show the menu + * + * @return void + */ + + function show() + { + # action => array('prompt', 'title') + $menu = + array('profilesettings' => + array(_('Profile'), + _('Change your profile settings')), + 'avatarsettings' => + array(_('Avatar'), + _('Upload an avatar')), + 'passwordsettings' => + array(_('Password'), + _('Change your password')), + 'emailsettings' => + array(_('Email'), + _('Change email handling')), + 'openidsettings' => + array(_('OpenID'), + _('Add or remove OpenIDs')), + 'othersettings' => + array(_('Other'), + _('Other options'))); + + $action_name = $this->action->trimmed('action'); + $this->action->elementStart('ul', array('class' => 'nav')); + + foreach ($menu as $menuaction => $menudesc) { + $this->action->menuItem(common_local_url($menuaction), + $menudesc[0], + $menudesc[1], + $action_name === $menuaction); + } + + $this->action->elementEnd('ul'); + } +} diff --git a/lib/action.php b/lib/action.php index 71520b84e..e62a032b6 100644 --- a/lib/action.php +++ b/lib/action.php @@ -208,20 +208,20 @@ class Action extends HTMLOutputter // lawsuit $this->showLogo(); $this->showPrimaryNav(); $this->showSiteNotice(); - if (common_logged_in()) { - $this->showNoticeForm(); - } else { - $this->showAnonymousMessage(); - } + if (common_logged_in()) { + $this->showNoticeForm(); + } else { + $this->showAnonymousMessage(); + } $this->elementEnd('div'); } function showLogo() { $this->elementStart('address', array('id' => 'site_contact', - 'class' => 'vcard')); + 'class' => 'vcard')); $this->elementStart('a', array('class' => 'url home bookmark', - 'href' => common_local_url('public'))); + 'href' => common_local_url('public'))); if (common_config('site', 'logo') || file_exists(theme_file('logo.png'))) { $this->element('img', array('class' => 'logo photo', @@ -237,21 +237,21 @@ class Action extends HTMLOutputter // lawsuit { $this->elementStart('dl', array('id' => 'site_nav_global_primary')); $this->element('dt', null, _('Primary site navigation')); - $this->elementStart('dd'); + $this->elementStart('dd'); $user = common_current_user(); $this->elementStart('ul', array('class' => 'nav')); if ($user) { $this->menuItem(common_local_url('all', array('nickname' => $user->nickname)), - _('Home')); + _('Home')); } $this->menuItem(common_local_url('peoplesearch'), _('Search')); if ($user) { $this->menuItem(common_local_url('profilesettings'), - _('Settings')); - $this->menuItem(common_local_url('invite'), - _('Invite')); + _('Account')); + $this->menuItem(common_local_url('imsettings'), + _('Connect')); $this->menuItem(common_local_url('logout'), - _('Logout')); + _('Logout')); } else { $this->menuItem(common_local_url('login'), _('Login')); if (!common_config('site', 'closed')) { @@ -260,25 +260,25 @@ class Action extends HTMLOutputter // lawsuit $this->menuItem(common_local_url('openidlogin'), _('OpenID')); } $this->menuItem(common_local_url('doc', array('title' => 'help')), - _('Help')); + _('Help')); $this->elementEnd('ul'); - $this->elementEnd('dd'); + $this->elementEnd('dd'); $this->elementEnd('dl'); } // Revist. Should probably do an hAtom pattern here function showSiteNotice() { - $text = common_config('site', 'notice'); - if ($text) { - $this->elementStart('dl', array('id' => 'site_notice', - 'class' => 'system_notice')); - $this->element('dt', null, _('Site notice')); - $this->element('dd', null, $text); - $this->elementEnd('dl'); - } + $text = common_config('site', 'notice'); + if ($text) { + $this->elementStart('dl', array('id' => 'site_notice', + 'class' => 'system_notice')); + $this->element('dt', null, _('Site notice')); + $this->element('dd', null, $text); + $this->elementEnd('dl'); + } } - + // MAY overload if no notice form needed... or direct message box???? function showNoticeForm() @@ -289,9 +289,9 @@ class Action extends HTMLOutputter // lawsuit function showAnonymousMessage() { - // needs to be defined by the class + // needs to be defined by the class } - + function showCore() { $this->elementStart('div', array('id' => 'core')); @@ -331,13 +331,13 @@ class Action extends HTMLOutputter // lawsuit function showPageNoticeBlock() { - $this->elementStart('dl', array('id' => 'page_notice', - 'class' => 'system_notice')); - $this->element('dt', null, _('Page notice')); - $this->elementStart('dd'); - $this->showPageNotice(); - $this->elementEnd('dd'); - $this->elementEnd('dl'); + $this->elementStart('dl', array('id' => 'page_notice', + 'class' => 'system_notice')); + $this->element('dt', null, _('Page notice')); + $this->elementStart('dd'); + $this->showPageNotice(); + $this->elementEnd('dd'); + $this->elementEnd('dl'); } // SHOULD overload (unless there's not a notice) @@ -345,7 +345,7 @@ class Action extends HTMLOutputter // lawsuit function showPageNotice() { } - + // MUST overload function showContent() @@ -391,17 +391,17 @@ class Action extends HTMLOutputter // lawsuit $this->elementStart('dd', null); $this->elementStart('ul', array('class' => 'nav')); $this->menuItem(common_local_url('doc', array('title' => 'help')), - _('Help')); + _('Help')); $this->menuItem(common_local_url('doc', array('title' => 'about')), - _('About')); + _('About')); $this->menuItem(common_local_url('doc', array('title' => 'faq')), - _('FAQ')); + _('FAQ')); $this->menuItem(common_local_url('doc', array('title' => 'privacy')), - _('Privacy')); + _('Privacy')); $this->menuItem(common_local_url('doc', array('title' => 'source')), - _('Source')); + _('Source')); $this->menuItem(common_local_url('doc', array('title' => 'contact')), - _('Contact')); + _('Contact')); $this->elementEnd('ul'); $this->elementEnd('dd'); $this->elementEnd('dl'); @@ -567,7 +567,7 @@ class Action extends HTMLOutputter // lawsuit } (is_null($id)) ? $lattrs : $lattrs['id'] = $id; - + $this->elementStart('li', $lattrs); $attrs['href'] = $url; if ($title) { diff --git a/lib/connectsettingsaction.php b/lib/connectsettingsaction.php new file mode 100644 index 000000000..30629680e --- /dev/null +++ b/lib/connectsettingsaction.php @@ -0,0 +1,129 @@ +. + * + * @category Settings + * @package Laconica + * @author Evan Prodromou + * @copyright 2008-2009 Control Yourself, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + */ + +if (!defined('LACONICA')) { + exit(1); +} + +require_once INSTALLDIR.'/lib/settingsaction.php'; + +/** + * Base class for connection settings actions + * + * @category Settings + * @package Laconica + * @author Evan Prodromou + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + * + * @see Widget + */ + +class ConnectSettingsAction extends SettingsAction +{ + /** + * Show the local navigation menu + * + * This is the same for all settings, so we show it here. + * + * @return void + */ + + function showLocalNav() + { + $menu = new ConnectSettingsNav($this); + $menu->show(); + } +} + +/** + * A widget for showing the connect group local nav menu + * + * @category Widget + * @package Laconica + * @author Evan Prodromou + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + * + * @see HTMLOutputter + */ + +class ConnectSettingsNav extends Widget +{ + var $action = null; + + /** + * Construction + * + * @param Action $action current action, used for output + */ + + function __construct($action=null) + { + parent::__construct($action); + $this->action = $action; + } + + /** + * Show the menu + * + * @return void + */ + + function show() + { + # action => array('prompt', 'title') + $menu = + array('imsettings' => + array(_('IM'), + _('Updates by instant messenger (IM)')), + 'smssettings' => + array(_('SMS'), + _('Updates by SMS')), + 'twittersettings' => + array(_('Twitter'), + _('Twitter integration options'))); + + $action_name = $this->action->trimmed('action'); + $this->action->elementStart('ul', array('class' => 'nav')); + + foreach ($menu as $menuaction => $menudesc) { + if ($menuaction == 'imsettings' && + !common_config('xmpp', 'enabled')) { + continue; + } + $this->action->menuItem(common_local_url($menuaction), + $menudesc[0], + $menudesc[1], + $action_name === $menuaction); + } + + $this->action->elementEnd('ul'); + } +} diff --git a/lib/rssaction.php b/lib/rssaction.php index 9564cfb46..2c532912b 100644 --- a/lib/rssaction.php +++ b/lib/rssaction.php @@ -1,9 +1,12 @@ . + * + * @category Mail + * @package Laconica + * @author Evan Prodromou + * @author Earle Martin + * @copyright 2008-9 Control Yourself, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ */ if (!defined('LACONICA')) { exit(1); } @@ -23,35 +34,84 @@ define('DEFAULT_RSS_LIMIT', 48); class Rss10Action extends Action { - # This will contain the details of each feed item's author and be used to generate SIOC data. + var $creators = array(); + var $limit = DEFAULT_RSS_LIMIT; + + /** + * Constructor + * + * Just wraps the Action constructor. + * + * @param string $output URI to output to, default = stdout + * @param boolean $indent Whether to indent output, default true + * + * @see Action::__construct + */ - function is_readonly() + function __construct($output='php://output', $indent=true) + { + parent::__construct($output, $indent); + } + + /** + * Do we need to write to the database? + * + * @return boolean true + */ + + function isReadonly() { return true; } + /** + * Read arguments and initialize members + * + * @param array $args Arguments from $_REQUEST + * @return boolean success + */ + + function prepare($args) + { + $this->limit = (int) $this->trimmed('limit'); + if ($this->limit == 0) { + $this->limit = DEFAULT_RSS_LIMIT; + } + return true; + } + + /** + * Handle a request + * + * @param array $args Arguments from $_REQUEST + * + * @return void + */ + function handle($args) { parent::handle($args); - $limit = (int) $this->trimmed('limit'); - if ($limit == 0) { - $limit = DEFAULT_RSS_LIMIT; - } $this->show_rss($limit); } - function init() - { - return true; - } - - function get_notices() + /** + * Get the notices to output in this stream + * + * @return array an array of Notice objects sorted in reverse chron + */ + + function getNotices() { return array(); } + /** + * Get a description of the channel + * + * Returns an array with the following + * @return array function get_channel() { return array('url' => '', @@ -67,11 +127,6 @@ class Rss10Action extends Action function show_rss($limit=0) { - - if (!$this->init()) { - return; - } - $notices = $this->get_notices($limit); $this->init_rss(); diff --git a/lib/settingsaction.php b/lib/settingsaction.php index 8624803ac..dfe1f114b 100644 --- a/lib/settingsaction.php +++ b/lib/settingsaction.php @@ -31,8 +31,6 @@ if (!defined('LACONICA')) { exit(1); } -require_once INSTALLDIR.'/lib/settingsgroupnav.php'; - /** * Base class for settings group of actions * @@ -149,17 +147,4 @@ class SettingsAction extends Action return ''; } - /** - * Show the local navigation menu - * - * This is the same for all settings, so we show it here. - * - * @return void - */ - - function showLocalNav() - { - $menu = new SettingsGroupNav($this); - $menu->show(); - } } diff --git a/lib/settingsgroupnav.php b/lib/settingsgroupnav.php deleted file mode 100644 index bd66c65a6..000000000 --- a/lib/settingsgroupnav.php +++ /dev/null @@ -1,112 +0,0 @@ -. - * - * @category Widget - * @package Laconica - * @author Evan Prodromou - * @copyright 2009 Control Yourself, Inc. - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 - * @link http://laconi.ca/ - */ - -if (!defined('LACONICA')) { - exit(1); -} - -require_once INSTALLDIR.'/lib/widget.php'; - -/** - * A widget for showing the settings group local nav menu - * - * @category Widget - * @package Laconica - * @author Evan Prodromou - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 - * @link http://laconi.ca/ - * - * @see HTMLOutputter - */ - -class SettingsGroupNav extends Widget -{ - var $action = null; - - /** - * Construction - * - * @param Action $action current action, used for output - */ - - function __construct($action=null) - { - parent::__construct($action); - $this->action = $action; - } - - /** - * Show the menu - * - * @return void - */ - - function show() - { - # action => array('prompt', 'title') - $menu = - array('profilesettings' => - array(_('Profile'), - _('Change your profile settings')), - 'emailsettings' => - array(_('Email'), - _('Change email handling')), - 'openidsettings' => - array(_('OpenID'), - _('Add or remove OpenIDs')), - 'smssettings' => - array(_('SMS'), - _('Updates by SMS')), - 'imsettings' => - array(_('IM'), - _('Updates by instant messenger (IM)')), - 'twittersettings' => - array(_('Twitter'), - _('Twitter integration options')), - 'othersettings' => - array(_('Other'), - _('Other options'))); - - $action_name = $this->action->trimmed('action'); - $this->action->elementStart('ul', array('class' => 'nav')); - - foreach ($menu as $menuaction => $menudesc) { - if ($menuaction == 'imsettings' && - !common_config('xmpp', 'enabled')) { - continue; - } - $this->action->menuItem(common_local_url($menuaction), - $menudesc[0], - $menudesc[1], - $action_name === $menuaction); - } - - $this->action->elementEnd('ul'); - } -} diff --git a/lib/util.php b/lib/util.php index 9ca817eab..d67c64972 100644 --- a/lib/util.php +++ b/lib/util.php @@ -770,6 +770,8 @@ function common_fancy_url($action, $args=null) return common_path('main/openid'); case 'profilesettings': return common_path('settings/profile'); + case 'passwordsettings': + return common_path('settings/password'); case 'emailsettings': return common_path('settings/email'); case 'openidsettings': @@ -852,6 +854,8 @@ function common_fancy_url($action, $args=null) return common_path($path); case 'imsettings': return common_path('settings/im'); + case 'avatarsettings': + return common_path('settings/avatar'); case 'peoplesearch': return common_path('search/people' . (($args) ? ('?' . http_build_query($args)) : '')); case 'noticesearch': -- cgit v1.2.3-54-g00ecf From 41f74218f2ab70b78ba96d386b41fb6a1f958f75 Mon Sep 17 00:00:00 2001 From: sarven Date: Wed, 21 Jan 2009 20:33:37 +0000 Subject: Profile avatar settings --- actions/avatarsettings.php | 47 ++++++++++++++++++++++++++----------------- js/jcrop/jquery.Jcrop.go.js | 41 +++++++++++++++++++++++++++++++++++++ js/jcrop/jquery.Jcrop.pack.js | 8 ++++++++ js/jquery.Jcrop.go.js | 41 ------------------------------------- js/jquery.Jcrop.pack.js | 8 -------- theme/base/css/display.css | 28 +++++++++++++++++++------- 6 files changed, 98 insertions(+), 75 deletions(-) create mode 100644 js/jcrop/jquery.Jcrop.go.js create mode 100644 js/jcrop/jquery.Jcrop.pack.js delete mode 100644 js/jquery.Jcrop.go.js delete mode 100644 js/jquery.Jcrop.pack.js (limited to 'actions/avatarsettings.php') diff --git a/actions/avatarsettings.php b/actions/avatarsettings.php index a9b381b0a..ffbeb5486 100644 --- a/actions/avatarsettings.php +++ b/actions/avatarsettings.php @@ -37,12 +37,13 @@ require_once INSTALLDIR.'/lib/accountsettingsaction.php'; /** * Upload an avatar * - * We use jQuery to crop the image after upload. + * We use jCrop plugin for jQuery to crop the image after upload. * * @category Settings * @package Laconica * @author Evan Prodromou * @author Zach Copley + * @author Sarven Capadisli * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://laconi.ca/ */ @@ -94,42 +95,43 @@ class AvatarsettingsAction extends AccountSettingsAction $original = $profile->getOriginalAvatar(); $this->elementStart('form', array('enctype' => 'multipart/form-data', - 'method' => 'POST', - 'id' => 'avatar', + 'method' => 'post', + 'id' => 'form_settings_avatar', + 'class' => 'form_settings', 'action' => common_local_url('avatarsettings'))); + $this->elementStart('fieldset'); + $this->element('legend', null, _('Avatar settings')); $this->hidden('token', common_session_token()); + $this->elementStart('ul', 'form_data'); if ($original) { - $this->elementStart('div', + $this->elementStart('li', array('id' => 'avatar_original', 'class' => 'avatar_view')); - $this->element('h3', null, _("Original:")); + $this->element('h2', null, _("Original")); $this->elementStart('div', array('id'=>'avatar_original_view')); $this->element('img', array('src' => $original->url, - 'class' => 'avatar original', 'width' => $original->width, 'height' => $original->height, 'alt' => $user->nickname)); $this->elementEnd('div'); - $this->elementEnd('div'); + $this->elementEnd('li'); } $avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE); if ($avatar) { - $this->elementStart('div', + $this->elementStart('li', array('id' => 'avatar_preview', 'class' => 'avatar_view')); - $this->element('h3', null, _("Preview:")); + $this->element('h2', null, _("Preview")); $this->elementStart('div', array('id'=>'avatar_preview_view')); $this->element('img', array('src' => $original->url,//$avatar->url, - 'class' => 'avatar profile', 'width' => AVATAR_PROFILE_SIZE, 'height' => AVATAR_PROFILE_SIZE, 'alt' => $user->nickname)); $this->elementEnd('div'); - $this->elementEnd('div'); foreach (array('avatar_crop_x', 'avatar_crop_y', 'avatar_crop_w', 'avatar_crop_h') as $crop_info) { @@ -138,21 +140,28 @@ class AvatarsettingsAction extends AccountSettingsAction 'id' => $crop_info)); } $this->submit('crop', _('Crop')); + + $this->elementEnd('li'); } + $this->elementStart('li', array ('id' => 'settings_attach')); + $this->element('input', array('name' => 'avatarfile', + 'type' => 'file', + 'id' => 'avatarfile')); $this->element('input', array('name' => 'MAX_FILE_SIZE', 'type' => 'hidden', 'id' => 'MAX_FILE_SIZE', 'value' => MAX_AVATAR_SIZE)); + $this->elementEnd('li'); + $this->elementEnd('ul'); - $this->elementStart('p'); - - $this->element('input', array('name' => 'avatarfile', - 'type' => 'file', - 'id' => 'avatarfile')); - $this->elementEnd('p'); - + $this->elementStart('ul', 'form_actions'); + $this->elementStart('li'); $this->submit('upload', _('Upload')); + $this->elementEnd('li'); + $this->elementEnd('ul'); + + $this->elementEnd('fieldset'); $this->elementEnd('form'); } @@ -277,7 +286,7 @@ class AvatarsettingsAction extends AccountSettingsAction { parent::showStylesheets(); $jcropStyle = - common_path('js/jcrop/jquery.Jcrop.css?version='.LACONICA_VERSION); + common_path('theme/base/css/jquery.Jcrop.css?version='.LACONICA_VERSION); $this->element('link', array('rel' => 'stylesheet', 'type' => 'text/css', diff --git a/js/jcrop/jquery.Jcrop.go.js b/js/jcrop/jquery.Jcrop.go.js new file mode 100644 index 000000000..d5176c14c --- /dev/null +++ b/js/jcrop/jquery.Jcrop.go.js @@ -0,0 +1,41 @@ + $(function(){ + jQuery("#avatar_original img").Jcrop({ + onChange: showPreview, + setSelect: [ 0, 0, $("#avatar_original img").attr("width"), $("#avatar_original img").attr("height") ], + onSelect: updateCoords, + aspectRatio: 1, + boxWidth: 480, + boxHeight: 480, + bgColor: '#000', + bgOpacity: .4 + }); + }); + + function showPreview(coords) { + var rx = 96 / coords.w; + var ry = 96 / coords.h; + + var img_width = $("#avatar_original img").attr("width"); + var img_height = $("#avatar_original img").attr("height"); + + $('#avatar_preview img').css({ + width: Math.round(rx *img_width) + 'px', + height: Math.round(ry * img_height) + 'px', + marginLeft: '-' + Math.round(rx * coords.x) + 'px', + marginTop: '-' + Math.round(ry * coords.y) + 'px' + }); + }; + + function updateCoords(c) { + $('#avatar_crop_x').val(c.x); + $('#avatar_crop_y').val(c.y); + $('#avatar_crop_w').val(c.w); + $('#avatar_crop_h').val(c.h); + }; + + function checkCoords() { + if (parseInt($('#avatar_crop_w').val())) return true; + alert('Please select a crop region then press submit.'); + return false; + }; + diff --git a/js/jcrop/jquery.Jcrop.pack.js b/js/jcrop/jquery.Jcrop.pack.js new file mode 100644 index 000000000..aa82e8abe --- /dev/null +++ b/js/jcrop/jquery.Jcrop.pack.js @@ -0,0 +1,8 @@ +/** + * Jcrop v.0.9.5 (packed) + * (c) 2008 Kelly Hallman and DeepLiquid.com + * More information: http://deepliquid.com/content/Jcrop.html + * Released under MIT License - this header must remain with code + */ + +eval(function(p,a,c,k,e,d){e=function(c){return(c35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--){d[e(c)]=k[c]||e(c)}k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c])}}return p}('$.1n=7(G,F){d G=G,F=F;g(1p(G)!==\'2d\')G=$(G)[0];g(1p(F)!==\'2d\')F={};g(!(\'2x\'1a F))F.2x=$.3d.3e?K:M;g(!(\'2c\'1a F))F.2c=$.3d.3e?K:M;d 4f={2x:K,3W:\'4C\',1f:4D,3T:\'4Y\',3x:.6,3O:.4,3P:.5,53:5,3N:9,3D:5,51:14,25:0,2c:M,3I:M,3B:M,30:M,3A:M,49:0,4p:0,4k:8,3V:20,3X:3,2f:K,3n:[0,0],2z:[0,0],2O:[0,0],2D:7(){},2G:7(){}};d j=4f;21(F);d $I=$(G).B({16:\'1b\'});47($I,j.49,j.4p);d S=$I.W(),L=$I.U(),$12=$(\'<12 />\').W(S).U(L).1f(1L(\'4F\')).B({16:\'4H\',4B:j.3T});g(j.1f)$12.1f(j.1f);$I.54($12);d $34=$(\'\').3Y(\'2N\',$I.3Y(\'2N\')).B(\'16\',\'1b\').W(S).U(L);d $2C=$(\'<12 />\').W(1t(V)).U(1t(V)).B({1l:59,16:\'1b\',4o:\'4g\'}).1P($34);d $2g=$(\'<12 />\').W(1t(V)).U(1t(V)).B({1l:5b});d $28=$(\'<12 />\').B({16:\'1b\',1l:55}).3U($I).1P($2C,$2g);d 23=j.4k;d $1S=$(\'<12 />\').1f(1L(\'3v\')).W(S+(23*2)).U(L+(23*2)).B({16:\'1b\',R:D(-23),P:D(-23),1l:3R,1z:0}).3q(48);d 1I,1Q;d 2u=2Q(G),1q,1B,3i,58,3h,1O;g(\'36\'1a j){1I=j.36[0]/S;1Q=j.36[1]/L}d E=7(){d A=0,u=0,q=0,m=0,Z,Y;7 1A(z){d z=2T(z);q=A=z[0];m=u=z[1]};7 1y(z){d z=2T(z);Z=z[0]-q;Y=z[1]-m;q=z[0];m=z[1]};7 3f(){k[Z,Y]};7 2b(2y){d Z=2y[0],Y=2y[1];g(0>A+Z)Z-=Z+A;g(0>u+Y)Y-=Y+u;g(LS){15=S;h=N.17((15-A)/1k);13=1Z<0?u-h:h+u}}1g{15=q;h=3c/1k;13=1Z<0?u-h:u+h;g(13<0){13=0;w=N.17((13-u)*1k);15=1V<0?A-w:w+A}1g g(13>L){13=L;w=N.17(13-u)*1k;15=1V<0?A-w:w+A}}k 4E=3g(1F(A,u,15,13))};7 2T(p){g(p[0]<0)p[0]=0;g(p[1]<0)p[1]=0;g(p[0]>S)p[0]=S;g(p[1]>L)p[1]=L;k[p[0],p[1]]};7 1F(A,u,q,m){d 2R=A,3r=q,3o=u,3l=m;g(q2q))q=(1U>0)?(A+2q):(A-2q);g(2n&&(N.17(22)>2n))m=(22>0)?(u+2n):(u-2n);g(2i&&(N.17(22)<2i))m=(22>0)?(u+2i):(u-2i);g(2m&&(N.17(1U)<2m))q=(1U>0)?(A+2m):(A-2m);g(A<0){q-=A;A-=A}g(u<0){m-=u;u-=u}g(q<0){A-=q;q-=q}g(m<0){u-=m;m-=m}g(q>S){d X=q-S;A-=X;q-=X}g(m>L){d X=m-L;u-=X;m-=X}g(A>S){d X=A-L;m-=X;u-=X}g(u>L){d X=u-L;m-=X;u-=X}k 3g(1F(A,u,q,m))};7 3g(a){k{x:a[0],y:a[1],q:a[2],m:a[3],w:a[2]-a[0],h:a[3]-a[1]}};k{1F:1F,1A:1A,1y:1y,3f:3f,2b:2b,2K:2K,Q:Q}}();d J=7(){d 4v,4z,4y,1R,2U=4x;d 2F={};d H={};d 2E=K;d 1i=j.3D;g(j.30){2F={R:1Y(\'3C\').B(\'R\',$.3d.3e?D(-1):D(0)),3Q:1Y(\'3C\'),P:1Y(\'3z\'),3L:1Y(\'3z\')}}g(j.3A){H.t=1W(\'n\');H.b=1W(\'s\');H.r=1W(\'e\');H.l=1W(\'w\')}j.3B&&2Y([\'n\',\'s\',\'e\',\'w\']);j.3I&&2Y([\'1M\',\'11\',\'1s\',\'2e\']);7 1Y(1u){d 1J=$(\'<12 />\').B({16:\'1b\',1z:j.3O}).1f(1L(1u));$2C.1P(1J);k 1J};7 2W(T,3y){d 1J=$(\'<12 />\').3q(3b(T)).B({3p:T+\'-2A\',16:\'1b\',1l:3y});$2g.1P(1J);k 1J};7 3J(T){k 2W(T,2U++).B({R:D(-1i+1),P:D(-1i+1),1z:j.3P}).1f(1L(\'H\'))};7 1W(T){d s=j.3N,o=1i,h=s,w=s,t=o,l=o;1E(T){C\'n\':C\'s\':w=1t(V);O;C\'e\':C\'w\':h=1t(V);O}k 2W(T,2U++).W(w).U(h).B({R:D(-t+1),P:D(-l+1)})};7 2Y(2J){4U(i 1a 2J)H[2J[i]]=3J(2J[i])};7 31(c){d 3a=N.1K((c.h/2)-1i),35=N.1K((c.w/2)-1i),4V=4W=-1i+1,2a=c.w-1i,1X=c.h-1i,x,y;\'e\'1a H&&H.e.B({R:D(3a),P:D(2a)})&&H.w.B({R:D(3a)})&&H.s.B({R:D(1X),P:D(35)})&&H.n.B({P:D(35)});\'1s\'1a H&&H.1s.B({P:D(2a)})&&H.2e.B({R:D(1X),P:D(2a)})&&H.1M.B({R:D(1X)});\'b\'1a H&&H.b.B({R:D(1X)})&&H.r.B({P:D(2a)})};7 3K(x,y){$34.B({R:D(-y),P:D(-x)});$28.B({R:D(y),P:D(x)})};7 2A(w,h){$28.W(w).U(h)};7 3s(){d p=E.Q();E.1A([p.x,p.y]);E.1y([p.q,p.m])};7 2I(){g(1R)k 1e()};7 1e(){d c=E.Q();2A(c.w,c.h);3K(c.x,c.y);j.30&&2F[\'3L\'].B({P:D(c.w-1)})&&2F[\'3Q\'].B({R:D(c.h-1)});2E&&31(c);1R||1w();j.2D(2H(c))};7 1w(){$28.1w();$I.B(\'1z\',j.3x);1R=M};7 1r(){1o();$28.1v();$I.B(\'1z\',1);1R=K};7 1v(){1r();$I.B(\'1z\',1);1R=K};7 2t(){2E=M;31(E.Q());$2g.1w()};7 1o(){2E=K;$2g.1v()};7 2o(v){(3h=v)?1o():2t()};7 1h(){d c=E.Q();2o(K);3s()};1o();$2C.1P($(\'<12 />\').1f(1L(\'3v\')).3q(3b(\'1N\')).B({3p:\'1N\',16:\'1b\',1l:4M,1z:0}));k{2I:2I,1e:1e,1r:1r,1w:1w,1v:1v,2t:2t,1o:1o,2o:2o,1h:1h}}();d 1j=7(){d 2w=7(){},2v=7(){},2L=j.2x;g(!2L){$1S.3k(2B).2S(26).4N(26)}7 4j(){g(2L){$(3t).3k(2B).2S(26)}$1S.B({1l:4G})}7 4i(){g(2L){$(3t).3H(\'3k\',2B).3H(\'2S\',26)}$1S.B({1l:3R})}7 2B(e){2w(2r(e))};7 26(e){e.2j();e.2k();g(1q){1q=K;2v(2r(e));j.2G(2H(E.Q()));4i();2w=7(){};2v=7(){}}k K};7 1G(1N,1h){1q=M;2w=1N;2v=1h;4j();k K};7 1x(t){$1S.B(\'3p\',t)};$I.4s($1S);k{1G:1G,1x:1x}}();d 33=7(){d $24=$(\'<4w 1u="4L" />\').B({16:\'1b\',P:\'-4O\'}).57(43).56(2f).5a(41),$3S=$(\'<12 />\').B({16:\'1b\',4o:\'4g\'}).1P($24);7 2l(){g(j.2c){$24.1w();$24.4Z()}};7 41(e){$24.1v()};7 2f(e){g(!j.2f)k;d 42=1O,1C;1O=e.4Q?M:K;g(42!=1O){g(1O&&1q){1C=E.Q();1B=1C.w/1C.h}1g 1B=0;J.1e()}e.2k();e.2j();k K};7 29(e,x,y){E.2b([x,y]);J.2I();e.2j();e.2k()};7 43(e){g(e.4T)k M;2f(e);d 2h=1O?10:1;1E(e.5d){C 37:29(e,-2h,0);O;C 39:29(e,2h,0);O;C 38:29(e,0,-2h);O;C 40:29(e,0,2h);O;C 27:J.1r();O;C 9:k M}k K};g(j.2c)$3S.3U($I);k{2l:2l}}();7 D(n){k\'\'+1m(n)+\'D\'};7 1t(n){k\'\'+1m(n)+\'%\'};7 1L(44){k j.3W+\'-\'+44};7 2Q(G){d z=$(G).2y();k[z.P,z.R]};7 2r(e){k[(e.4q-2u[0]),(e.4r-2u[1])]};7 46(1u){g(1u!=3i){1j.1x(1u);3i=1u}};7 4a(19,z){2u=2Q(G);1j.1x(19==\'1N\'?19:19+\'-2A\');g(19==\'1N\')k 1j.1G(4e(z),2P);d 1C=E.Q();E.1A(E.2K(4b(19)));1j.1G(45(19,1C),2P)};7 45(19,f){k 7(z){g(!j.25&&!1B)1E(19){C\'e\':z[1]=f.m;O;C\'w\':z[1]=f.m;O;C\'n\':z[0]=f.q;O;C\'s\':z[0]=f.q;O}1g 1E(19){C\'e\':z[1]=f.y+1;O;C\'w\':z[1]=f.y+1;O;C\'n\':z[0]=f.x+1;O;C\'s\':z[0]=f.x+1;O}E.1y(z);J.1e()}};7 4e(z){d 2M=z;33.2l();k 7(z){E.2b([z[0]-2M[0],z[1]-2M[1]]);2M=z;J.1e()}};7 4b(T){1E(T){C\'n\':k\'1M\';C\'s\':k\'11\';C\'e\':k\'11\';C\'w\':k\'1s\';C\'1s\':k\'1M\';C\'11\':k\'2e\';C\'2e\':k\'11\';C\'1M\':k\'1s\'}};7 3b(T){k 7(e){1q=M;4a(T,2r(e));e.2k();e.2j();k K}};7 47($G,w,h){d 11=$G.W(),1H=$G.U();g((11>w)&&w>0){11=w;1H=(w/$G.W())*$G.U()}g((1H>h)&&h>0){1H=h;11=(h/$G.U())*$G.W()}1I=$G.W()/11;1Q=$G.U()/1H;$G.W(11).U(1H)};7 2H(c){k{x:1m(c.x*1I),y:1m(c.y*1Q),q:1m(c.q*1I),m:1m(c.m*1Q),w:1m(c.w*1I),h:1m(c.h*1Q)}};7 2P(z){d c=E.Q();g(c.w>j.3n[0]&&c.h>j.3n[1]){J.2t();J.1h()}1g{J.1r()}1j.1x(\'2X\')};7 48(e){1q=M;2u=2Q(G);J.1r();J.1o();46(\'2X\');E.1A(2r(e));1j.1G(4c,2P);33.2l();e.2k();e.2j();k K};7 4c(z){E.1y(z);J.1e()};7 2Z(a){d A=a[0],u=a[1],q=a[2],m=a[3];g(3h)k;d 2s=E.1F(A,u,q,m);d c=E.Q();d 18=2p=[c.x,c.y,c.q,c.m];d 3w=j.3V;d x=18[0];d y=18[1];d q=18[2];d m=18[3];d 3Z=2s[0]-2p[0];d 4m=2s[1]-2p[1];d 4n=2s[2]-2p[2];d 4l=2s[3]-2p[3];d 1c=0;d 4h=j.3X;J.2o(M);d 3u=7(){k 7(){1c+=(V-1c)/4h;18[0]=x+((1c/V)*3Z);18[1]=y+((1c/V)*4m);18[2]=q+((1c/V)*4n);18[3]=m+((1c/V)*4l);g(1c=4K.8)1c=V;1d(18)}}();7 32(){4I.4t(3u,3w)};32()};7 1d(l){E.1A([l[0],l[1]]);E.1y([l[2],l[3]]);J.1e()};7 21(F){g(1p(F)!=\'2d\')F={};j=$.4X(j,F);g(1p(j.2D)!==\'7\')j.2D=7(){};g(1p(j.2G)!==\'7\')j.2G=7(){}};7 3m(){k 2H(E.Q())};7 2V(){k E.Q()};7 3E(F){21(F);g(\'1d\'1a F){1d(F.1d);J.1h()}};g(1p(F)!=\'2d\')F={};g(\'1d\'1a F){1d(F.1d);J.1h()}d 2q=j.2z[0]||0;d 2n=j.2z[1]||0;d 2m=j.2O[0]||0;d 2i=j.2O[1]||0;1j.1x(\'2X\');k{2Z:2Z,1d:1d,21:3E,3m:3m,2V:2V}};$.5e.1n=7(j){7 3G(1D){d 4d=j.4R||1D.2N;d I=4P 4S();d 1D=1D;I.50=7(){$(1D).1v().4A(I);1D.1n=$.1n(I,j)};I.2N=4d};g(1p(j)!==\'2d\')j={};1T.4J(7(){g(\'1n\'1a 1T){g(j==\'52\')k 1T.1n;1g 1T.1n.21(j)}1g 3G(1T)});k 1T};',62,325,'|||||||function||||||var|||if|||options|return||y2||||x2||||y1|||||pos|x1|css|case|px|Coords|opt|obj|handle|img|Selection|false|boundy|true|Math|break|left|getFixed|top|boundx|ord|height|100|width|delta|oy|ox||nw|div|yy||xx|position|abs|animat|mode|in|absolute|pcent|setSelect|update|addClass|else|done|hhs|Tracker|aspect|zIndex|parseInt|Jcrop|disableHandles|typeof|btndown|release|ne|pct|type|hide|show|setCursor|setCurrent|opacity|setPressed|aspectLock|fc|from|switch|flipCoords|activateHandlers|nh|xscale|jq|round|cssClass|sw|move|shift_down|append|yscale|awake|trk|this|xsize|rw|insertDragbar|south|insertBorder|rh||setOptions|ysize|bound|keymgr|aspectRatio|trackUp||sel|doNudge|east|moveOffset|keySupport|object|se|watchShift|hdl_holder|nudge|ymin|preventDefault|stopPropagation|watchKeys|xmin|ylimit|animMode|initcr|xlimit|mouseAbs|animto|enableHandles|docOffset|onDone|onMove|trackDocument|offset|maxSize|resize|trackMove|img_holder|onChange|seehandles|borders|onSelect|unscale|updateVisible|li|getCorner|trackDoc|lloc|src|minSize|doneSelect|getPos|xa|mouseup|rebound|hdep|tellScaled|dragDiv|crosshair|createHandles|animateTo|drawBorders|moveHandles|animateStart|KeyManager|img2|midhoriz|trueSize||||midvert|createDragger|rwa|browser|msie|getOffset|makeObj|animating|lastcurs|rha|mousemove|yb|tellSelect|minSelect|ya|cursor|mousedown|xb|refresh|document|animator|tracker|interv|bgOpacity|zi|vline|dragEdges|sideHandles|hline|handleOffset|setOptionsNew|getRect|attachWhenDone|unbind|cornerHandles|insertHandle|moveto|right|real_ratio|handleSize|borderOpacity|handleOpacity|bottom|290|keywrap|bgColor|insertBefore|animationDelay|baseClass|swingSpeed|attr|ix1||onBlur|init_shift|parseKey|cl|dragmodeHandler|myCursor|presize|newSelection|boxWidth|startDragMode|oppLockCorner|selectDrag|loadsrc|createMover|defaults|hidden|velocity|toBack|toFront|boundary|iy2|iy1|ix2|overflow|boxHeight|pageX|pageY|before|setTimeout|max|start|input|370|dragmode|end|after|backgroundColor|jcrop|null|last|holder|450|relative|window|each|99|radio|360|mouseout|30px|new|shiftKey|useImg|Image|ctrlKey|for|north|west|extend|black|focus|onload|edgeMargin|api|handlePad|wrap|300|keyup|keydown|dimmed|310|blur|320|min|keyCode|fn'.split('|'),0,{})) diff --git a/js/jquery.Jcrop.go.js b/js/jquery.Jcrop.go.js deleted file mode 100644 index e5d587354..000000000 --- a/js/jquery.Jcrop.go.js +++ /dev/null @@ -1,41 +0,0 @@ - $(function(){ - jQuery("#photo_original img").Jcrop({ - onChange: showPreview, - setSelect: [ 0, 0, $("#photo_original img").attr("width"), $("#photo_original img").attr("height") ], - onSelect: updateCoords, - aspectRatio: 1, - boxWidth: 480, - boxHeight: 480, - bgColor: '#000', - bgOpacity: .4 - }); - }); - - function showPreview(coords) { - var rx = 96 / coords.w; - var ry = 96 / coords.h; - - var img_width = $("#photo_original img").attr("width"); - var img_height = $("#photo_original img").attr("height"); - - $('#photo_preview img').css({ - width: Math.round(rx *img_width) + 'px', - height: Math.round(ry * img_height) + 'px', - marginLeft: '-' + Math.round(rx * coords.x) + 'px', - marginTop: '-' + Math.round(ry * coords.y) + 'px' - }); - }; - - function updateCoords(c) { - $('#photo_crop_x').val(c.x); - $('#photo_crop_y').val(c.y); - $('#photo_crop_w').val(c.w); - $('#photo_crop_h').val(c.h); - }; - - function checkCoords() { - if (parseInt($('#photo_crop_w').val())) return true; - alert('Please select a crop region then press submit.'); - return false; - }; - diff --git a/js/jquery.Jcrop.pack.js b/js/jquery.Jcrop.pack.js deleted file mode 100644 index aa82e8abe..000000000 --- a/js/jquery.Jcrop.pack.js +++ /dev/null @@ -1,8 +0,0 @@ -/** - * Jcrop v.0.9.5 (packed) - * (c) 2008 Kelly Hallman and DeepLiquid.com - * More information: http://deepliquid.com/content/Jcrop.html - * Released under MIT License - this header must remain with code - */ - -eval(function(p,a,c,k,e,d){e=function(c){return(c35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--){d[e(c)]=k[c]||e(c)}k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c])}}return p}('$.1n=7(G,F){d G=G,F=F;g(1p(G)!==\'2d\')G=$(G)[0];g(1p(F)!==\'2d\')F={};g(!(\'2x\'1a F))F.2x=$.3d.3e?K:M;g(!(\'2c\'1a F))F.2c=$.3d.3e?K:M;d 4f={2x:K,3W:\'4C\',1f:4D,3T:\'4Y\',3x:.6,3O:.4,3P:.5,53:5,3N:9,3D:5,51:14,25:0,2c:M,3I:M,3B:M,30:M,3A:M,49:0,4p:0,4k:8,3V:20,3X:3,2f:K,3n:[0,0],2z:[0,0],2O:[0,0],2D:7(){},2G:7(){}};d j=4f;21(F);d $I=$(G).B({16:\'1b\'});47($I,j.49,j.4p);d S=$I.W(),L=$I.U(),$12=$(\'<12 />\').W(S).U(L).1f(1L(\'4F\')).B({16:\'4H\',4B:j.3T});g(j.1f)$12.1f(j.1f);$I.54($12);d $34=$(\'\').3Y(\'2N\',$I.3Y(\'2N\')).B(\'16\',\'1b\').W(S).U(L);d $2C=$(\'<12 />\').W(1t(V)).U(1t(V)).B({1l:59,16:\'1b\',4o:\'4g\'}).1P($34);d $2g=$(\'<12 />\').W(1t(V)).U(1t(V)).B({1l:5b});d $28=$(\'<12 />\').B({16:\'1b\',1l:55}).3U($I).1P($2C,$2g);d 23=j.4k;d $1S=$(\'<12 />\').1f(1L(\'3v\')).W(S+(23*2)).U(L+(23*2)).B({16:\'1b\',R:D(-23),P:D(-23),1l:3R,1z:0}).3q(48);d 1I,1Q;d 2u=2Q(G),1q,1B,3i,58,3h,1O;g(\'36\'1a j){1I=j.36[0]/S;1Q=j.36[1]/L}d E=7(){d A=0,u=0,q=0,m=0,Z,Y;7 1A(z){d z=2T(z);q=A=z[0];m=u=z[1]};7 1y(z){d z=2T(z);Z=z[0]-q;Y=z[1]-m;q=z[0];m=z[1]};7 3f(){k[Z,Y]};7 2b(2y){d Z=2y[0],Y=2y[1];g(0>A+Z)Z-=Z+A;g(0>u+Y)Y-=Y+u;g(LS){15=S;h=N.17((15-A)/1k);13=1Z<0?u-h:h+u}}1g{15=q;h=3c/1k;13=1Z<0?u-h:u+h;g(13<0){13=0;w=N.17((13-u)*1k);15=1V<0?A-w:w+A}1g g(13>L){13=L;w=N.17(13-u)*1k;15=1V<0?A-w:w+A}}k 4E=3g(1F(A,u,15,13))};7 2T(p){g(p[0]<0)p[0]=0;g(p[1]<0)p[1]=0;g(p[0]>S)p[0]=S;g(p[1]>L)p[1]=L;k[p[0],p[1]]};7 1F(A,u,q,m){d 2R=A,3r=q,3o=u,3l=m;g(q2q))q=(1U>0)?(A+2q):(A-2q);g(2n&&(N.17(22)>2n))m=(22>0)?(u+2n):(u-2n);g(2i&&(N.17(22)<2i))m=(22>0)?(u+2i):(u-2i);g(2m&&(N.17(1U)<2m))q=(1U>0)?(A+2m):(A-2m);g(A<0){q-=A;A-=A}g(u<0){m-=u;u-=u}g(q<0){A-=q;q-=q}g(m<0){u-=m;m-=m}g(q>S){d X=q-S;A-=X;q-=X}g(m>L){d X=m-L;u-=X;m-=X}g(A>S){d X=A-L;m-=X;u-=X}g(u>L){d X=u-L;m-=X;u-=X}k 3g(1F(A,u,q,m))};7 3g(a){k{x:a[0],y:a[1],q:a[2],m:a[3],w:a[2]-a[0],h:a[3]-a[1]}};k{1F:1F,1A:1A,1y:1y,3f:3f,2b:2b,2K:2K,Q:Q}}();d J=7(){d 4v,4z,4y,1R,2U=4x;d 2F={};d H={};d 2E=K;d 1i=j.3D;g(j.30){2F={R:1Y(\'3C\').B(\'R\',$.3d.3e?D(-1):D(0)),3Q:1Y(\'3C\'),P:1Y(\'3z\'),3L:1Y(\'3z\')}}g(j.3A){H.t=1W(\'n\');H.b=1W(\'s\');H.r=1W(\'e\');H.l=1W(\'w\')}j.3B&&2Y([\'n\',\'s\',\'e\',\'w\']);j.3I&&2Y([\'1M\',\'11\',\'1s\',\'2e\']);7 1Y(1u){d 1J=$(\'<12 />\').B({16:\'1b\',1z:j.3O}).1f(1L(1u));$2C.1P(1J);k 1J};7 2W(T,3y){d 1J=$(\'<12 />\').3q(3b(T)).B({3p:T+\'-2A\',16:\'1b\',1l:3y});$2g.1P(1J);k 1J};7 3J(T){k 2W(T,2U++).B({R:D(-1i+1),P:D(-1i+1),1z:j.3P}).1f(1L(\'H\'))};7 1W(T){d s=j.3N,o=1i,h=s,w=s,t=o,l=o;1E(T){C\'n\':C\'s\':w=1t(V);O;C\'e\':C\'w\':h=1t(V);O}k 2W(T,2U++).W(w).U(h).B({R:D(-t+1),P:D(-l+1)})};7 2Y(2J){4U(i 1a 2J)H[2J[i]]=3J(2J[i])};7 31(c){d 3a=N.1K((c.h/2)-1i),35=N.1K((c.w/2)-1i),4V=4W=-1i+1,2a=c.w-1i,1X=c.h-1i,x,y;\'e\'1a H&&H.e.B({R:D(3a),P:D(2a)})&&H.w.B({R:D(3a)})&&H.s.B({R:D(1X),P:D(35)})&&H.n.B({P:D(35)});\'1s\'1a H&&H.1s.B({P:D(2a)})&&H.2e.B({R:D(1X),P:D(2a)})&&H.1M.B({R:D(1X)});\'b\'1a H&&H.b.B({R:D(1X)})&&H.r.B({P:D(2a)})};7 3K(x,y){$34.B({R:D(-y),P:D(-x)});$28.B({R:D(y),P:D(x)})};7 2A(w,h){$28.W(w).U(h)};7 3s(){d p=E.Q();E.1A([p.x,p.y]);E.1y([p.q,p.m])};7 2I(){g(1R)k 1e()};7 1e(){d c=E.Q();2A(c.w,c.h);3K(c.x,c.y);j.30&&2F[\'3L\'].B({P:D(c.w-1)})&&2F[\'3Q\'].B({R:D(c.h-1)});2E&&31(c);1R||1w();j.2D(2H(c))};7 1w(){$28.1w();$I.B(\'1z\',j.3x);1R=M};7 1r(){1o();$28.1v();$I.B(\'1z\',1);1R=K};7 1v(){1r();$I.B(\'1z\',1);1R=K};7 2t(){2E=M;31(E.Q());$2g.1w()};7 1o(){2E=K;$2g.1v()};7 2o(v){(3h=v)?1o():2t()};7 1h(){d c=E.Q();2o(K);3s()};1o();$2C.1P($(\'<12 />\').1f(1L(\'3v\')).3q(3b(\'1N\')).B({3p:\'1N\',16:\'1b\',1l:4M,1z:0}));k{2I:2I,1e:1e,1r:1r,1w:1w,1v:1v,2t:2t,1o:1o,2o:2o,1h:1h}}();d 1j=7(){d 2w=7(){},2v=7(){},2L=j.2x;g(!2L){$1S.3k(2B).2S(26).4N(26)}7 4j(){g(2L){$(3t).3k(2B).2S(26)}$1S.B({1l:4G})}7 4i(){g(2L){$(3t).3H(\'3k\',2B).3H(\'2S\',26)}$1S.B({1l:3R})}7 2B(e){2w(2r(e))};7 26(e){e.2j();e.2k();g(1q){1q=K;2v(2r(e));j.2G(2H(E.Q()));4i();2w=7(){};2v=7(){}}k K};7 1G(1N,1h){1q=M;2w=1N;2v=1h;4j();k K};7 1x(t){$1S.B(\'3p\',t)};$I.4s($1S);k{1G:1G,1x:1x}}();d 33=7(){d $24=$(\'<4w 1u="4L" />\').B({16:\'1b\',P:\'-4O\'}).57(43).56(2f).5a(41),$3S=$(\'<12 />\').B({16:\'1b\',4o:\'4g\'}).1P($24);7 2l(){g(j.2c){$24.1w();$24.4Z()}};7 41(e){$24.1v()};7 2f(e){g(!j.2f)k;d 42=1O,1C;1O=e.4Q?M:K;g(42!=1O){g(1O&&1q){1C=E.Q();1B=1C.w/1C.h}1g 1B=0;J.1e()}e.2k();e.2j();k K};7 29(e,x,y){E.2b([x,y]);J.2I();e.2j();e.2k()};7 43(e){g(e.4T)k M;2f(e);d 2h=1O?10:1;1E(e.5d){C 37:29(e,-2h,0);O;C 39:29(e,2h,0);O;C 38:29(e,0,-2h);O;C 40:29(e,0,2h);O;C 27:J.1r();O;C 9:k M}k K};g(j.2c)$3S.3U($I);k{2l:2l}}();7 D(n){k\'\'+1m(n)+\'D\'};7 1t(n){k\'\'+1m(n)+\'%\'};7 1L(44){k j.3W+\'-\'+44};7 2Q(G){d z=$(G).2y();k[z.P,z.R]};7 2r(e){k[(e.4q-2u[0]),(e.4r-2u[1])]};7 46(1u){g(1u!=3i){1j.1x(1u);3i=1u}};7 4a(19,z){2u=2Q(G);1j.1x(19==\'1N\'?19:19+\'-2A\');g(19==\'1N\')k 1j.1G(4e(z),2P);d 1C=E.Q();E.1A(E.2K(4b(19)));1j.1G(45(19,1C),2P)};7 45(19,f){k 7(z){g(!j.25&&!1B)1E(19){C\'e\':z[1]=f.m;O;C\'w\':z[1]=f.m;O;C\'n\':z[0]=f.q;O;C\'s\':z[0]=f.q;O}1g 1E(19){C\'e\':z[1]=f.y+1;O;C\'w\':z[1]=f.y+1;O;C\'n\':z[0]=f.x+1;O;C\'s\':z[0]=f.x+1;O}E.1y(z);J.1e()}};7 4e(z){d 2M=z;33.2l();k 7(z){E.2b([z[0]-2M[0],z[1]-2M[1]]);2M=z;J.1e()}};7 4b(T){1E(T){C\'n\':k\'1M\';C\'s\':k\'11\';C\'e\':k\'11\';C\'w\':k\'1s\';C\'1s\':k\'1M\';C\'11\':k\'2e\';C\'2e\':k\'11\';C\'1M\':k\'1s\'}};7 3b(T){k 7(e){1q=M;4a(T,2r(e));e.2k();e.2j();k K}};7 47($G,w,h){d 11=$G.W(),1H=$G.U();g((11>w)&&w>0){11=w;1H=(w/$G.W())*$G.U()}g((1H>h)&&h>0){1H=h;11=(h/$G.U())*$G.W()}1I=$G.W()/11;1Q=$G.U()/1H;$G.W(11).U(1H)};7 2H(c){k{x:1m(c.x*1I),y:1m(c.y*1Q),q:1m(c.q*1I),m:1m(c.m*1Q),w:1m(c.w*1I),h:1m(c.h*1Q)}};7 2P(z){d c=E.Q();g(c.w>j.3n[0]&&c.h>j.3n[1]){J.2t();J.1h()}1g{J.1r()}1j.1x(\'2X\')};7 48(e){1q=M;2u=2Q(G);J.1r();J.1o();46(\'2X\');E.1A(2r(e));1j.1G(4c,2P);33.2l();e.2k();e.2j();k K};7 4c(z){E.1y(z);J.1e()};7 2Z(a){d A=a[0],u=a[1],q=a[2],m=a[3];g(3h)k;d 2s=E.1F(A,u,q,m);d c=E.Q();d 18=2p=[c.x,c.y,c.q,c.m];d 3w=j.3V;d x=18[0];d y=18[1];d q=18[2];d m=18[3];d 3Z=2s[0]-2p[0];d 4m=2s[1]-2p[1];d 4n=2s[2]-2p[2];d 4l=2s[3]-2p[3];d 1c=0;d 4h=j.3X;J.2o(M);d 3u=7(){k 7(){1c+=(V-1c)/4h;18[0]=x+((1c/V)*3Z);18[1]=y+((1c/V)*4m);18[2]=q+((1c/V)*4n);18[3]=m+((1c/V)*4l);g(1c=4K.8)1c=V;1d(18)}}();7 32(){4I.4t(3u,3w)};32()};7 1d(l){E.1A([l[0],l[1]]);E.1y([l[2],l[3]]);J.1e()};7 21(F){g(1p(F)!=\'2d\')F={};j=$.4X(j,F);g(1p(j.2D)!==\'7\')j.2D=7(){};g(1p(j.2G)!==\'7\')j.2G=7(){}};7 3m(){k 2H(E.Q())};7 2V(){k E.Q()};7 3E(F){21(F);g(\'1d\'1a F){1d(F.1d);J.1h()}};g(1p(F)!=\'2d\')F={};g(\'1d\'1a F){1d(F.1d);J.1h()}d 2q=j.2z[0]||0;d 2n=j.2z[1]||0;d 2m=j.2O[0]||0;d 2i=j.2O[1]||0;1j.1x(\'2X\');k{2Z:2Z,1d:1d,21:3E,3m:3m,2V:2V}};$.5e.1n=7(j){7 3G(1D){d 4d=j.4R||1D.2N;d I=4P 4S();d 1D=1D;I.50=7(){$(1D).1v().4A(I);1D.1n=$.1n(I,j)};I.2N=4d};g(1p(j)!==\'2d\')j={};1T.4J(7(){g(\'1n\'1a 1T){g(j==\'52\')k 1T.1n;1g 1T.1n.21(j)}1g 3G(1T)});k 1T};',62,325,'|||||||function||||||var|||if|||options|return||y2||||x2||||y1|||||pos|x1|css|case|px|Coords|opt|obj|handle|img|Selection|false|boundy|true|Math|break|left|getFixed|top|boundx|ord|height|100|width|delta|oy|ox||nw|div|yy||xx|position|abs|animat|mode|in|absolute|pcent|setSelect|update|addClass|else|done|hhs|Tracker|aspect|zIndex|parseInt|Jcrop|disableHandles|typeof|btndown|release|ne|pct|type|hide|show|setCursor|setCurrent|opacity|setPressed|aspectLock|fc|from|switch|flipCoords|activateHandlers|nh|xscale|jq|round|cssClass|sw|move|shift_down|append|yscale|awake|trk|this|xsize|rw|insertDragbar|south|insertBorder|rh||setOptions|ysize|bound|keymgr|aspectRatio|trackUp||sel|doNudge|east|moveOffset|keySupport|object|se|watchShift|hdl_holder|nudge|ymin|preventDefault|stopPropagation|watchKeys|xmin|ylimit|animMode|initcr|xlimit|mouseAbs|animto|enableHandles|docOffset|onDone|onMove|trackDocument|offset|maxSize|resize|trackMove|img_holder|onChange|seehandles|borders|onSelect|unscale|updateVisible|li|getCorner|trackDoc|lloc|src|minSize|doneSelect|getPos|xa|mouseup|rebound|hdep|tellScaled|dragDiv|crosshair|createHandles|animateTo|drawBorders|moveHandles|animateStart|KeyManager|img2|midhoriz|trueSize||||midvert|createDragger|rwa|browser|msie|getOffset|makeObj|animating|lastcurs|rha|mousemove|yb|tellSelect|minSelect|ya|cursor|mousedown|xb|refresh|document|animator|tracker|interv|bgOpacity|zi|vline|dragEdges|sideHandles|hline|handleOffset|setOptionsNew|getRect|attachWhenDone|unbind|cornerHandles|insertHandle|moveto|right|real_ratio|handleSize|borderOpacity|handleOpacity|bottom|290|keywrap|bgColor|insertBefore|animationDelay|baseClass|swingSpeed|attr|ix1||onBlur|init_shift|parseKey|cl|dragmodeHandler|myCursor|presize|newSelection|boxWidth|startDragMode|oppLockCorner|selectDrag|loadsrc|createMover|defaults|hidden|velocity|toBack|toFront|boundary|iy2|iy1|ix2|overflow|boxHeight|pageX|pageY|before|setTimeout|max|start|input|370|dragmode|end|after|backgroundColor|jcrop|null|last|holder|450|relative|window|each|99|radio|360|mouseout|30px|new|shiftKey|useImg|Image|ctrlKey|for|north|west|extend|black|focus|onload|edgeMargin|api|handlePad|wrap|300|keyup|keydown|dimmed|310|blur|320|min|keyCode|fn'.split('|'),0,{})) diff --git a/theme/base/css/display.css b/theme/base/css/display.css index 18205fceb..cfe445a98 100644 --- a/theme/base/css/display.css +++ b/theme/base/css/display.css @@ -148,7 +148,8 @@ font-weight:bold; #form_settings_profile legend, #form_login legend, #form_register legend, -#form_password legend { +#form_password legend, +#form_settings_avatar legend { display:none; } @@ -1161,21 +1162,34 @@ clear:both; - -#photo_original, -#photo_preview { +#form_settings_avatar li { +width:auto; +} +#form_settings_avatar input { +margin-left:0; +} +#avatar_original, +#avatar_preview { float:left; } -#photo_preview, -#settings_photo_action-crop { +#avatar_preview { margin-left:29px; } -#photo_preview_view { +#avatar_preview_view { height:96px; width:96px; +margin-bottom:18px; overflow:hidden; } +#settings_attach, +#form_settings_avatar .form_actions { +clear:both; +} + +#form_settings_avatar .form_actions { +margin-bottom:0; +} -- cgit v1.2.3-54-g00ecf From 6a3204d08e035812cf111e20f72bf0c7ffb4c601 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Thu, 22 Jan 2009 12:35:09 +0100 Subject: Extract image management code to a helper function --- actions/avatarsettings.php | 39 +++-------------- lib/imagefile.php | 105 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 111 insertions(+), 33 deletions(-) create mode 100644 lib/imagefile.php (limited to 'actions/avatarsettings.php') diff --git a/actions/avatarsettings.php b/actions/avatarsettings.php index a9b381b0a..b303fd2fd 100644 --- a/actions/avatarsettings.php +++ b/actions/avatarsettings.php @@ -196,37 +196,10 @@ class AvatarsettingsAction extends AccountSettingsAction function uploadAvatar() { - switch ($_FILES['avatarfile']['error']) { - case UPLOAD_ERR_OK: // success, jump out - break; - case UPLOAD_ERR_INI_SIZE: - case UPLOAD_ERR_FORM_SIZE: - $this->showForm(_('That file is too big.')); - return; - case UPLOAD_ERR_PARTIAL: - @unlink($_FILES['avatarfile']['tmp_name']); - $this->showForm(_('Partial upload.')); - return; - default: - $this->showForm(_('System error uploading file.')); - return; - } - - $info = @getimagesize($_FILES['avatarfile']['tmp_name']); - - if (!$info) { - @unlink($_FILES['avatarfile']['tmp_name']); - $this->showForm(_('Not an image or corrupt file.')); - return; - } - - switch ($info[2]) { - case IMAGETYPE_GIF: - case IMAGETYPE_JPEG: - case IMAGETYPE_PNG: - break; - default: - $this->showForm(_('Unsupported image file format.')); + try { + $imagefile = ImageFile::fromUpload('avatarfile'); + } catch (Exception $e) { + $this->showForm($e->getMessage()); return; } @@ -234,13 +207,13 @@ class AvatarsettingsAction extends AccountSettingsAction $profile = $user->getProfile(); - if ($profile->setOriginal($_FILES['avatarfile']['tmp_name'])) { + if ($profile->setOriginal($imagefile->filename)) { $this->showForm(_('Avatar updated.'), true); } else { $this->showForm(_('Failed updating avatar.')); } - @unlink($_FILES['avatarfile']['tmp_name']); + $imagefile->unlink(); } /** diff --git a/lib/imagefile.php b/lib/imagefile.php new file mode 100644 index 000000000..f15a72c76 --- /dev/null +++ b/lib/imagefile.php @@ -0,0 +1,105 @@ +. + * + * @category Image + * @package Laconica + * @author Evan Prodromou + * @author Zach Copley + * @copyright 2008-2009 Control Yourself, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + */ + +if (!defined('LACONICA')) { + exit(1); +} + +/** + * A wrapper on uploaded files + * + * Makes it slightly easier to accept an image file from upload. + * + * @category Image + * @package Laconica + * @author Evan Prodromou + * @author Zach Copley + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + */ + +class ImageFile +{ + var $filename = null; + var $type = null; + + function __construct($filename=null, $type=null) + { + $this->filename = $filename; + $this->type = $type; + } + + static function fromUpload($param='upload') + { + switch ($_FILES[$param]['error']) { + case UPLOAD_ERR_OK: // success, jump out + break; + case UPLOAD_ERR_INI_SIZE: + case UPLOAD_ERR_FORM_SIZE: + throw new Exception(_('That file is too big.')); + return; + case UPLOAD_ERR_PARTIAL: + @unlink($_FILES[$param]['tmp_name']); + throw new Exception(_('Partial upload.')); + return; + default: + throw new Exception(_('System error uploading file.')); + return; + } + + $imagefile = new ImageFile($_FILES[$param]['tmp_name']); + $info = @getimagesize($imagefile->filename); + + if (!$info) { + @unlink($imagefile->filename); + throw new Exception(_('Not an image or corrupt file.')); + return; + } + + switch ($info[2]) { + case IMAGETYPE_GIF: + case IMAGETYPE_JPEG: + case IMAGETYPE_PNG: + $imagefile->type = $info[2]; + break; + default: + @unlink($imagefile->filename); + throw new Exception(_('Unsupported image file format.')); + return; + } + + return $imagefile; + } + + function unlink() + { + @unlink($this->filename); + } +} \ No newline at end of file -- cgit v1.2.3-54-g00ecf From 9dc5d8d0f6db1249a62162877c81d240fcf32a0a Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Fri, 23 Jan 2009 06:16:55 +0100 Subject: Made avatar upload a two-stage process; first upload, then crop --- actions/avatarsettings.php | 190 ++++++++++++++++++++++++++++++++++++++++----- lib/imagefile.php | 10 ++- 2 files changed, 179 insertions(+), 21 deletions(-) (limited to 'actions/avatarsettings.php') diff --git a/actions/avatarsettings.php b/actions/avatarsettings.php index 2c7af9b7a..1db35237e 100644 --- a/actions/avatarsettings.php +++ b/actions/avatarsettings.php @@ -50,6 +50,10 @@ require_once INSTALLDIR.'/lib/accountsettingsaction.php'; class AvatarsettingsAction extends AccountSettingsAction { + var $mode = null; + var $imagefile = null; + var $filename = null; + /** * Title of the page * @@ -69,7 +73,7 @@ class AvatarsettingsAction extends AccountSettingsAction function getInstructions() { - return _('Set your personal avatar.'); + return _('You can upload your personal avatar.'); } /** @@ -81,6 +85,15 @@ class AvatarsettingsAction extends AccountSettingsAction */ function showContent() + { + if ($this->mode == 'crop') { + $this->showCropForm(); + } else { + $this->showUploadForm(); + } + } + + function showUploadForm() { $user = common_current_user(); @@ -132,16 +145,6 @@ class AvatarsettingsAction extends AccountSettingsAction 'height' => AVATAR_PROFILE_SIZE, 'alt' => $user->nickname)); $this->elementEnd('div'); - - foreach (array('avatar_crop_x', 'avatar_crop_y', - 'avatar_crop_w', 'avatar_crop_h') as $crop_info) { - $this->element('input', array('name' => $crop_info, - 'type' => 'hidden', - 'id' => $crop_info)); - } - $this->submit('crop', _('Crop')); - - $this->elementEnd('li'); } $this->elementStart('li', array ('id' => 'settings_attach')); @@ -166,6 +169,69 @@ class AvatarsettingsAction extends AccountSettingsAction } + function showCropForm() + { + $user = common_current_user(); + + $profile = $user->getProfile(); + + if (!$profile) { + common_log_db_error($user, 'SELECT', __FILE__); + $this->serverError(_('User without matching profile')); + return; + } + + $original = $profile->getOriginalAvatar(); + + $this->elementStart('form', array('method' => 'post', + 'id' => 'form_settings_avatar', + 'class' => 'form_settings', + 'action' => + common_local_url('avatarsettings'))); + $this->elementStart('fieldset'); + $this->element('legend', null, _('Avatar settings')); + $this->hidden('token', common_session_token()); + + $this->elementStart('ul', 'form_data'); + + $this->elementStart('li', + array('id' => 'avatar_original', + 'class' => 'avatar_view')); + $this->element('h2', null, _("Original")); + $this->elementStart('div', array('id'=>'avatar_original_view')); + $this->element('img', array('src' => common_avatar_url($this->filedata['filename']), + 'width' => $this->filedata['width'], + 'height' => $this->filedata['height'], + 'alt' => $user->nickname)); + $this->elementEnd('div'); + $this->elementEnd('li'); + + $this->elementStart('li', + array('id' => 'avatar_preview', + 'class' => 'avatar_view')); + $this->element('h2', null, _("Preview")); + $this->elementStart('div', array('id'=>'avatar_preview_view')); + $this->element('img', array('src' => common_avatar_url($this->filedata['filename']), + 'width' => AVATAR_PROFILE_SIZE, + 'height' => AVATAR_PROFILE_SIZE, + 'alt' => $user->nickname)); + $this->elementEnd('div'); + + foreach (array('avatar_crop_x', 'avatar_crop_y', + 'avatar_crop_w', 'avatar_crop_h') as $crop_info) { + $this->element('input', array('name' => $crop_info, + 'type' => 'hidden', + 'id' => $crop_info)); + } + $this->submit('crop', _('Crop')); + + $this->elementEnd('li'); + $this->elementEnd('ul'); + $this->elementEnd('fieldset'); + $this->elementEnd('form'); + + } + /** * Handle a post * @@ -212,17 +278,31 @@ class AvatarsettingsAction extends AccountSettingsAction return; } - $user = common_current_user(); + $cur = common_current_user(); - $profile = $user->getProfile(); + $filename = common_avatar_filename($cur->id, + image_type_to_extension($imagefile->type), + null, + 'tmp'.common_timestamp()); - if ($profile->setOriginal($imagefile->filename)) { - $this->showForm(_('Avatar updated.'), true); - } else { - $this->showForm(_('Failed updating avatar.')); - } + $filepath = common_avatar_path($filename); - $imagefile->unlink(); + move_uploaded_file($imagefile->filename, $filepath); + + $filedata = array('filename' => $filename, + 'filepath' => $filepath, + 'width' => $imagefile->width, + 'height' => $imagefile->height, + 'type' => $imagefile->type); + + $_SESSION['FILEDATA'] = $filedata; + + $this->filedata = $filedata; + + $this->mode = 'crop'; + + $this->showForm(_('Pick a square area of the image to be your avatar'), + true); } /** @@ -242,7 +322,77 @@ class AvatarsettingsAction extends AccountSettingsAction $w = $this->arg('avatar_crop_w'); $h = $this->arg('avatar_crop_h'); - if ($profile->crop_avatars($x, $y, $w, $h)) { + $filedata = $_SESSION['FILEDATA']; + + if (!$filedata) { + $this->serverError(_('Lost our file data.')); + return; + } + + $filepath = common_avatar_path($filedata['filename']); + + if (!file_exists($filepath)) { + $this->serverError(_('Lost our file.')); + return; + } + + switch ($filedata['type']) { + case IMAGETYPE_GIF: + $image_src = imagecreatefromgif($filepath); + break; + case IMAGETYPE_JPEG: + $image_src = imagecreatefromjpeg($filepath); + break; + case IMAGETYPE_PNG: + $image_src = imagecreatefrompng($filepath); + break; + default: + $this->serverError(_('Unknown file type')); + return; + } + + common_debug("W = $w, H = $h, X = $x, Y = $y"); + + $image_dest = imagecreatetruecolor($w, $h); + + $background = imagecolorallocate($image_dest, 0, 0, 0); + ImageColorTransparent($image_dest, $background); + imagealphablending($image_dest, false); + + imagecopyresized($image_dest, $image_src, 0, 0, $x, $y, $w, $h, $w, $h); + + $cur = common_current_user(); + + $filename = common_avatar_filename($cur->id, + image_type_to_extension($filedata['type']), + null, + common_timestamp()); + + $filepath = common_avatar_path($filename); + + switch ($filedata['type']) { + case IMAGETYPE_GIF: + imagegif($image_dest, $filepath); + break; + case IMAGETYPE_JPEG: + imagejpeg($image_dest, $filepath); + break; + case IMAGETYPE_PNG: + imagepng($image_dest, $filepath); + break; + default: + $this->serverError(_('Unknown file type')); + return; + } + + $user = common_current_user(); + + $profile = $cur->getProfile(); + + if ($profile->setOriginal($filepath)) { + @unlink(common_avatar_path($filedata['filename'])); + unset($_SESSION['FILEDATA']); + $this->mode = 'upload'; $this->showForm(_('Avatar updated.'), true); } else { $this->showForm(_('Failed updating avatar.')); diff --git a/lib/imagefile.php b/lib/imagefile.php index f15a72c76..7f1db892c 100644 --- a/lib/imagefile.php +++ b/lib/imagefile.php @@ -48,12 +48,17 @@ if (!defined('LACONICA')) { class ImageFile { var $filename = null; + var $barename = null; var $type = null; + var $height = null; + var $width = null; - function __construct($filename=null, $type=null) + function __construct($filename=null, $type=null, $width=null, $height=null) { $this->filename = $filename; $this->type = $type; + $this->width = $type; + $this->height = $type; } static function fromUpload($param='upload') @@ -83,6 +88,9 @@ class ImageFile return; } + $imagefile->width = $info[0]; + $imagefile->height = $info[1]; + switch ($info[2]) { case IMAGETYPE_GIF: case IMAGETYPE_JPEG: -- cgit v1.2.3-54-g00ecf From c97980b14587327a0870f872305ecdd157896385 Mon Sep 17 00:00:00 2001 From: sarven Date: Fri, 23 Jan 2009 06:14:56 +0000 Subject: Missing closing li --- actions/avatarsettings.php | 13 ++++++------- theme/base/css/display.css | 2 +- 2 files changed, 7 insertions(+), 8 deletions(-) (limited to 'actions/avatarsettings.php') diff --git a/actions/avatarsettings.php b/actions/avatarsettings.php index 1db35237e..19f53b882 100644 --- a/actions/avatarsettings.php +++ b/actions/avatarsettings.php @@ -119,9 +119,8 @@ class AvatarsettingsAction extends AccountSettingsAction $this->elementStart('ul', 'form_data'); if ($original) { - $this->elementStart('li', - array('id' => 'avatar_original', - 'class' => 'avatar_view')); + $this->elementStart('li', array('id' => 'avatar_original', + 'class' => 'avatar_view')); $this->element('h2', null, _("Original")); $this->elementStart('div', array('id'=>'avatar_original_view')); $this->element('img', array('src' => $original->url, @@ -135,16 +134,16 @@ class AvatarsettingsAction extends AccountSettingsAction $avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE); if ($avatar) { - $this->elementStart('li', - array('id' => 'avatar_preview', - 'class' => 'avatar_view')); + $this->elementStart('li', array('id' => 'avatar_preview', + 'class' => 'avatar_view')); $this->element('h2', null, _("Preview")); $this->elementStart('div', array('id'=>'avatar_preview_view')); - $this->element('img', array('src' => $original->url,//$avatar->url, + $this->element('img', array('src' => $original->url, 'width' => AVATAR_PROFILE_SIZE, 'height' => AVATAR_PROFILE_SIZE, 'alt' => $user->nickname)); $this->elementEnd('div'); + $this->elementEnd('li'); } $this->elementStart('li', array ('id' => 'settings_attach')); diff --git a/theme/base/css/display.css b/theme/base/css/display.css index b4f3ffd54..4eee3449b 100644 --- a/theme/base/css/display.css +++ b/theme/base/css/display.css @@ -226,7 +226,7 @@ position:absolute; right:0; top:49px; float:right; -width:322px; +width:300px; } #page_notice { clear:both; -- cgit v1.2.3-54-g00ecf