From be53b94bfdb0498b335aaa558f5631c95a23e3d5 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Mon, 7 Mar 2011 17:26:19 -0800 Subject: [PATCH 01/46] - Fix table name; add comments --- plugins/ExtendedProfile/Profile_detail.php | 63 +++++++++++++++++++--- 1 file changed, 57 insertions(+), 6 deletions(-) diff --git a/plugins/ExtendedProfile/Profile_detail.php b/plugins/ExtendedProfile/Profile_detail.php index 6fd96cca70..25eca4d09c 100644 --- a/plugins/ExtendedProfile/Profile_detail.php +++ b/plugins/ExtendedProfile/Profile_detail.php @@ -21,18 +21,52 @@ if (!defined('STATUSNET')) { exit(1); } +/** + * DataObject class to store extended profile fields. Allows for storing + * multiple values per a "field" (field property is not unique). + * + * Example: + * + * Jed's Phone Numbers + * home : 510-384-1992 + * mobile: 510-719-1139 + * work : 415-231-1121 + * + * We can store these phone numbers in a "field" represented by three + * Profile_detail objects, each named 'phone_number' like this: + * + * $phone1 = new Profile_detail(); + * $phone1->field = 'phone_number'; + * $phone1->rel = 'home'; + * $phone1->field_index = 1; + * $phone1->value = '510-384-1992'; + * + * $phone1 = new Profile_detail(); + * $phone1->field = 'phone_number'; + * $phone1->rel = 'mobile'; + * $phone1->field_index = 2; + * $phone1->value = '510-719-1139'; + * + * $phone1 = new Profile_detail(); + * $phone1->field = 'phone_number'; + * $phone1->rel = 'work'; + * $phone1->field_index = 3; + * $phone1->value = '415-231-1121'; + * + */ class Profile_detail extends Memcached_DataObject { - public $__table = 'submirror'; + public $__table = 'profile_detail'; public $id; public $profile_id; + public $rel; // detail for some field types; eg "home", "mobile", "work" for phones or "aim", "irc", "xmpp" for IM public $field; + + public $value; // primary text value public $field_index; // relative ordering of multiple values in the same field - public $value; // primary text value - public $rel; // detail for some field types; eg "home", "mobile", "work" for phones or "aim", "irc", "xmpp" for IM public $ref_profile; // for people types, allows pointing to a known profile in the system public $created; @@ -68,9 +102,17 @@ class Profile_detail extends Memcached_DataObject 'modified' => DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME + DB_DATAOBJECT_NOTNULL); } + /** + * Database schema setup + * + * @see Schema + * @see ColumnDef + * + * @return boolean hook value; true means continue processing, false means stop. + */ + static function schemaDef() { - // @fixme need a reverse key on (subscribed, subscriber) as well return array(new ColumnDef('id', 'integer', null, false, 'PRI'), @@ -113,7 +155,7 @@ class Profile_detail extends Memcached_DataObject } /** - * return key definitions for DB_DataObject + * Return key definitions for DB_DataObject * * DB_DataObject needs to know about keys that the table has; this function * defines them. @@ -127,7 +169,7 @@ class Profile_detail extends Memcached_DataObject } /** - * return key definitions for Memcached_DataObject + * Return key definitions for Memcached_DataObject * * Our caching system uses the same key definitions, but uses a different * method to get them. @@ -142,6 +184,15 @@ class Profile_detail extends Memcached_DataObject return array('id' => 'K'); } + /** + * Get the sequence key + * + * Returns the first serial column defined in the table, if any. + * + * @access private + * @return array (column,use_native,sequence_name) + */ + function sequenceKey() { return array('id', true); From 99bd8c670c3a1be5be944879ffed248c040c2770 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Mon, 7 Mar 2011 21:34:57 -0800 Subject: [PATCH 02/46] Fix a couple things --- plugins/ExtendedProfile/Profile_detail.php | 2 +- plugins/ExtendedProfile/extendedprofile.php | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/plugins/ExtendedProfile/Profile_detail.php b/plugins/ExtendedProfile/Profile_detail.php index 25eca4d09c..4b193e54ee 100644 --- a/plugins/ExtendedProfile/Profile_detail.php +++ b/plugins/ExtendedProfile/Profile_detail.php @@ -96,7 +96,7 @@ class Profile_detail extends Memcached_DataObject 'value' => DB_DATAOBJECT_STR, 'rel' => DB_DATAOBJECT_STR, - 'ref_profile' => DB_DATAOBJECT_ID, + 'ref_profile' => DB_DATAOBJECT_INT, 'created' => DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME + DB_DATAOBJECT_NOTNULL, 'modified' => DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME + DB_DATAOBJECT_NOTNULL); diff --git a/plugins/ExtendedProfile/extendedprofile.php b/plugins/ExtendedProfile/extendedprofile.php index 7f69f90899..3be753b23f 100644 --- a/plugins/ExtendedProfile/extendedprofile.php +++ b/plugins/ExtendedProfile/extendedprofile.php @@ -35,8 +35,10 @@ class ExtendedProfile $detail = new Profile_detail(); $detail->profile_id = $this->profile->id; $detail->find(); - - while ($detail->get()) { + + $fields = array(); + + while ($detail->fetch()) { $fields[$detail->field][] = clone($detail); } return $fields; From 794cb5609b94befce80f7ebaf68419e993821897 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 8 Mar 2011 19:20:43 -0800 Subject: [PATCH 03/46] Save basic profile data to the right place --- plugins/ExtendedProfile/extendedprofile.php | 57 +++++- .../ExtendedProfile/extendedprofilewidget.php | 165 ++++++++++++++++-- .../ExtendedProfile/profiledetailaction.php | 1 + .../profiledetailsettingsaction.php | 134 +++++++++++++- 4 files changed, 338 insertions(+), 19 deletions(-) diff --git a/plugins/ExtendedProfile/extendedprofile.php b/plugins/ExtendedProfile/extendedprofile.php index 3be753b23f..61a66b4b43 100644 --- a/plugins/ExtendedProfile/extendedprofile.php +++ b/plugins/ExtendedProfile/extendedprofile.php @@ -21,15 +21,29 @@ if (!defined('STATUSNET')) { exit(1); } +/** + * Class to represent extended profile data + */ class ExtendedProfile { + /** + * Constructor + * + * @param Profile $profile + */ function __construct(Profile $profile) { - $this->profile = $profile; + $this->profile = $profile; + $this->user = $profile->getUser(); $this->sections = $this->getSections(); - $this->fields = $this->loadFields(); + $this->fields = $this->loadFields(); } + /** + * Load extended profile fields + * + * @return array $fields the list of fields + */ function loadFields() { $detail = new Profile_detail(); @@ -41,9 +55,48 @@ class ExtendedProfile while ($detail->fetch()) { $fields[$detail->field][] = clone($detail); } + return $fields; } + /** + * Get a the self-tags associated with this profile + * + * @return string the concatenated string of tags + */ + function getTags() + { + return implode(' ', $this->user->getSelfTags()); + } + + /** + * Return a simple string value. Checks for fields that should + * be stored in the regular profile and returns values from it + * if appropriate. + * + * @param string $name name of the detail field to get the + * value from + * + * @return string the value + */ + function getTextValue($name) + { + $profileFields = array('fullname', 'location', 'bio'); + + if (in_array(strtolower($name), $profileFields)) { + return $this->profile->$name; + } else if (in_array($name, $this->fields)) { + return $this->fields[$name]->value; + } else { + return null; + } + } + + /** + * Return all the sections of the extended profile + * + * @return array the big list of sections and fields + */ function getSections() { return array( diff --git a/plugins/ExtendedProfile/extendedprofilewidget.php b/plugins/ExtendedProfile/extendedprofilewidget.php index bf9b4056cd..fbb3ff3c23 100644 --- a/plugins/ExtendedProfile/extendedprofilewidget.php +++ b/plugins/ExtendedProfile/extendedprofilewidget.php @@ -21,13 +21,35 @@ if (!defined('STATUSNET')) { exit(1); } -class ExtendedProfileWidget extends Widget +/** + * Class for outputting a widget to display or edit + * extended profiles + */ +class ExtendedProfileWidget extends Form { - const EDITABLE=true; + const EDITABLE = true; + /** + * The parent profile + * + * @var Profile + */ protected $profile; + + /** + * The extended profile + * + * @var Extended_profile + */ protected $ext; + /** + * Constructor + * + * @param XMLOutputter $out + * @param Profile $profile + * @param boolean $editable + */ public function __construct(XMLOutputter $out=null, Profile $profile=null, $editable=false) { parent::__construct($out); @@ -38,7 +60,30 @@ class ExtendedProfileWidget extends Widget $this->editable = $editable; } + /** + * Show the extended profile, or the edit form + */ public function show() + { + if ($this->editable) { + parent::show(); + } else { + $this->showSections(); + } + } + + /** + * Show form data + */ + public function formData() + { + $this->showSections(); + } + + /** + * Show each section of the extended profile + */ + public function showSections() { $sections = $this->ext->getSections(); foreach ($sections as $name => $section) { @@ -46,6 +91,12 @@ class ExtendedProfileWidget extends Widget } } + /** + * Show an extended profile section + * + * @param string $name name of the section + * @param array $section array of fields for the section + */ protected function showExtendedProfileSection($name, $section) { $this->out->element('h3', null, $section['label']); @@ -56,6 +107,12 @@ class ExtendedProfileWidget extends Widget $this->out->elementEnd('table'); } + /** + * Show an extended profile field + * + * @param string $name name of the field + * @param array $field set of key/value pairs for the field + */ protected function showExtendedProfileField($name, $field) { $this->out->elementStart('tr'); @@ -73,30 +130,110 @@ class ExtendedProfileWidget extends Widget $this->out->elementEnd('tr'); } + /** + * Outputs the value of a field + * + * @param string $name name of the field + * @param array $field set of key/value pairs for the field + */ protected function showFieldValue($name, $field) { - $this->out->text($name); + $type = strval(@$field['type']); + + switch($type) + { + case '': + case 'text': + case 'textarea': + $this->out->text($this->ext->getTextValue($name)); + break; + case 'tags': + $this->out->text($this->ext->getTags()); + break; + default: + $this->out->text("TYPE: $type"); + } + } + /** + * Show an editable version of the field + * + * @param string $name name fo the field + * @param array $field array of key/value pairs for the field + */ protected function showEditableField($name, $field) { $out = $this->out; - //$out = new HTMLOutputter(); - // @fixme + $type = strval(@$field['type']); $id = "extprofile-" . $name; + $value = 'placeholder'; switch ($type) { - case '': - case 'text': - $out->input($id, null, $value); - break; - case 'textarea': - $out->textarea($id, null, $value); - break; - default: - $out->input($id, null, "TYPE: $type"); + case '': + case 'text': + $out->input($id, null, $this->ext->getTextValue($name)); + break; + case 'textarea': + $out->textarea($id, null, $this->ext->getTextValue($name)); + break; + case 'tags': + $out->input($id, null, $this->ext->getTags()); + break; + default: + $out->input($id, null, "TYPE: $type"); } } + + /** + * Action elements + * + * @return void + */ + + function formActions() + { + $this->out->submit( + 'save', + _m('BUTTON','Save'), + 'submit form_action-secondary', + 'save', + _('Save details') + ); + } + + /** + * ID of the form + * + * @return string ID of the form + */ + + function id() + { + return 'profile-details-' . $this->profile->id; + } + + /** + * class of the form + * + * @return string of the form class + */ + + function formClass() + { + return 'form_profile_details'; + } + + /** + * Action of the form + * + * @return string URL of the action + */ + + function action() + { + return common_local_url('profiledetailsettings'); + } } diff --git a/plugins/ExtendedProfile/profiledetailaction.php b/plugins/ExtendedProfile/profiledetailaction.php index a4bb12956e..d2eb06775c 100644 --- a/plugins/ExtendedProfile/profiledetailaction.php +++ b/plugins/ExtendedProfile/profiledetailaction.php @@ -23,6 +23,7 @@ if (!defined('STATUSNET')) { class ProfileDetailAction extends ProfileAction { + function isReadOnly($args) { return true; diff --git a/plugins/ExtendedProfile/profiledetailsettingsaction.php b/plugins/ExtendedProfile/profiledetailsettingsaction.php index 77d755c0b0..d1153cc075 100644 --- a/plugins/ExtendedProfile/profiledetailsettingsaction.php +++ b/plugins/ExtendedProfile/profiledetailsettingsaction.php @@ -21,7 +21,7 @@ if (!defined('STATUSNET')) { exit(1); } -class ProfileDetailSettingsAction extends AccountSettingsAction +class ProfileDetailSettingsAction extends SettingsAction { function title() @@ -47,9 +47,26 @@ class ProfileDetailSettingsAction extends AccountSettingsAction return true; } - function handle($args) + function handlePost() { - $this->showPage(); + // CSRF protection + $token = $this->trimmed('token'); + if (!$token || $token != common_session_token()) { + $this->show_form( + _m( + 'There was a problem with your session token. ' + . 'Try again, please.' + ) + ); + return; + } + + if ($this->arg('save')) { + $this->saveDetails(); + } else { + // TRANS: Message given submitting a form with an unknown action + $this->showForm(_m('Unexpected form submission.')); + } } function showContent() @@ -60,4 +77,115 @@ class ProfileDetailSettingsAction extends AccountSettingsAction $widget = new ExtendedProfileWidget($this, $profile, ExtendedProfileWidget::EDITABLE); $widget->show(); } + + function saveDetails() + { + common_debug(var_export($_POST, true)); + + $user = common_current_user(); + + try { + $this->saveStandardProfileDetails($user); + } catch (Exception $e) { + $this->showForm($e->getMessage(), false); + return; + } + + $profile = $user->getProfile(); + + + $simple_fields = array('title', 'manager', 'tags', 'spouse'); + + $this->showForm(_('Details saved.'), true); + + } + + /** + * Save fields that should be stored in the main profile object + * + * XXX: There's a lot of dupe code here from ProfileSettingsAction. + * Do not want. + * + * @param User $user the current user + */ + function saveStandardProfileDetails($user) + { + $user->query('BEGIN'); + + $fullname = $this->trimmed('extprofile-fullname'); + $location = $this->trimmed('extprofile-location'); + $tagstring = $this->trimmed('extprofile-tags'); + $bio = $this->trimmed('extprofile-bio'); + + if ($tagstring) { + $tags = array_map( + 'common_canonical_tag', + preg_split('/[\s,]+/', $tagstring) + ); + } else { + $tags = array(); + } + + foreach ($tags as $tag) { + if (!common_valid_profile_tag($tag)) { + // TRANS: Validation error in form for profile settings. + // TRANS: %s is an invalid tag. + throw new Exception(sprintf(_m('Invalid tag: "%s".'), $tag)); + } + } + + $profile = $user->getProfile(); + + if ($fullname != $profile->fullname + || $location != $profile->location + || $tags != $profile->tags + || $bio != $profile->bio) { + + $orig = clone($profile); + + $profile->nickname = $user->nickname; + $profile->fullname = $fullname; + $profile->bio = $bio; + $profile->location = $location; + + $loc = Location::fromName($location); + + if (empty($loc)) { + $profile->lat = null; + $profile->lon = null; + $profile->location_id = null; + $profile->location_ns = null; + } else { + $profile->lat = $loc->lat; + $profile->lon = $loc->lon; + $profile->location_id = $loc->location_id; + $profile->location_ns = $loc->location_ns; + } + + $profile->profileurl = common_profile_url($user->nickname); + + $result = $profile->update($orig); + + if ($result === false) { + common_log_db_error($profile, 'UPDATE', __FILE__); + // TRANS: Server error thrown when user profile settings could not be saved. + $this->serverError(_('Could not save profile.')); + return; + } + + // Set the user tags + $result = $user->setSelfTags($tags); + + if (!$result) { + // TRANS: Server error thrown when user profile settings tags could not be saved. + $this->serverError(_('Could not save tags.')); + return; + } + + $user->query('COMMIT'); + Event::handle('EndProfileSaveForm', array($this)); + common_broadcast_profile($profile); + } + } + } From 65f9b5d954f35e9a89edaad9dfdb48f61bc9c2c5 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 9 Mar 2011 11:27:29 -0800 Subject: [PATCH 04/46] Attempt to save field (doesn't work right yet) --- .../profiledetailsettingsaction.php | 44 ++++++++++++++++++- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/plugins/ExtendedProfile/profiledetailsettingsaction.php b/plugins/ExtendedProfile/profiledetailsettingsaction.php index d1153cc075..ce0828c3e1 100644 --- a/plugins/ExtendedProfile/profiledetailsettingsaction.php +++ b/plugins/ExtendedProfile/profiledetailsettingsaction.php @@ -93,13 +93,50 @@ class ProfileDetailSettingsAction extends SettingsAction $profile = $user->getProfile(); + $simpleFieldNames = array('title'); - $simple_fields = array('title', 'manager', 'tags', 'spouse'); + foreach ($simpleFieldNames as $name) { + $value = $this->trimmed('extprofile-' . $name); + $this->saveSimpleField($user, $name, $value); + } $this->showForm(_('Details saved.'), true); } + function saveSimpleField($user, $name, $value) + { + $profile = $user->getProfile(); + + $detail = new Profile_detail(); + + $detail->profile_id = $profile->id; + $detail->field = $name; + $detail->field_index = 1; + + $result = $detail->find(true); + + + if (empty($result)) { + $detail->value = $value; + + $detail->created = common_sql_now(); + + common_debug("XXXXXXXXXXXXXXX not found"); + //common_debug('bbbbbbbbbbbb ' . var_export($detail, true)); + + $result = $detail->insert(); + } else { + common_debug('zzzzz FOUND'); + $orig = clone($detail); + $detail->value = $value; + $result = $detail->update($orig); + } + + $detail->free(); + + } + /** * Save fields that should be stored in the main profile object * @@ -136,9 +173,12 @@ class ProfileDetailSettingsAction extends SettingsAction $profile = $user->getProfile(); + $oldTags = $user->getSelfTags(); + $newTags = array_diff($tags, $oldTags); + if ($fullname != $profile->fullname || $location != $profile->location - || $tags != $profile->tags + || !empty($newTags) || $bio != $profile->bio) { $orig = clone($profile); From 0429a52c6e8bf135b03a86398c1aee95ddebea88 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 9 Mar 2011 18:00:24 -0800 Subject: [PATCH 05/46] Update to use new Managed_dataobject --- .../ExtendedProfile/ExtendedProfilePlugin.php | 2 - plugins/ExtendedProfile/Profile_detail.php | 193 ++++++------------ plugins/ExtendedProfile/extendedprofile.php | 4 +- .../profiledetailsettingsaction.php | 17 +- 4 files changed, 80 insertions(+), 136 deletions(-) diff --git a/plugins/ExtendedProfile/ExtendedProfilePlugin.php b/plugins/ExtendedProfile/ExtendedProfilePlugin.php index 3f541c0008..933b43cad7 100644 --- a/plugins/ExtendedProfile/ExtendedProfilePlugin.php +++ b/plugins/ExtendedProfile/ExtendedProfilePlugin.php @@ -95,8 +95,6 @@ class ExtendedProfilePlugin extends Plugin $schema = Schema::get(); $schema->ensureTable('profile_detail', Profile_detail::schemaDef()); - // @hack until key definition support is merged - Profile_detail::fixIndexes($schema); return true; } diff --git a/plugins/ExtendedProfile/Profile_detail.php b/plugins/ExtendedProfile/Profile_detail.php index 4b193e54ee..ebbeb86054 100644 --- a/plugins/ExtendedProfile/Profile_detail.php +++ b/plugins/ExtendedProfile/Profile_detail.php @@ -23,7 +23,7 @@ if (!defined('STATUSNET')) { /** * DataObject class to store extended profile fields. Allows for storing - * multiple values per a "field" (field property is not unique). + * multiple values per a "field_name" (field_name property is not unique). * * Example: * @@ -36,166 +36,105 @@ if (!defined('STATUSNET')) { * Profile_detail objects, each named 'phone_number' like this: * * $phone1 = new Profile_detail(); - * $phone1->field = 'phone_number'; + * $phone1->field_name = 'phone_number'; * $phone1->rel = 'home'; - * $phone1->field_index = 1; * $phone1->value = '510-384-1992'; + * $phone1->value_index = 1; * * $phone1 = new Profile_detail(); - * $phone1->field = 'phone_number'; + * $phone1->field_name = 'phone_number'; * $phone1->rel = 'mobile'; - * $phone1->field_index = 2; * $phone1->value = '510-719-1139'; + * $phone1->value_index = 2; * * $phone1 = new Profile_detail(); - * $phone1->field = 'phone_number'; + * $phone1->field_name = 'phone_number'; * $phone1->rel = 'work'; - * $phone1->field_index = 3; - * $phone1->value = '415-231-1121'; + * $phone1->field_value = '415-231-1121'; + * $phone1->value_index = 3; * */ -class Profile_detail extends Memcached_DataObject +class Profile_detail extends Managed_DataObject { public $__table = 'profile_detail'; public $id; - - public $profile_id; + public $profile_id; // profile this is for public $rel; // detail for some field types; eg "home", "mobile", "work" for phones or "aim", "irc", "xmpp" for IM - public $field; - + public $field_name; // name public $value; // primary text value - public $field_index; // relative ordering of multiple values in the same field - + public $value_index; // relative ordering of multiple values in the same field public $ref_profile; // for people types, allows pointing to a known profile in the system - public $created; public $modified; - public /*static*/ function staticGet($k, $v=null) + /** + * Get an instance by key + * + * This is a utility method to get a single instance with a given key value. + * + * @param string $k Key to use to lookup + * @param mixed $v Value to lookup + * + * @return User_greeting_count object found, or null for no hits + * + */ + + function staticGet($k, $v=null) { - return parent::staticGet(__CLASS__, $k, $v); + return Memcached_DataObject::staticGet('Profile_detail', $k, $v); } /** - * return table definition for DB_DataObject + * Get an instance by compound key * - * DB_DataObject needs to know something about the table to manipulate - * instances. This method provides all the DB_DataObject needs to know. + * This is a utility method to get a single instance with a given set of + * key-value pairs. Usually used for the primary key for a compound key; thus + * the name. + * + * @param array $kv array of key-value mappings + * + * @return Bookmark object found, or null for no hits * - * @return array array of column definitions */ - function table() + function pkeyGet($kv) { - return array('id' => DB_DATAOBJECT_INT + DB_DATAOBJECT_NOTNULL, - - 'profile_id' => DB_DATAOBJECT_INT + DB_DATAOBJECT_NOTNULL, - 'field' => DB_DATAOBJECT_STR + DB_DATAOBJECT_NOTNULL, - 'field_index' => DB_DATAOBJECT_INT + DB_DATAOBJECT_NOTNULL, - - 'value' => DB_DATAOBJECT_STR, - 'rel' => DB_DATAOBJECT_STR, - 'ref_profile' => DB_DATAOBJECT_INT, - - 'created' => DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME + DB_DATAOBJECT_NOTNULL, - 'modified' => DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME + DB_DATAOBJECT_NOTNULL); + return Memcached_DataObject::pkeyGet('Profile_detail', $kv); } - /** - * Database schema setup - * - * @see Schema - * @see ColumnDef - * - * @return boolean hook value; true means continue processing, false means stop. - */ - static function schemaDef() { - return array(new ColumnDef('id', 'integer', - null, false, 'PRI'), - - // @fixme need a unique index on these three - new ColumnDef('profile_id', 'integer', - null, false), - new ColumnDef('field', 'varchar', - 16, false), - new ColumnDef('field_index', 'integer', - null, false), - - new ColumnDef('value', 'text', - null, true), - new ColumnDef('rel', 'varchar', - 16, true), - new ColumnDef('ref_profile', 'integer', - null, true), - - new ColumnDef('created', 'datetime', - null, false), - new ColumnDef('modified', 'datetime', - null, false)); - } - - /** - * Temporary hack to set up the compound index, since we can't do - * it yet through regular Schema interface. (Coming for 1.0...) - * - * @param Schema $schema - * @return void - */ - static function fixIndexes($schema) - { - try { - // @fixme this won't be a unique index... SIGH - $schema->createIndex('profile_detail', array('profile_id', 'field', 'field_index')); - } catch (Exception $e) { - common_log(LOG_ERR, __METHOD__ . ': ' . $e->getMessage()); - } - } - - /** - * Return key definitions for DB_DataObject - * - * DB_DataObject needs to know about keys that the table has; this function - * defines them. - * - * @return array key definitions - */ - - function keys() - { - return array_keys($this->keyTypes()); - } - - /** - * Return key definitions for Memcached_DataObject - * - * Our caching system uses the same key definitions, but uses a different - * method to get them. - * - * @return array key definitions - */ - - function keyTypes() - { - // @fixme keys - // need a sane key for reverse lookup too - return array('id' => 'K'); - } - - /** - * Get the sequence key - * - * Returns the first serial column defined in the table, if any. - * - * @access private - * @return array (column,use_native,sequence_name) - */ - - function sequenceKey() - { - return array('id', true); + return array( + 'description' + => 'Additional profile details for the ExtendedProfile plugin', + 'fields' => array( + 'id' => array('type' => 'serial', 'not null' => true), + 'profile_id' => array('type' => 'int', 'not null' => true), + 'field_name' => array( + 'type' => 'varchar', + 'length' => 16, + 'not null' => true + ), + 'value_index' => array('type' => 'int'), + 'field_value' => array('type' => 'text'), + 'rel' => array('type' => 'varchar', 'length' => 16), + 'rel_profile' => array('type' => 'int'), + 'created' => array( + 'type' => 'datetime', + 'not null' => true + ), + 'modified' => array( + 'type' => 'timestamp', + 'not null' => true + ), + ), + 'primary key' => array('id'), + 'unique keys' => array( + 'profile_detial_profile_id_field_name_value_index' + => array('profile_id', 'field_name', 'value_index'), + ) + ); } } diff --git a/plugins/ExtendedProfile/extendedprofile.php b/plugins/ExtendedProfile/extendedprofile.php index 61a66b4b43..5731c808ae 100644 --- a/plugins/ExtendedProfile/extendedprofile.php +++ b/plugins/ExtendedProfile/extendedprofile.php @@ -53,7 +53,7 @@ class ExtendedProfile $fields = array(); while ($detail->fetch()) { - $fields[$detail->field][] = clone($detail); + $fields[$detail->field_name][] = clone($detail); } return $fields; @@ -86,7 +86,7 @@ class ExtendedProfile if (in_array(strtolower($name), $profileFields)) { return $this->profile->$name; } else if (in_array($name, $this->fields)) { - return $this->fields[$name]->value; + return $this->fields[$name]->field_value; } else { return null; } diff --git a/plugins/ExtendedProfile/profiledetailsettingsaction.php b/plugins/ExtendedProfile/profiledetailsettingsaction.php index ce0828c3e1..1f2be5a060 100644 --- a/plugins/ExtendedProfile/profiledetailsettingsaction.php +++ b/plugins/ExtendedProfile/profiledetailsettingsaction.php @@ -111,26 +111,33 @@ class ProfileDetailSettingsAction extends SettingsAction $detail = new Profile_detail(); $detail->profile_id = $profile->id; - $detail->field = $name; - $detail->field_index = 1; + $detail->field_name = $name; $result = $detail->find(true); if (empty($result)) { - $detail->value = $value; + + $detail->field_value = $value; $detail->created = common_sql_now(); common_debug("XXXXXXXXXXXXXXX not found"); - //common_debug('bbbbbbbbbbbb ' . var_export($detail, true)); $result = $detail->insert(); + + if (empty($result)) { + common_log_db_error($detail, 'INSERT', __FILE__); + $this->serverError(_m('Could not save profile details.')); + } + } else { + common_debug('zzzzz FOUND'); $orig = clone($detail); - $detail->value = $value; + $detail->field_value = $value; $result = $detail->update($orig); + } $detail->free(); From 3d61d003bc03dd18aa46dc9e96ecb9b0ed9034c7 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 9 Mar 2011 18:16:02 -0800 Subject: [PATCH 06/46] Fix property declaration --- plugins/ExtendedProfile/Profile_detail.php | 8 ++++---- plugins/ExtendedProfile/extendedprofile.php | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/plugins/ExtendedProfile/Profile_detail.php b/plugins/ExtendedProfile/Profile_detail.php index ebbeb86054..f9f4d00098 100644 --- a/plugins/ExtendedProfile/Profile_detail.php +++ b/plugins/ExtendedProfile/Profile_detail.php @@ -38,13 +38,13 @@ if (!defined('STATUSNET')) { * $phone1 = new Profile_detail(); * $phone1->field_name = 'phone_number'; * $phone1->rel = 'home'; - * $phone1->value = '510-384-1992'; + * $phone1->field_value = '510-384-1992'; * $phone1->value_index = 1; * * $phone1 = new Profile_detail(); * $phone1->field_name = 'phone_number'; * $phone1->rel = 'mobile'; - * $phone1->value = '510-719-1139'; + * $phone1->field_value = '510-719-1139'; * $phone1->value_index = 2; * * $phone1 = new Profile_detail(); @@ -62,7 +62,7 @@ class Profile_detail extends Managed_DataObject public $profile_id; // profile this is for public $rel; // detail for some field types; eg "home", "mobile", "work" for phones or "aim", "irc", "xmpp" for IM public $field_name; // name - public $value; // primary text value + public $field_value; // primary text value public $value_index; // relative ordering of multiple values in the same field public $ref_profile; // for people types, allows pointing to a known profile in the system public $created; @@ -131,7 +131,7 @@ class Profile_detail extends Managed_DataObject ), 'primary key' => array('id'), 'unique keys' => array( - 'profile_detial_profile_id_field_name_value_index' + 'profile_detail_profile_id_field_name_value_index' => array('profile_id', 'field_name', 'value_index'), ) ); diff --git a/plugins/ExtendedProfile/extendedprofile.php b/plugins/ExtendedProfile/extendedprofile.php index 5731c808ae..43f5b55b9c 100644 --- a/plugins/ExtendedProfile/extendedprofile.php +++ b/plugins/ExtendedProfile/extendedprofile.php @@ -37,6 +37,7 @@ class ExtendedProfile $this->user = $profile->getUser(); $this->sections = $this->getSections(); $this->fields = $this->loadFields(); + common_debug(var_export($this->fields, true)); } /** From adcda00e7668532b1261ba9808834ba45421c01a Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 9 Mar 2011 19:27:21 -0800 Subject: [PATCH 07/46] * Remove evil transaction * Fix text value retrieval method --- plugins/ExtendedProfile/extendedprofile.php | 9 ++++++--- .../ExtendedProfile/profiledetailsettingsaction.php | 11 ++++++----- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/plugins/ExtendedProfile/extendedprofile.php b/plugins/ExtendedProfile/extendedprofile.php index 43f5b55b9c..5ad6db114f 100644 --- a/plugins/ExtendedProfile/extendedprofile.php +++ b/plugins/ExtendedProfile/extendedprofile.php @@ -26,6 +26,8 @@ if (!defined('STATUSNET')) { */ class ExtendedProfile { + protected $fields; + /** * Constructor * @@ -82,12 +84,13 @@ class ExtendedProfile */ function getTextValue($name) { + $key = strtolower($name); $profileFields = array('fullname', 'location', 'bio'); - if (in_array(strtolower($name), $profileFields)) { + if (in_array($key, $profileFields)) { return $this->profile->$name; - } else if (in_array($name, $this->fields)) { - return $this->fields[$name]->field_value; + } else if (array_key_exists($key, $this->fields)) { + return $this->fields[$key][0]->field_value; } else { return null; } diff --git a/plugins/ExtendedProfile/profiledetailsettingsaction.php b/plugins/ExtendedProfile/profiledetailsettingsaction.php index 1f2be5a060..7c68216972 100644 --- a/plugins/ExtendedProfile/profiledetailsettingsaction.php +++ b/plugins/ExtendedProfile/profiledetailsettingsaction.php @@ -74,7 +74,11 @@ class ProfileDetailSettingsAction extends SettingsAction $cur = common_current_user(); $profile = $cur->getProfile(); - $widget = new ExtendedProfileWidget($this, $profile, ExtendedProfileWidget::EDITABLE); + $widget = new ExtendedProfileWidget( + $this, + $profile, + ExtendedProfileWidget::EDITABLE + ); $widget->show(); } @@ -154,8 +158,6 @@ class ProfileDetailSettingsAction extends SettingsAction */ function saveStandardProfileDetails($user) { - $user->query('BEGIN'); - $fullname = $this->trimmed('extprofile-fullname'); $location = $this->trimmed('extprofile-location'); $tagstring = $this->trimmed('extprofile-tags'); @@ -187,7 +189,7 @@ class ProfileDetailSettingsAction extends SettingsAction || $location != $profile->location || !empty($newTags) || $bio != $profile->bio) { - + $orig = clone($profile); $profile->nickname = $user->nickname; @@ -229,7 +231,6 @@ class ProfileDetailSettingsAction extends SettingsAction return; } - $user->query('COMMIT'); Event::handle('EndProfileSaveForm', array($this)); common_broadcast_profile($profile); } From 5203fa7151c099e0ba5a9ef80565ed681a3a200a Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 9 Mar 2011 19:31:37 -0800 Subject: [PATCH 08/46] Make all simple fields save --- plugins/ExtendedProfile/profiledetailsettingsaction.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/ExtendedProfile/profiledetailsettingsaction.php b/plugins/ExtendedProfile/profiledetailsettingsaction.php index 7c68216972..0f84dc0582 100644 --- a/plugins/ExtendedProfile/profiledetailsettingsaction.php +++ b/plugins/ExtendedProfile/profiledetailsettingsaction.php @@ -97,7 +97,7 @@ class ProfileDetailSettingsAction extends SettingsAction $profile = $user->getProfile(); - $simpleFieldNames = array('title'); + $simpleFieldNames = array('title', 'spouse', 'kids'); foreach ($simpleFieldNames as $name) { $value = $this->trimmed('extprofile-' . $name); From c456e998c7de9b70171db4524dc7ac90e908b7ad Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Thu, 10 Mar 2011 14:14:21 -0800 Subject: [PATCH 09/46] Make phone numbers save --- plugins/ExtendedProfile/extendedprofile.php | 24 ++-- .../ExtendedProfile/extendedprofilewidget.php | 48 ++++++++ .../profiledetailsettingsaction.php | 109 +++++++++++++++--- 3 files changed, 155 insertions(+), 26 deletions(-) diff --git a/plugins/ExtendedProfile/extendedprofile.php b/plugins/ExtendedProfile/extendedprofile.php index 5ad6db114f..908f0bc721 100644 --- a/plugins/ExtendedProfile/extendedprofile.php +++ b/plugins/ExtendedProfile/extendedprofile.php @@ -39,7 +39,7 @@ class ExtendedProfile $this->user = $profile->getUser(); $this->sections = $this->getSections(); $this->fields = $this->loadFields(); - common_debug(var_export($this->fields, true)); + //common_debug(var_export($this->fields, true)); } /** @@ -96,6 +96,21 @@ class ExtendedProfile } } + + function getPhones() + { + return array( + 'label' => _m('Phone'), + 'type' => 'phone', + 'multi' => true, + 'index' => 8123, + 'rel' => 'home', + 'value' => '510-528-0079', + 'vcard' => 'tel' + + ); + } + /** * Return all the sections of the extended profile * @@ -140,12 +155,7 @@ class ExtendedProfile 'contact' => array( 'label' => _m('Contact'), 'fields' => array( - 'phone' => array( - 'label' => _m('Phone'), - 'type' => 'phone', - 'multi' => true, - 'vcard' => 'tel', - ), + 'phone' => $this->getPhones(), 'im' => array( 'label' => _m('IM'), 'type' => 'im', diff --git a/plugins/ExtendedProfile/extendedprofilewidget.php b/plugins/ExtendedProfile/extendedprofilewidget.php index fbb3ff3c23..f5685e9981 100644 --- a/plugins/ExtendedProfile/extendedprofilewidget.php +++ b/plugins/ExtendedProfile/extendedprofilewidget.php @@ -150,10 +150,55 @@ class ExtendedProfileWidget extends Form case 'tags': $this->out->text($this->ext->getTags()); break; + case 'phone': + common_debug("GOT a PHONE!"); + $this->showPhone($field); + break; default: $this->out->text("TYPE: $type"); } + } + protected function showPhone($field) + { + $this->out->elementStart('div', array('class' => 'phone-display')); + $this->out->text($field['value']); + $this->out->text(' (' . $field['rel'] . ')'); + $this->out->elementEnd('div'); + } + + protected function showEditablePhone($name, $field) + { + $index = $field['index']; + $id = "extprofile-$name-$index"; + $rel = $id . '-rel'; + + $this->out->elementStart('div', array('class' => 'phone-edit')); + $this->out->input($id, null, $field['value']); + $this->out->dropdown( + $id . '-rel', + 'Type', + array( + 'office' => 'Office', + 'mobile' => 'Mobile', + 'home' => 'Home', + 'pager' => 'Pager', + 'other' => 'Other' + ), + null, + false, + $field['rel'] + ); + if ($field['multi']) { + $this->out->element( + 'a', + array( + 'name' => $name, + 'href' => 'javascript://'), + '+' + ); + } + $this->out->elementEnd('div'); } /** @@ -182,6 +227,9 @@ class ExtendedProfileWidget extends Form case 'tags': $out->input($id, null, $this->ext->getTags()); break; + case 'phone': + $this->showEditablePhone($name, $field); + break; default: $out->input($id, null, "TYPE: $type"); } diff --git a/plugins/ExtendedProfile/profiledetailsettingsaction.php b/plugins/ExtendedProfile/profiledetailsettingsaction.php index 0f84dc0582..c18732c058 100644 --- a/plugins/ExtendedProfile/profiledetailsettingsaction.php +++ b/plugins/ExtendedProfile/profiledetailsettingsaction.php @@ -101,51 +101,122 @@ class ProfileDetailSettingsAction extends SettingsAction foreach ($simpleFieldNames as $name) { $value = $this->trimmed('extprofile-' . $name); - $this->saveSimpleField($user, $name, $value); + $this->saveField($user, $name, $value); } + $this->savePhoneNumbers($user); + $this->showForm(_('Details saved.'), true); } - function saveSimpleField($user, $name, $value) + function savePhoneNumbers($user) { + $phones = $this->findPhoneNumbers(); + + foreach ($phones as $phone) { + $this->saveField( + $user, + 'phone', + $phone['value'], + $phone['rel'], + $phone['index'] + ); + } + } + + function findPhoneNumbers() { + $phones = array(); + $phoneParams = $this->findMultiParams('phone'); + ksort($phoneParams); // this sorts them into pairs + $phones = $this->arraySplit($phoneParams, sizeof($phoneParams) / 2); + + $phoneTuples = array(); + + foreach($phones as $phone) { + $firstkey = array_shift(array_keys($phone)); + $index = substr($firstkey, strrpos($firstkey, '-') + 1); + list($number, $rel) = array_values($phone); + + $phoneTuples[] = array( + 'value' => $number, + 'index' => $index, + 'rel' => $rel + ); + + return $phoneTuples; + } + + return $phones; + } + + function arraySplit($array, $pieces) + { + if ($pieces < 2) { + return array($array); + } + + $newCount = ceil(count($array) / $pieces); + $a = array_slice($array, 0, $newCount); + $b = array_split(array_slice($array, $newCount), $pieces - 1); + + return array_merge(array($a), $b); + } + + function findMultiParams($type) { + $formVals = array(); + $target = $type; + foreach ($_POST as $key => $val) { + if (strrpos('extprofile-' . $key, $target) !== false) { + $formVals[$key] = $val; + } + } + return $formVals; + } + + /** + * Save an extended profile field as a Profile_detail + * + * @param User $user the current user + * @param string $name field name + * @param string $value field value + * @param string $rel field rel (type) + * @param int $index index (fields can have multiple values) + */ + function saveField($user, $name, $value, $rel = null, $index = null) { $profile = $user->getProfile(); - - $detail = new Profile_detail(); + $detail = new Profile_detail(); $detail->profile_id = $profile->id; $detail->field_name = $name; + $detail->value_index = $index; $result = $detail->find(true); - if (empty($result)) { - + $detial->value_index = $index; + $detail->rel = $rel; $detail->field_value = $value; - - $detail->created = common_sql_now(); - - common_debug("XXXXXXXXXXXXXXX not found"); - + $detail->created = common_sql_now(); $result = $detail->insert(); - if (empty($result)) { common_log_db_error($detail, 'INSERT', __FILE__); $this->serverError(_m('Could not save profile details.')); } - } else { - - common_debug('zzzzz FOUND'); $orig = clone($detail); - $detail->field_value = $value; - $result = $detail->update($orig); + $detail->field_value = $value; + $detail->rel = $rel; + + $result = $detail->update($orig); + if (empty($result)) { + common_log_db_error($detail, 'UPDATE', __FILE__); + $this->serverError(_m('Could not save profile details.')); + } } $detail->free(); - } /** @@ -189,7 +260,7 @@ class ProfileDetailSettingsAction extends SettingsAction || $location != $profile->location || !empty($newTags) || $bio != $profile->bio) { - + $orig = clone($profile); $profile->nickname = $user->nickname; From 8efd2cf04dfb3343b88cb51f5740bb1688ba3c05 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Thu, 10 Mar 2011 16:57:41 -0800 Subject: [PATCH 10/46] Make phone number save and display from DB --- plugins/ExtendedProfile/extendedprofile.php | 39 ++++++++++++++----- .../ExtendedProfile/extendedprofilewidget.php | 18 +++++++-- 2 files changed, 44 insertions(+), 13 deletions(-) diff --git a/plugins/ExtendedProfile/extendedprofile.php b/plugins/ExtendedProfile/extendedprofile.php index 908f0bc721..2a10759d91 100644 --- a/plugins/ExtendedProfile/extendedprofile.php +++ b/plugins/ExtendedProfile/extendedprofile.php @@ -37,8 +37,10 @@ class ExtendedProfile { $this->profile = $profile; $this->user = $profile->getUser(); - $this->sections = $this->getSections(); $this->fields = $this->loadFields(); + $this->sections = $this->getSections(); + //common_debug(var_export($this->sections, true)); + //common_debug(var_export($this->fields, true)); } @@ -96,19 +98,36 @@ class ExtendedProfile } } - function getPhones() { - return array( + $phones = $this->fields['phone']; + $pArrays = array(); + + if (empty($phones)) { + $pArrays[] = array( 'label' => _m('Phone'), 'type' => 'phone', - 'multi' => true, - 'index' => 8123, - 'rel' => 'home', - 'value' => '510-528-0079', - 'vcard' => 'tel' - - ); + 'vcard' => 'tel', + 'multi' => true + ); + } else { + for ($i = 0; $i < sizeof($phones); $i++) { + $pa = array( + 'label' => _m('Phone'), + 'type' => 'phone', + 'index' => $phones[$i]->value_index, + 'rel' => $phones[$i]->rel, + 'value' => $phones[$i]->field_value, + 'vcard' => 'tel' + ); + // Last phone record should allow adding more + if ($i == sizeof($phones) - 1) { + $pa['multi'] = true; + } + $pArrays[] = $pa; + } + } + return $pArrays; } /** diff --git a/plugins/ExtendedProfile/extendedprofilewidget.php b/plugins/ExtendedProfile/extendedprofilewidget.php index f5685e9981..d31a34b1e2 100644 --- a/plugins/ExtendedProfile/extendedprofilewidget.php +++ b/plugins/ExtendedProfile/extendedprofilewidget.php @@ -101,8 +101,13 @@ class ExtendedProfileWidget extends Form { $this->out->element('h3', null, $section['label']); $this->out->elementStart('table', array('class' => 'extended-profile')); + foreach ($section['fields'] as $fieldName => $field) { - $this->showExtendedProfileField($fieldName, $field); + if ($fieldName == 'phone') { + $this->showPhones($fieldName, $field); + } else { + $this->showExtendedProfileField($fieldName, $field); + } } $this->out->elementEnd('table'); } @@ -151,7 +156,6 @@ class ExtendedProfileWidget extends Form $this->out->text($this->ext->getTags()); break; case 'phone': - common_debug("GOT a PHONE!"); $this->showPhone($field); break; default: @@ -159,11 +163,19 @@ class ExtendedProfileWidget extends Form } } + protected function showPhones($name, $field) { + foreach ($field as $phone) { + $this->showExtendedProfileField($name, $phone); + } + } + protected function showPhone($field) { $this->out->elementStart('div', array('class' => 'phone-display')); $this->out->text($field['value']); - $this->out->text(' (' . $field['rel'] . ')'); + if (!empty($field['rel'])) { + $this->out->text(' (' . $field['rel'] . ')'); + } $this->out->elementEnd('div'); } From 302f0236bdee73afc9183f724432df2f43fb480a Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Thu, 10 Mar 2011 17:13:34 -0800 Subject: [PATCH 11/46] Make correct nav menus show --- plugins/ExtendedProfile/profiledetailaction.php | 13 +------------ .../ExtendedProfile/profiledetailsettingsaction.php | 2 +- 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/plugins/ExtendedProfile/profiledetailaction.php b/plugins/ExtendedProfile/profiledetailaction.php index d2eb06775c..beac7d6321 100644 --- a/plugins/ExtendedProfile/profiledetailaction.php +++ b/plugins/ExtendedProfile/profiledetailaction.php @@ -21,7 +21,7 @@ if (!defined('STATUSNET')) { exit(1); } -class ProfileDetailAction extends ProfileAction +class ProfileDetailAction extends ShowstreamAction { function isReadOnly($args) @@ -34,23 +34,12 @@ class ProfileDetailAction extends ProfileAction return $this->profile->getFancyName(); } - function showLocalNav() - { - $nav = new PersonalGroupNav($this); - $nav->show(); - } - function showStylesheets() { parent::showStylesheets(); $this->cssLink('plugins/ExtendedProfile/profiledetail.css'); return true; } - function handle($args) - { - $this->showPage(); - } - function showContent() { $cur = common_current_user(); diff --git a/plugins/ExtendedProfile/profiledetailsettingsaction.php b/plugins/ExtendedProfile/profiledetailsettingsaction.php index c18732c058..ec2c4935a2 100644 --- a/plugins/ExtendedProfile/profiledetailsettingsaction.php +++ b/plugins/ExtendedProfile/profiledetailsettingsaction.php @@ -21,7 +21,7 @@ if (!defined('STATUSNET')) { exit(1); } -class ProfileDetailSettingsAction extends SettingsAction +class ProfileDetailSettingsAction extends ProfileSettingsAction { function title() From deb40602d2bc61772eb0b2631f3f4d6c6b592aac Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Sun, 13 Mar 2011 16:32:13 -0700 Subject: [PATCH 12/46] Extended profile - more work on getting complex fields to save --- .../{ => css}/profiledetail.css | 0 plugins/ExtendedProfile/extendedprofile.php | 3 +- .../ExtendedProfile/extendedprofilewidget.php | 19 ++++- plugins/ExtendedProfile/js/profiledetail.js | 83 +++++++++++++++++++ .../profiledetailsettingsaction.php | 16 ++-- 5 files changed, 111 insertions(+), 10 deletions(-) rename plugins/ExtendedProfile/{ => css}/profiledetail.css (100%) create mode 100644 plugins/ExtendedProfile/js/profiledetail.js diff --git a/plugins/ExtendedProfile/profiledetail.css b/plugins/ExtendedProfile/css/profiledetail.css similarity index 100% rename from plugins/ExtendedProfile/profiledetail.css rename to plugins/ExtendedProfile/css/profiledetail.css diff --git a/plugins/ExtendedProfile/extendedprofile.php b/plugins/ExtendedProfile/extendedprofile.php index 2a10759d91..94a5ef4826 100644 --- a/plugins/ExtendedProfile/extendedprofile.php +++ b/plugins/ExtendedProfile/extendedprofile.php @@ -106,6 +106,7 @@ class ExtendedProfile if (empty($phones)) { $pArrays[] = array( 'label' => _m('Phone'), + 'index' => 0, 'type' => 'phone', 'vcard' => 'tel', 'multi' => true @@ -115,7 +116,7 @@ class ExtendedProfile $pa = array( 'label' => _m('Phone'), 'type' => 'phone', - 'index' => $phones[$i]->value_index, + 'index' => intva($phones[$i]->value_index), 'rel' => $phones[$i]->rel, 'value' => $phones[$i]->field_value, 'vcard' => 'tel' diff --git a/plugins/ExtendedProfile/extendedprofilewidget.php b/plugins/ExtendedProfile/extendedprofilewidget.php index d31a34b1e2..7eb195e369 100644 --- a/plugins/ExtendedProfile/extendedprofilewidget.php +++ b/plugins/ExtendedProfile/extendedprofilewidget.php @@ -184,8 +184,12 @@ class ExtendedProfileWidget extends Form $index = $field['index']; $id = "extprofile-$name-$index"; $rel = $id . '-rel'; - - $this->out->elementStart('div', array('class' => 'phone-edit')); + $this->out->elementStart( + 'div', array( + 'id' => $id . '-edit', + 'class' => 'phone-edit' + ) + ); $this->out->input($id, null, $field['value']); $this->out->dropdown( $id . '-rel', @@ -205,10 +209,19 @@ class ExtendedProfileWidget extends Form $this->out->element( 'a', array( - 'name' => $name, + 'class' => 'add_row', 'href' => 'javascript://'), '+' ); + $this->out->element( + 'a', + array( + 'class' => 'remove_row', + 'href' => 'javascript://', + 'style' => 'display: none; ' + ), + '-' + ); } $this->out->elementEnd('div'); } diff --git a/plugins/ExtendedProfile/js/profiledetail.js b/plugins/ExtendedProfile/js/profiledetail.js new file mode 100644 index 0000000000..a021a32645 --- /dev/null +++ b/plugins/ExtendedProfile/js/profiledetail.js @@ -0,0 +1,83 @@ +var removeRow = function() { + var cnt = rowCount(this); + var table = $(this).closest('table'); + console.log("row count = " + cnt); + if (cnt > 1) { + var target = $(this).closest('tr'); + target.remove(); + reorder(table); + } +}; + +var rowCount = function(row) { + var top = $(row).closest('table'); + var trs = $(top).find('tr'); + return trs.length - 1; // exclude th section header row +}; + +var reorder = function(table) { + var trs = $(table).find('tr').has('td'); + + $(trs).find('a').hide(); + + $(trs).each(function(i, tr) { + console.log("ROW " + i); + $(tr).find('a.remove_row').show(); + replaceIndex(rowIndex(tr), i); + }); + + $(trs).last().find('a.add_row').show(); + + if (trs.length == 1) { + $(trs).find('a.remove_row').hide(); + } + +}; + +var rowIndex = function(elem) { + var idStr = $(elem).find('div').attr('id'); + var id = idStr.match(/\d+/); + console.log("id = " + id); +}; + +var replaceIndex = function(elem, oldIndex, newIndex) { + $(elem).find('*').each(function() { + $.each(this.attributes, function(i, attrib) { + var regexp = /extprofile-.*-\d.*/; + var value = attrib.value; + var match = value.match(regexp); + if (match != null) { + attrib.value = value.replace("-" + oldIndex, "-" + newIndex); + console.log('match: oldIndex = ' + oldIndex + ' newIndex = ' + newIndex + ' name = ' + attrib.name + ' value = ' + attrib.value); + } + }); + }); +} + +var resetRow = function(elem) { + $(elem).find('input').attr('value', ''); + $(elem).find("select option[value='office']").attr("selected", true); +} + +var addRow = function() { + var divId = $(this).closest('div').attr('id'); + var index = divId.match(/\d+/); + console.log("Current row = " + index); + var tr = $(this).closest('tr'); + var newtr = $(tr).clone(); + var newIndex = parseInt(index) + 1; + replaceIndex(newtr, index, newIndex); + resetRow(newtr); + $(tr).after(newtr); + console.log("number of rows: " + rowCount(tr)); + reorder($(this).closest('table')); +}; + +$(document).ready( + +function() { + $('.add_row').live('click', addRow); + $('.remove_row').live('click', removeRow); +} + +); \ No newline at end of file diff --git a/plugins/ExtendedProfile/profiledetailsettingsaction.php b/plugins/ExtendedProfile/profiledetailsettingsaction.php index ec2c4935a2..ee450118c3 100644 --- a/plugins/ExtendedProfile/profiledetailsettingsaction.php +++ b/plugins/ExtendedProfile/profiledetailsettingsaction.php @@ -43,7 +43,13 @@ class ProfileDetailSettingsAction extends ProfileSettingsAction function showStylesheets() { parent::showStylesheets(); - $this->cssLink('plugins/ExtendedProfile/profiledetail.css'); + $this->cssLink('plugins/ExtendedProfile/css/profiledetail.css'); + return true; + } + + function showScripts() { + parent::showScripts(); + $this->script('plugins/ExtendedProfile/js/profiledetail.js'); return true; } @@ -133,7 +139,7 @@ class ProfileDetailSettingsAction extends ProfileSettingsAction $phoneTuples = array(); foreach($phones as $phone) { - $firstkey = array_shift(array_keys($phone)); + $firstkey = current(array_keys($phone)); $index = substr($firstkey, strrpos($firstkey, '-') + 1); list($number, $rel) = array_values($phone); @@ -142,11 +148,9 @@ class ProfileDetailSettingsAction extends ProfileSettingsAction 'index' => $index, 'rel' => $rel ); - - return $phoneTuples; } - return $phones; + return $phoneTuples; } function arraySplit($array, $pieces) @@ -157,7 +161,7 @@ class ProfileDetailSettingsAction extends ProfileSettingsAction $newCount = ceil(count($array) / $pieces); $a = array_slice($array, 0, $newCount); - $b = array_split(array_slice($array, $newCount), $pieces - 1); + $b = $this->arraySplit(array_slice($array, $newCount), $pieces - 1); return array_merge(array($a), $b); } From 04c8bf2743db51cd724449b4cbec1aaef531597c Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Mon, 14 Mar 2011 01:49:46 -0700 Subject: [PATCH 13/46] Extended profile - finished basic pattern for adding/removing/saving multiple complex fields --- plugins/ExtendedProfile/extendedprofile.php | 12 ++- .../ExtendedProfile/extendedprofilewidget.php | 53 ++++++------ plugins/ExtendedProfile/js/profiledetail.js | 80 +++++++++++-------- .../profiledetailsettingsaction.php | 36 ++++++--- 4 files changed, 107 insertions(+), 74 deletions(-) diff --git a/plugins/ExtendedProfile/extendedprofile.php b/plugins/ExtendedProfile/extendedprofile.php index 94a5ef4826..711fdcf1bb 100644 --- a/plugins/ExtendedProfile/extendedprofile.php +++ b/plugins/ExtendedProfile/extendedprofile.php @@ -100,7 +100,7 @@ class ExtendedProfile function getPhones() { - $phones = $this->fields['phone']; + $phones = (isset($this->fields['phone'])) ? $this->fields['phone'] : null; $pArrays = array(); if (empty($phones)) { @@ -109,22 +109,20 @@ class ExtendedProfile 'index' => 0, 'type' => 'phone', 'vcard' => 'tel', - 'multi' => true + 'rel' => 'office', + 'value' => null ); } else { for ($i = 0; $i < sizeof($phones); $i++) { $pa = array( 'label' => _m('Phone'), 'type' => 'phone', - 'index' => intva($phones[$i]->value_index), + 'index' => intval($phones[$i]->value_index), 'rel' => $phones[$i]->rel, 'value' => $phones[$i]->field_value, 'vcard' => 'tel' ); - // Last phone record should allow adding more - if ($i == sizeof($phones) - 1) { - $pa['multi'] = true; - } + $pArrays[] = $pa; } } diff --git a/plugins/ExtendedProfile/extendedprofilewidget.php b/plugins/ExtendedProfile/extendedprofilewidget.php index 7eb195e369..d8c42df6a3 100644 --- a/plugins/ExtendedProfile/extendedprofilewidget.php +++ b/plugins/ExtendedProfile/extendedprofilewidget.php @@ -156,7 +156,7 @@ class ExtendedProfileWidget extends Form $this->out->text($this->ext->getTags()); break; case 'phone': - $this->showPhone($field); + $this->showPhone($name, $field); break; default: $this->out->text("TYPE: $type"); @@ -169,7 +169,7 @@ class ExtendedProfileWidget extends Form } } - protected function showPhone($field) + protected function showPhone($name, $field) { $this->out->elementStart('div', array('class' => 'phone-display')); $this->out->text($field['value']); @@ -181,7 +181,7 @@ class ExtendedProfileWidget extends Form protected function showEditablePhone($name, $field) { - $index = $field['index']; + $index = isset($field['index']) ? $field['index'] : 0; $id = "extprofile-$name-$index"; $rel = $id . '-rel'; $this->out->elementStart( @@ -190,7 +190,11 @@ class ExtendedProfileWidget extends Form 'class' => 'phone-edit' ) ); - $this->out->input($id, null, $field['value']); + $this->out->input( + $id, + null, + isset($field['value']) ? $field['value'] : null + ); $this->out->dropdown( $id . '-rel', 'Type', @@ -203,26 +207,29 @@ class ExtendedProfileWidget extends Form ), null, false, - $field['rel'] + isset($field['rel']) ? $field['rel'] : null ); - if ($field['multi']) { - $this->out->element( - 'a', - array( - 'class' => 'add_row', - 'href' => 'javascript://'), - '+' - ); - $this->out->element( - 'a', - array( - 'class' => 'remove_row', - 'href' => 'javascript://', - 'style' => 'display: none; ' - ), - '-' - ); - } + + $this->out->element( + 'a', + array( + 'class' => 'add_row', + 'href' => 'javascript://', + 'style' => 'display: none; ' + ), + '+' + ); + + $this->out->element( + 'a', + array( + 'class' => 'remove_row', + 'href' => 'javascript://', + 'style' => 'display: none; ' + ), + '-' + ); + $this->out->elementEnd('div'); } diff --git a/plugins/ExtendedProfile/js/profiledetail.js b/plugins/ExtendedProfile/js/profiledetail.js index a021a32645..7d7eceddc1 100644 --- a/plugins/ExtendedProfile/js/profiledetail.js +++ b/plugins/ExtendedProfile/js/profiledetail.js @@ -1,43 +1,35 @@ -var removeRow = function() { - var cnt = rowCount(this); - var table = $(this).closest('table'); - console.log("row count = " + cnt); - if (cnt > 1) { - var target = $(this).closest('tr'); - target.remove(); - reorder(table); - } -}; +var reorder = function(class) { + console.log("QQQ Enter reorder"); -var rowCount = function(row) { - var top = $(row).closest('table'); - var trs = $(top).find('tr'); - return trs.length - 1; // exclude th section header row -}; + var divs = $.find('div[class=' + class + ']'); + console.log('divs length = ' + divs.length); -var reorder = function(table) { - var trs = $(table).find('tr').has('td'); + $(divs).find('a').hide(); - $(trs).find('a').hide(); - - $(trs).each(function(i, tr) { + $(divs).each(function(i, div) { console.log("ROW " + i); - $(tr).find('a.remove_row').show(); - replaceIndex(rowIndex(tr), i); + $(div).find('a.remove_row').show(); + replaceIndex(rowIndex(div), i); }); - $(trs).last().find('a.add_row').show(); + $(divs).last().find('a.add_row').show(); - if (trs.length == 1) { - $(trs).find('a.remove_row').hide(); + if (divs.length == 1) { + $(divs).find('a.remove_row').hide(); } }; -var rowIndex = function(elem) { - var idStr = $(elem).find('div').attr('id'); - var id = idStr.match(/\d+/); +var rowIndex = function(div) { + var idstr = $(div).attr('id'); + var id = idstr.match(/\d+/); console.log("id = " + id); + return id; +}; + +var rowCount = function(class) { + var divs = $.find('div[class=' + class + ']'); + return divs.length; }; var replaceIndex = function(elem, oldIndex, newIndex) { @@ -46,7 +38,7 @@ var replaceIndex = function(elem, oldIndex, newIndex) { var regexp = /extprofile-.*-\d.*/; var value = attrib.value; var match = value.match(regexp); - if (match != null) { + if (match !== null) { attrib.value = value.replace("-" + oldIndex, "-" + newIndex); console.log('match: oldIndex = ' + oldIndex + ' newIndex = ' + newIndex + ' name = ' + attrib.name + ' value = ' + attrib.value); } @@ -60,22 +52,42 @@ var resetRow = function(elem) { } var addRow = function() { - var divId = $(this).closest('div').attr('id'); - var index = divId.match(/\d+/); - console.log("Current row = " + index); + var div = $(this).closest('div'); + var id = $(div).attr('id'); + var class = $(div).attr('class'); + var index = id.match(/\d+/); + console.log("Current row = " + index + ', class = ' + class); var tr = $(this).closest('tr'); var newtr = $(tr).clone(); var newIndex = parseInt(index) + 1; replaceIndex(newtr, index, newIndex); resetRow(newtr); $(tr).after(newtr); - console.log("number of rows: " + rowCount(tr)); - reorder($(this).closest('table')); + reorder(class); }; +var removeRow = function() { + var div = $(this).closest('div'); + var id = $(div).attr('id'); + var class = $(div).attr('class'); + + cnt = rowCount(class); + console.debug("removeRow - cnt = " + cnt); + if (cnt > 1) { + var target = $(this).closest('tr'); + target.remove(); + reorder(class); + } +}; + +var init = function() { + reorder('phone-edit'); +} + $(document).ready( function() { + init(); $('.add_row').live('click', addRow); $('.remove_row').live('click', removeRow); } diff --git a/plugins/ExtendedProfile/profiledetailsettingsaction.php b/plugins/ExtendedProfile/profiledetailsettingsaction.php index ee450118c3..89b8d61cf9 100644 --- a/plugins/ExtendedProfile/profiledetailsettingsaction.php +++ b/plugins/ExtendedProfile/profiledetailsettingsaction.php @@ -107,7 +107,9 @@ class ProfileDetailSettingsAction extends ProfileSettingsAction foreach ($simpleFieldNames as $name) { $value = $this->trimmed('extprofile-' . $name); - $this->saveField($user, $name, $value); + if (!empty($value)) { + $this->saveField($user, $name, $value); + } } $this->savePhoneNumbers($user); @@ -118,15 +120,19 @@ class ProfileDetailSettingsAction extends ProfileSettingsAction function savePhoneNumbers($user) { $phones = $this->findPhoneNumbers(); - - foreach ($phones as $phone) { - $this->saveField( - $user, - 'phone', - $phone['value'], - $phone['rel'], - $phone['index'] - ); + $this->removeAll($user, 'phone'); + $i = 0; + foreach($phones as $phone) { + if (!empty($phone['value'])) { + ++$i; + $this->saveField( + $user, + 'phone', + $phone['value'], + $phone['rel'], + $i + ); + } } } @@ -223,6 +229,16 @@ class ProfileDetailSettingsAction extends ProfileSettingsAction $detail->free(); } + function removeAll($user, $name) + { + $profile = $user->getProfile(); + $detail = new Profile_detail(); + $detail->profile_id = $profile->id; + $detail->field_name = $name; + $detail->delete(); + $detail->free(); + } + /** * Save fields that should be stored in the main profile object * From f11b788b5af29d325f17ebb77c321309a41e5e70 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Mon, 14 Mar 2011 12:53:49 -0700 Subject: [PATCH 14/46] Extended profile - add a date value for fields --- plugins/ExtendedProfile/Profile_detail.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/ExtendedProfile/Profile_detail.php b/plugins/ExtendedProfile/Profile_detail.php index f9f4d00098..96869b0e63 100644 --- a/plugins/ExtendedProfile/Profile_detail.php +++ b/plugins/ExtendedProfile/Profile_detail.php @@ -64,6 +64,7 @@ class Profile_detail extends Managed_DataObject public $field_name; // name public $field_value; // primary text value public $value_index; // relative ordering of multiple values in the same field + public $date; // related date public $ref_profile; // for people types, allows pointing to a known profile in the system public $created; public $modified; @@ -118,6 +119,7 @@ class Profile_detail extends Managed_DataObject ), 'value_index' => array('type' => 'int'), 'field_value' => array('type' => 'text'), + 'date' => array('type' => 'datetime'), 'rel' => array('type' => 'varchar', 'length' => 16), 'rel_profile' => array('type' => 'int'), 'created' => array( From 27c75dd4bb1092199c1604700f6e5a5a6dbcb61b Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Mon, 14 Mar 2011 15:29:11 -0700 Subject: [PATCH 15/46] Extended profile - show and edit experience --- plugins/ExtendedProfile/extendedprofile.php | 28 +++- .../ExtendedProfile/extendedprofilewidget.php | 146 +++++++++++++----- plugins/ExtendedProfile/js/profiledetail.js | 1 + .../profiledetailsettingsaction.php | 93 ++++++++++- 4 files changed, 222 insertions(+), 46 deletions(-) diff --git a/plugins/ExtendedProfile/extendedprofile.php b/plugins/ExtendedProfile/extendedprofile.php index 711fdcf1bb..2277e4d769 100644 --- a/plugins/ExtendedProfile/extendedprofile.php +++ b/plugins/ExtendedProfile/extendedprofile.php @@ -129,6 +129,29 @@ class ExtendedProfile return $pArrays; } + function getExperiences() + { + $companies = (isset($this->fields['companies'])) ? $this->fields['company'] : null; + $start = (isset($this->fields['start'])) ? $this->fields['start'] : null; + $end = (isset($this->fields['end'])) ? $this->fields['end'] : null; + + $cArrays = array(); + + if (empty($experiences)) { + $eArrays[] = array( + 'label' => _m('Employer'), + 'type' => 'experience', + 'company' => "Bozotronix", + 'start' => '1/5/10', + 'end' => '2/3/11', + 'current' => true, + 'index' => 0 + ); + } + + return $eArrays; + } + /** * Return all the sections of the extended profile * @@ -206,10 +229,7 @@ class ExtendedProfile 'experience' => array( 'label' => _m('Work experience'), 'fields' => array( - 'experience' => array( - 'type' => 'experience', - 'label' => _m('Employer'), - ), + 'experience' => $this->getExperiences(), ), ), 'education' => array( diff --git a/plugins/ExtendedProfile/extendedprofilewidget.php b/plugins/ExtendedProfile/extendedprofilewidget.php index d8c42df6a3..9dfbaa716e 100644 --- a/plugins/ExtendedProfile/extendedprofilewidget.php +++ b/plugins/ExtendedProfile/extendedprofilewidget.php @@ -103,9 +103,13 @@ class ExtendedProfileWidget extends Form $this->out->elementStart('table', array('class' => 'extended-profile')); foreach ($section['fields'] as $fieldName => $field) { - if ($fieldName == 'phone') { - $this->showPhones($fieldName, $field); - } else { + + switch($fieldName) { + case 'phone': + case 'experience': + $this->showMultiple($fieldName, $field); + break; + default: $this->showExtendedProfileField($fieldName, $field); } } @@ -135,37 +139,9 @@ class ExtendedProfileWidget extends Form $this->out->elementEnd('tr'); } - /** - * Outputs the value of a field - * - * @param string $name name of the field - * @param array $field set of key/value pairs for the field - */ - protected function showFieldValue($name, $field) - { - $type = strval(@$field['type']); - - switch($type) - { - case '': - case 'text': - case 'textarea': - $this->out->text($this->ext->getTextValue($name)); - break; - case 'tags': - $this->out->text($this->ext->getTags()); - break; - case 'phone': - $this->showPhone($name, $field); - break; - default: - $this->out->text("TYPE: $type"); - } - } - - protected function showPhones($name, $field) { - foreach ($field as $phone) { - $this->showExtendedProfileField($name, $phone); + protected function showMultiple($name, $fields) { + foreach ($fields as $field) { + $this->showExtendedProfileField($name, $field); } } @@ -210,6 +186,74 @@ class ExtendedProfileWidget extends Form isset($field['rel']) ? $field['rel'] : null ); + $this->showMultiControls(); + $this->out->elementEnd('div'); + } + + protected function showExperience($name, $field) + { + $this->out->elementStart('div', array('class' => 'experience-display')); + $this->out->text($field['company']); + $this->out->elementStart('dl', 'experience-start-and-end'); + $this->out->element('dt', null, _m('Start')); + $this->out->element('dd', null, $field['start']); + $this->out->element('dt', null, _m('End')); + if ($field['current']) { + $this->out->element('dd', null, '(' . _m('Current') . ')'); + } else { + $this->out->element('dd', null, $field['end']); + } + $this->out->elementEnd('dl'); + $this->out->elementEnd('div'); + } + + protected function showEditableExperience($name, $field) + { + $index = isset($field['index']) ? $field['index'] : 0; + $id = "extprofile-$name-$index"; + $this->out->elementStart( + 'div', array( + 'id' => $id . '-edit', + 'class' => 'experience-edit' + ) + ); + + $this->out->input( + $id, + null, + isset($field['company']) ? $field['company'] : null + ); + + $this->out->elementStart('ul', 'experience-start-and-end'); + $this->out->elementStart('li'); + $this->out->input( + $id . '-start', + _m('Start'), + isset($field['start']) ? $field['start'] : null + ); + $this->out->elementEnd('li'); + + $this->out->elementStart('li'); + $this->out->input( + $id . '-end', + _m('End'), + isset($field['end']) ? $field['end'] : null + ); + $this->out->elementEnd('li'); + $this->out->elementStart('li'); + $this->out->checkbox( + $id . '-current', + _m('Current'), + $field['current'] + ); + $this->out->elementEnd('li'); + $this->out->elementEnd('ul'); + $this->showMultiControls(); + $this->out->elementEnd('div'); + } + + function showMultiControls() + { $this->out->element( 'a', array( @@ -229,8 +273,37 @@ class ExtendedProfileWidget extends Form ), '-' ); + } - $this->out->elementEnd('div'); + /** + * Outputs the value of a field + * + * @param string $name name of the field + * @param array $field set of key/value pairs for the field + */ + protected function showFieldValue($name, $field) + { + $type = strval(@$field['type']); + + switch($type) + { + case '': + case 'text': + case 'textarea': + $this->out->text($this->ext->getTextValue($name)); + break; + case 'tags': + $this->out->text($this->ext->getTags()); + break; + case 'phone': + $this->showPhone($name, $field); + break; + case 'experience': + $this->showExperience($name, $field); + break; + default: + $this->out->text("TYPE: $type"); + } } /** @@ -262,6 +335,9 @@ class ExtendedProfileWidget extends Form case 'phone': $this->showEditablePhone($name, $field); break; + case 'experience': + $this->showEditableExperience($name, $field); + break; default: $out->input($id, null, "TYPE: $type"); } diff --git a/plugins/ExtendedProfile/js/profiledetail.js b/plugins/ExtendedProfile/js/profiledetail.js index 7d7eceddc1..4dc2faf2aa 100644 --- a/plugins/ExtendedProfile/js/profiledetail.js +++ b/plugins/ExtendedProfile/js/profiledetail.js @@ -82,6 +82,7 @@ var removeRow = function() { var init = function() { reorder('phone-edit'); + reorder('experience-edit'); } $(document).ready( diff --git a/plugins/ExtendedProfile/profiledetailsettingsaction.php b/plugins/ExtendedProfile/profiledetailsettingsaction.php index 89b8d61cf9..5e505f6c28 100644 --- a/plugins/ExtendedProfile/profiledetailsettingsaction.php +++ b/plugins/ExtendedProfile/profiledetailsettingsaction.php @@ -113,6 +113,7 @@ class ProfileDetailSettingsAction extends ProfileSettingsAction } $this->savePhoneNumbers($user); + $this->saveExperiences($user); $this->showForm(_('Details saved.'), true); @@ -141,17 +142,12 @@ class ProfileDetailSettingsAction extends ProfileSettingsAction $phoneParams = $this->findMultiParams('phone'); ksort($phoneParams); // this sorts them into pairs $phones = $this->arraySplit($phoneParams, sizeof($phoneParams) / 2); - $phoneTuples = array(); - foreach($phones as $phone) { - $firstkey = current(array_keys($phone)); - $index = substr($firstkey, strrpos($firstkey, '-') + 1); + foreach ($phones as $phone) { list($number, $rel) = array_values($phone); - $phoneTuples[] = array( 'value' => $number, - 'index' => $index, 'rel' => $rel ); } @@ -159,6 +155,86 @@ class ProfileDetailSettingsAction extends ProfileSettingsAction return $phoneTuples; } + function findExperiences() { + + // Form vals look like this: + // 'extprofile-experience-0' => 'Bozotronix', + // 'extprofile-experience-0-current' => 'true' + // 'extprofile-experience-0-start' => '1/5/10', + // 'extprofile-experience-0-end' => '2/3/11', + + $experiences = array(); + $expParams = $this->findMultiParams('experience'); + ksort($expParams); + $experiences = $this->arraySplit($expParams, sizeof($expParams) / 4); + $expArray = array(); + + foreach ($experiences as $exp) { + list($company, $current, $start, $end) = array_values($exp); + $expArray[] = array( + 'company' => $company, + 'start' => $start, + 'end' => $end, + 'current' => $current, + ); + } + + return $expArray; + } + + function saveExperiences($user) { + common_debug('save experiences'); + $experiences = $this->findExperiences(); + + $this->removeAll($user, 'company'); + $this->removeAll($user, 'start'); + $this->removeAll($user, 'end'); // also stores 'current' + + $i = 0; + foreach($experiences as $experience) { + if (!empty($experience['company'])) { + ++$i; + $this->saveField( + $user, + 'company', + $experience['company'], + null, + $i + ); + /* + $this->saveField( + $user, + 'start', + null, + null, + $i, + $experience['start'] + ); + + // Save "current" employer indicator in rel + if ($experience['current']) { + $this->saveField( + $user, + 'end', + null, + 'current', // rel + $i + ); + } else { + $this->saveField( + $user, + 'end', + null, + null, + $i, + $experience['end'] + ); + } + */ + } + } + } + function arraySplit($array, $pieces) { if ($pieces < 2) { @@ -191,8 +267,9 @@ class ProfileDetailSettingsAction extends ProfileSettingsAction * @param string $value field value * @param string $rel field rel (type) * @param int $index index (fields can have multiple values) + * @param date $date related date */ - function saveField($user, $name, $value, $rel = null, $index = null) + function saveField($user, $name, $value, $rel = null, $index = null, $date = null) { $profile = $user->getProfile(); $detail = new Profile_detail(); @@ -207,6 +284,7 @@ class ProfileDetailSettingsAction extends ProfileSettingsAction $detial->value_index = $index; $detail->rel = $rel; $detail->field_value = $value; + $detail->date = $date; $detail->created = common_sql_now(); $result = $detail->insert(); if (empty($result)) { @@ -218,6 +296,7 @@ class ProfileDetailSettingsAction extends ProfileSettingsAction $detail->field_value = $value; $detail->rel = $rel; + $detail->date = $date; $result = $detail->update($orig); if (empty($result)) { From 07ccb6a9f839f39ab6c1763dc4f49e6d29b98147 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Mon, 14 Mar 2011 17:27:50 -0700 Subject: [PATCH 16/46] Extended profile - make experience save and display --- plugins/ExtendedProfile/extendedprofile.php | 28 ++++++--- .../ExtendedProfile/extendedprofilewidget.php | 4 ++ .../profiledetailsettingsaction.php | 61 +++++++++++++------ 3 files changed, 65 insertions(+), 28 deletions(-) diff --git a/plugins/ExtendedProfile/extendedprofile.php b/plugins/ExtendedProfile/extendedprofile.php index 2277e4d769..b6844e205f 100644 --- a/plugins/ExtendedProfile/extendedprofile.php +++ b/plugins/ExtendedProfile/extendedprofile.php @@ -131,24 +131,36 @@ class ExtendedProfile function getExperiences() { - $companies = (isset($this->fields['companies'])) ? $this->fields['company'] : null; + $companies = (isset($this->fields['company'])) ? $this->fields['company'] : null; $start = (isset($this->fields['start'])) ? $this->fields['start'] : null; $end = (isset($this->fields['end'])) ? $this->fields['end'] : null; - $cArrays = array(); + $eArrays = array(); - if (empty($experiences)) { + if (empty($companies)) { $eArrays[] = array( 'label' => _m('Employer'), 'type' => 'experience', - 'company' => "Bozotronix", - 'start' => '1/5/10', - 'end' => '2/3/11', - 'current' => true, + 'company' => null, + 'start' => null, + 'end' => null, + 'current' => false, 'index' => 0 ); + } else { + for ($i = 0; $i < sizeof($companies); $i++) { + $ea = array( + 'label' => _m('Employer'), + 'type' => 'experience', + 'company' => $companies[$i]->field_value, + 'index' => intval($companies[$i]->value_index), + 'current' => $end[$i]->rel, + 'start' => $start[$i]->date, + 'end' => $end[$i]->date + ); + $eArrays[] = $ea; + } } - return $eArrays; } diff --git a/plugins/ExtendedProfile/extendedprofilewidget.php b/plugins/ExtendedProfile/extendedprofilewidget.php index 9dfbaa716e..478990ac63 100644 --- a/plugins/ExtendedProfile/extendedprofilewidget.php +++ b/plugins/ExtendedProfile/extendedprofilewidget.php @@ -241,6 +241,10 @@ class ExtendedProfileWidget extends Form ); $this->out->elementEnd('li'); $this->out->elementStart('li'); + $this->out->hidden( + $id . '-current', + 'false' + ); $this->out->checkbox( $id . '-current', _m('Current'), diff --git a/plugins/ExtendedProfile/profiledetailsettingsaction.php b/plugins/ExtendedProfile/profiledetailsettingsaction.php index 5e505f6c28..56f81d7a2d 100644 --- a/plugins/ExtendedProfile/profiledetailsettingsaction.php +++ b/plugins/ExtendedProfile/profiledetailsettingsaction.php @@ -95,26 +95,27 @@ class ProfileDetailSettingsAction extends ProfileSettingsAction $user = common_current_user(); try { - $this->saveStandardProfileDetails($user); + $this->saveStandardProfileDetails($user); + + $profile = $user->getProfile(); + + $simpleFieldNames = array('title', 'spouse', 'kids'); + + foreach ($simpleFieldNames as $name) { + $value = $this->trimmed('extprofile-' . $name); + if (!empty($value)) { + $this->saveField($user, $name, $value); + } + } + + $this->savePhoneNumbers($user); + $this->saveExperiences($user); + } catch (Exception $e) { $this->showForm($e->getMessage(), false); return; } - $profile = $user->getProfile(); - - $simpleFieldNames = array('title', 'spouse', 'kids'); - - foreach ($simpleFieldNames as $name) { - $value = $this->trimmed('extprofile-' . $name); - if (!empty($value)) { - $this->saveField($user, $name, $value); - } - } - - $this->savePhoneNumbers($user); - $this->saveExperiences($user); - $this->showForm(_('Details saved.'), true); } @@ -170,11 +171,31 @@ class ProfileDetailSettingsAction extends ProfileSettingsAction $expArray = array(); foreach ($experiences as $exp) { - list($company, $current, $start, $end) = array_values($exp); + + common_debug('Experience: ' . var_export($exp, true)); + + list($company, $current, $end, $start) = array_values($exp); + + $startTs = strtotime($start); + + if ($startTs === false) { + throw new Exception( + sprintf(_m("Invalid start date: %s"), $start) + ); + } + + $endTs = strtotime($end); + + if ($current === 'false' && $endTs === false) { + throw new Exception( + sprintf(_m("Invalid end date: %s"), $start) + ); + } + $expArray[] = array( 'company' => $company, - 'start' => $start, - 'end' => $end, + 'start' => common_sql_date($startTs), + 'end' => common_sql_date($endTs), 'current' => $current, ); } @@ -201,7 +222,7 @@ class ProfileDetailSettingsAction extends ProfileSettingsAction null, $i ); - /* + $this->saveField( $user, 'start', @@ -230,7 +251,7 @@ class ProfileDetailSettingsAction extends ProfileSettingsAction $experience['end'] ); } - */ + } } } From 0fd4b84eb87b30fb2ab322225119c73195c144c2 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Mon, 14 Mar 2011 17:53:54 -0700 Subject: [PATCH 17/46] Extended profile - better error handling for bad dates --- .../profiledetailsettingsaction.php | 33 ++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/plugins/ExtendedProfile/profiledetailsettingsaction.php b/plugins/ExtendedProfile/profiledetailsettingsaction.php index 56f81d7a2d..74b2fa667b 100644 --- a/plugins/ExtendedProfile/profiledetailsettingsaction.php +++ b/plugins/ExtendedProfile/profiledetailsettingsaction.php @@ -139,10 +139,8 @@ class ProfileDetailSettingsAction extends ProfileSettingsAction } function findPhoneNumbers() { - $phones = array(); - $phoneParams = $this->findMultiParams('phone'); - ksort($phoneParams); // this sorts them into pairs - $phones = $this->arraySplit($phoneParams, sizeof($phoneParams) / 2); + + $phones = $this->sliceParams('phone', 2); $phoneTuples = array(); foreach ($phones as $phone) { @@ -156,6 +154,14 @@ class ProfileDetailSettingsAction extends ProfileSettingsAction return $phoneTuples; } + function sliceParams($key, $size) { + $slice = array(); + $params = $this->findMultiParams($key); + ksort($params); + $slice = $this->arraySplit($params, sizeof($params) / $size); + return $slice; + } + function findExperiences() { // Form vals look like this: @@ -164,10 +170,7 @@ class ProfileDetailSettingsAction extends ProfileSettingsAction // 'extprofile-experience-0-start' => '1/5/10', // 'extprofile-experience-0-end' => '2/3/11', - $experiences = array(); - $expParams = $this->findMultiParams('experience'); - ksort($expParams); - $experiences = $this->arraySplit($expParams, sizeof($expParams) / 4); + $experiences = $this->sliceParams('experience', 4); $expArray = array(); foreach ($experiences as $exp) { @@ -179,24 +182,24 @@ class ProfileDetailSettingsAction extends ProfileSettingsAction $startTs = strtotime($start); if ($startTs === false) { - throw new Exception( - sprintf(_m("Invalid start date: %s"), $start) - ); + $msg = empty($start) ? _m('You must supply a start date.') + : sprintf(_m("Invalid start date: %s"), $start); + throw new Exception($msg); } $endTs = strtotime($end); if ($current === 'false' && $endTs === false) { - throw new Exception( - sprintf(_m("Invalid end date: %s"), $start) - ); + $msg = empty($end) ? _m('You must supply an end date.') + : sprintf(_m("Invalid end date: %s"), $end); + throw new Exception($msg); } $expArray[] = array( 'company' => $company, 'start' => common_sql_date($startTs), 'end' => common_sql_date($endTs), - 'current' => $current, + 'current' => ($current == 'false') ? false : true ); } From c6a6d41dab2286caa387e6a8a5c3ffc46b773f22 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 15 Mar 2011 02:09:22 +0000 Subject: [PATCH 18/46] Extended profile - change HTML output for displaying work experience --- .../ExtendedProfile/extendedprofilewidget.php | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/plugins/ExtendedProfile/extendedprofilewidget.php b/plugins/ExtendedProfile/extendedprofilewidget.php index 478990ac63..4c47987406 100644 --- a/plugins/ExtendedProfile/extendedprofilewidget.php +++ b/plugins/ExtendedProfile/extendedprofilewidget.php @@ -192,18 +192,19 @@ class ExtendedProfileWidget extends Form protected function showExperience($name, $field) { - $this->out->elementStart('div', array('class' => 'experience-display')); - $this->out->text($field['company']); - $this->out->elementStart('dl', 'experience-start-and-end'); - $this->out->element('dt', null, _m('Start')); - $this->out->element('dd', null, $field['start']); - $this->out->element('dt', null, _m('End')); + $this->out->elementStart('div', 'experience-item'); + $this->out->element('div', 'field', $field['company']); + $this->out->element('div', 'label', _m('Start')); + $this->out->element('div', array('class' => 'field date'), $field['start']); + $this->out->element('div', 'label', _m('End')); + $this->out->element('div', array('class' => 'field date'), $field['end']); if ($field['current']) { - $this->out->element('dd', null, '(' . _m('Current') . ')'); - } else { - $this->out->element('dd', null, $field['end']); + $this->out->element( + 'div', + array('class' => 'field current'), + '(' . _m('Current') . ')' + ); } - $this->out->elementEnd('dl'); $this->out->elementEnd('div'); } From 0ff7bf77e4c208030ece6de13e8488d3845e224c Mon Sep 17 00:00:00 2001 From: Samantha Doherty Date: Mon, 14 Mar 2011 22:40:31 -0400 Subject: [PATCH 19/46] Couple quick fixes for profile view. --- plugins/ExtendedProfile/profiledetailaction.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugins/ExtendedProfile/profiledetailaction.php b/plugins/ExtendedProfile/profiledetailaction.php index beac7d6321..a777a28e03 100644 --- a/plugins/ExtendedProfile/profiledetailaction.php +++ b/plugins/ExtendedProfile/profiledetailaction.php @@ -36,7 +36,7 @@ class ProfileDetailAction extends ShowstreamAction function showStylesheets() { parent::showStylesheets(); - $this->cssLink('plugins/ExtendedProfile/profiledetail.css'); + $this->cssLink('plugins/ExtendedProfile/css/profiledetail.css'); return true; } @@ -45,6 +45,7 @@ class ProfileDetailAction extends ShowstreamAction $cur = common_current_user(); if ($cur && $cur->id == $this->profile->id) { // your own page $this->elementStart('div', 'entity_actions'); + $this->elementStart('ul'); $this->elementStart('li', 'entity_edit'); $this->element('a', array('href' => common_local_url('profiledetailsettings'), // TRANS: Link title for link on user profile. @@ -52,6 +53,7 @@ class ProfileDetailAction extends ShowstreamAction // TRANS: Link text for link on user profile. _m('Edit')); $this->elementEnd('li'); + $this->elementEnd('ul'); $this->elementEnd('div'); } From bd238e9a4de7aafbb9dd70307e965b2ba9bab6e9 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Mon, 14 Mar 2011 20:58:35 -0700 Subject: [PATCH 20/46] Extended profile - HTML layout for education entries --- plugins/ExtendedProfile/extendedprofile.php | 46 ++++++++++-- .../ExtendedProfile/extendedprofilewidget.php | 75 +++++++++++++++++++ .../profiledetailsettingsaction.php | 32 ++++---- 3 files changed, 132 insertions(+), 21 deletions(-) diff --git a/plugins/ExtendedProfile/extendedprofile.php b/plugins/ExtendedProfile/extendedprofile.php index b6844e205f..713d5c601a 100644 --- a/plugins/ExtendedProfile/extendedprofile.php +++ b/plugins/ExtendedProfile/extendedprofile.php @@ -164,6 +164,45 @@ class ExtendedProfile return $eArrays; } + function getEducation() + { + $schools = (isset($this->fields['school'])) ? $this->fields['school'] : null; + $degrees = (isset($this->fields['degree'])) ? $this->fields['degree'] : null; + $descs = (isset($this->fields['degree_description'])) ? $this->fields['degree_description'] : null; + $start = (isset($this->fields['school_start'])) ? $this->fields['school_start'] : null; + $end = (isset($this->fields['school_end'])) ? $this->fields['school_end'] : null; + $iArrays = array(); + + if (empty($schools)) { + $iArrays[] = array( + 'type' => 'education', + 'label' => _m('Institution'), + 'school' => null, + 'degree' => null, + 'description' => null, + 'start' => null, + 'end' => null, + 'index' => 0 + ); + } else { + for ($i = 0; $i < sizeof($schools); $i++) { + $ia = array( + 'type' => 'education', + 'label' => _m('Institution'), + 'school' => $schools[$i]->field_value, + 'degree' => $degrees[$i]->field_value, + 'description' => $descs[$i]->field_value, + 'index' => intval($schools[$i]->value_index), + 'start' => $start[$i]->date, + 'end' => $end[$i]->date + ); + $iArrays[] = $ia; + } + } + + return $iArrays; + } + /** * Return all the sections of the extended profile * @@ -241,16 +280,13 @@ class ExtendedProfile 'experience' => array( 'label' => _m('Work experience'), 'fields' => array( - 'experience' => $this->getExperiences(), + 'experience' => $this->getExperiences() ), ), 'education' => array( 'label' => _m('Education'), 'fields' => array( - 'education' => array( - 'type' => 'education', - 'label' => _m('Institution'), - ), + 'education' => $this->getEducation() ), ), ); diff --git a/plugins/ExtendedProfile/extendedprofilewidget.php b/plugins/ExtendedProfile/extendedprofilewidget.php index 4c47987406..967cf6dd20 100644 --- a/plugins/ExtendedProfile/extendedprofilewidget.php +++ b/plugins/ExtendedProfile/extendedprofilewidget.php @@ -107,6 +107,7 @@ class ExtendedProfileWidget extends Form switch($fieldName) { case 'phone': case 'experience': + case 'education': $this->showMultiple($fieldName, $field); break; default: @@ -257,6 +258,74 @@ class ExtendedProfileWidget extends Form $this->out->elementEnd('div'); } + protected function showEducation($name, $field) + { + $this->out->elementStart('div', 'education-item'); + $this->out->element('div', 'field', $field['school']); + $this->out->element('div', 'label', _m('Degree')); + $this->out->element('div', 'field', $field['degree']); + $this->out->element('div', 'label', _m('Description')); + $this->out->element('div', 'field', $field['description']); + $this->out->element('div', 'label', _m('Start')); + $this->out->element('div', array('class' => 'field date'), $field['start']); + $this->out->element('div', 'label', _m('End')); + $this->out->element('div', array('class' => 'field date'), $field['end']); + $this->out->elementEnd('div'); + } + + protected function showEditableEducation($name, $field) + { + $index = isset($field['index']) ? $field['index'] : 0; + $id = "extprofile-$name-$index"; + $this->out->elementStart( + 'div', array( + 'id' => $id . '-edit', + 'class' => 'education-edit' + ) + ); + $this->out->input( + $id, + null, + isset($field['school']) ? $field['school'] : null + ); + + $this->out->element('div', 'label', _m('Degree')); + $this->out->input( + $id, + null, + isset($field['degree']) ? $field['degree'] : null + ); + + $this->out->element('div', 'label', _m('Description')); + $this->out->element('div', 'field', $field['description']); + + $this->out->input( + $id, + null, + isset($field['description']) ? $field['description'] : null + ); + + $this->out->elementStart('ul', 'education-start-and-end'); + $this->out->elementStart('li'); + $this->out->input( + $id . '-start', + _m('Start'), + isset($field['start']) ? $field['start'] : null + ); + $this->out->elementEnd('li'); + + $this->out->elementStart('li'); + $this->out->input( + $id . '-end', + _m('End'), + isset($field['end']) ? $field['end'] : null + ); + $this->out->elementEnd('ul'); + + $this->showMultiControls(); + $this->out->elementEnd('div'); + } + function showMultiControls() { $this->out->element( @@ -306,6 +375,9 @@ class ExtendedProfileWidget extends Form case 'experience': $this->showExperience($name, $field); break; + case 'education': + $this->showEducation($name, $field); + break; default: $this->out->text("TYPE: $type"); } @@ -343,6 +415,9 @@ class ExtendedProfileWidget extends Form case 'experience': $this->showEditableExperience($name, $field); break; + case 'education': + $this->showEditableEducation($name, $field); + break; default: $out->input($id, null, "TYPE: $type"); } diff --git a/plugins/ExtendedProfile/profiledetailsettingsaction.php b/plugins/ExtendedProfile/profiledetailsettingsaction.php index 74b2fa667b..7870c273ba 100644 --- a/plugins/ExtendedProfile/profiledetailsettingsaction.php +++ b/plugins/ExtendedProfile/profiledetailsettingsaction.php @@ -140,26 +140,22 @@ class ProfileDetailSettingsAction extends ProfileSettingsAction function findPhoneNumbers() { - $phones = $this->sliceParams('phone', 2); - $phoneTuples = array(); + // Form vals look like this: + // 'extprofile-phone-1' => '11332', + // 'extprofile-phone-1-rel' => 'mobile', + + $phones = $this->sliceParams('phone', 2); + $phoneArray = array(); foreach ($phones as $phone) { list($number, $rel) = array_values($phone); - $phoneTuples[] = array( + $phoneArray[] = array( 'value' => $number, 'rel' => $rel ); } - return $phoneTuples; - } - - function sliceParams($key, $size) { - $slice = array(); - $params = $this->findMultiParams($key); - ksort($params); - $slice = $this->arraySplit($params, sizeof($params) / $size); - return $slice; + return $phoneArray; } function findExperiences() { @@ -174,11 +170,7 @@ class ProfileDetailSettingsAction extends ProfileSettingsAction $expArray = array(); foreach ($experiences as $exp) { - - common_debug('Experience: ' . var_export($exp, true)); - list($company, $current, $end, $start) = array_values($exp); - $startTs = strtotime($start); if ($startTs === false) { @@ -283,6 +275,14 @@ class ProfileDetailSettingsAction extends ProfileSettingsAction return $formVals; } + function sliceParams($key, $size) { + $slice = array(); + $params = $this->findMultiParams($key); + ksort($params); + $slice = $this->arraySplit($params, sizeof($params) / $size); + return $slice; + } + /** * Save an extended profile field as a Profile_detail * From 79c4af6073ab7aca718ec797c43bba957380164f Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Mon, 14 Mar 2011 21:07:14 -0700 Subject: [PATCH 21/46] Add in missing --- plugins/ExtendedProfile/extendedprofilewidget.php | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/ExtendedProfile/extendedprofilewidget.php b/plugins/ExtendedProfile/extendedprofilewidget.php index 967cf6dd20..a4913eed12 100644 --- a/plugins/ExtendedProfile/extendedprofilewidget.php +++ b/plugins/ExtendedProfile/extendedprofilewidget.php @@ -320,6 +320,7 @@ class ExtendedProfileWidget extends Form _m('End'), isset($field['end']) ? $field['end'] : null ); + $this->out->elementEnd('li'); $this->out->elementEnd('ul'); $this->showMultiControls(); From 8559fbb2ca1f7f2e154be0ec0084a324d936f22c Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Mon, 14 Mar 2011 21:09:03 -0700 Subject: [PATCH 22/46] Extended profile - intialize controls for multiple education entries --- plugins/ExtendedProfile/js/profiledetail.js | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/ExtendedProfile/js/profiledetail.js b/plugins/ExtendedProfile/js/profiledetail.js index 4dc2faf2aa..d491b46ba6 100644 --- a/plugins/ExtendedProfile/js/profiledetail.js +++ b/plugins/ExtendedProfile/js/profiledetail.js @@ -83,6 +83,7 @@ var removeRow = function() { var init = function() { reorder('phone-edit'); reorder('experience-edit'); + reorder('education-edit'); } $(document).ready( From 6d34818b5d9ca72dc1dbc2a9e484b1f7c0a45940 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Mon, 14 Mar 2011 22:02:24 -0700 Subject: [PATCH 23/46] Extended profile - make education entries save --- plugins/ExtendedProfile/extendedprofile.php | 6 +- .../ExtendedProfile/extendedprofilewidget.php | 4 +- .../profiledetailsettingsaction.php | 147 +++++++++++++++--- 3 files changed, 132 insertions(+), 25 deletions(-) diff --git a/plugins/ExtendedProfile/extendedprofile.php b/plugins/ExtendedProfile/extendedprofile.php index 713d5c601a..09d010b090 100644 --- a/plugins/ExtendedProfile/extendedprofile.php +++ b/plugins/ExtendedProfile/extendedprofile.php @@ -168,7 +168,7 @@ class ExtendedProfile { $schools = (isset($this->fields['school'])) ? $this->fields['school'] : null; $degrees = (isset($this->fields['degree'])) ? $this->fields['degree'] : null; - $descs = (isset($this->fields['degree_description'])) ? $this->fields['degree_description'] : null; + $descs = (isset($this->fields['degree_descr'])) ? $this->fields['degree_descr'] : null; $start = (isset($this->fields['school_start'])) ? $this->fields['school_start'] : null; $end = (isset($this->fields['school_end'])) ? $this->fields['school_end'] : null; $iArrays = array(); @@ -190,8 +190,8 @@ class ExtendedProfile 'type' => 'education', 'label' => _m('Institution'), 'school' => $schools[$i]->field_value, - 'degree' => $degrees[$i]->field_value, - 'description' => $descs[$i]->field_value, + 'degree' => isset($degrees[$i]->field_value) ? $degrees[$i]->field_value : null, + 'description' => isset($descs[$i]->field_value) ? $descs[$i]->field_value : null, 'index' => intval($schools[$i]->value_index), 'start' => $start[$i]->date, 'end' => $end[$i]->date diff --git a/plugins/ExtendedProfile/extendedprofilewidget.php b/plugins/ExtendedProfile/extendedprofilewidget.php index a4913eed12..03f70592fc 100644 --- a/plugins/ExtendedProfile/extendedprofilewidget.php +++ b/plugins/ExtendedProfile/extendedprofilewidget.php @@ -291,7 +291,7 @@ class ExtendedProfileWidget extends Form $this->out->element('div', 'label', _m('Degree')); $this->out->input( - $id, + $id . '-degree', null, isset($field['degree']) ? $field['degree'] : null ); @@ -300,7 +300,7 @@ class ExtendedProfileWidget extends Form $this->out->element('div', 'field', $field['description']); $this->out->input( - $id, + $id . '-description', null, isset($field['description']) ? $field['description'] : null ); diff --git a/plugins/ExtendedProfile/profiledetailsettingsaction.php b/plugins/ExtendedProfile/profiledetailsettingsaction.php index 7870c273ba..3708f54d65 100644 --- a/plugins/ExtendedProfile/profiledetailsettingsaction.php +++ b/plugins/ExtendedProfile/profiledetailsettingsaction.php @@ -110,6 +110,7 @@ class ProfileDetailSettingsAction extends ProfileSettingsAction $this->savePhoneNumbers($user); $this->saveExperiences($user); + $this->saveEducations($user); } catch (Exception $e) { $this->showForm($e->getMessage(), false); @@ -171,28 +172,30 @@ class ProfileDetailSettingsAction extends ProfileSettingsAction foreach ($experiences as $exp) { list($company, $current, $end, $start) = array_values($exp); - $startTs = strtotime($start); + if (!empty($company)) { + $startTs = strtotime($start); - if ($startTs === false) { - $msg = empty($start) ? _m('You must supply a start date.') - : sprintf(_m("Invalid start date: %s"), $start); - throw new Exception($msg); + if ($startTs === false) { + $msg = empty($start) ? _m('You must supply a start date.') + : sprintf(_m("Invalid start date: %s"), $start); + throw new Exception($msg); + } + + $endTs = strtotime($end); + + if ($current === 'false' && $endTs === false) { + $msg = empty($end) ? _m('You must supply an end date.') + : sprintf(_m("Invalid end date: %s"), $end); + throw new Exception($msg); + } + + $expArray[] = array( + 'company' => $company, + 'start' => common_sql_date($startTs), + 'end' => common_sql_date($endTs), + 'current' => ($current == 'false') ? false : true + ); } - - $endTs = strtotime($end); - - if ($current === 'false' && $endTs === false) { - $msg = empty($end) ? _m('You must supply an end date.') - : sprintf(_m("Invalid end date: %s"), $end); - throw new Exception($msg); - } - - $expArray[] = array( - 'company' => $company, - 'start' => common_sql_date($startTs), - 'end' => common_sql_date($endTs), - 'current' => ($current == 'false') ? false : true - ); } return $expArray; @@ -251,6 +254,110 @@ class ProfileDetailSettingsAction extends ProfileSettingsAction } } + function findEducations() { + + // Form vals look like this: + // 'extprofile-education-0-school' => 'Pigdog', + // 'extprofile-education-0-degree' => 'BA', + // 'extprofile-education-0-description' => 'Blar', + // 'extprofile-education-0-start' => '05/22/99', + // 'extprofile-education-0-end' => '05/22/05', + + $edus = $this->sliceParams('education', 5); + $eduArray = array(); + + foreach ($edus as $edu) { + list($school, $degree, $description, $end, $start) = array_values($edu); + + if (!empty($school)) { + + $startTs = strtotime($start); + + if ($startTs === false) { + $msg = empty($start) ? _m('You must supply a start date.') + : sprintf(_m("Invalid start date: %s"), $start); + throw new Exception($msg); + } + + $endTs = strtotime($end); + + if ($endTs === false) { + $msg = empty($end) ? _m('You must supply an end date.') + : sprintf(_m("Invalid end date: %s"), $end); + throw new Exception($msg); + } + + $eduArray[] = array( + 'school' => $school, + 'degree' => $degree, + 'description' => $description, + 'start' => common_sql_date($startTs), + 'end' => common_sql_date($endTs) + ); + } + } + + return $eduArray; + } + + + function saveEducations($user) { + common_debug('save education'); + $edus = $this->findEducations(); + common_debug(var_export($edus, true)); + + $this->removeAll($user, 'school'); + $this->removeAll($user, 'degree'); + $this->removeAll($user, 'degree_descr'); + $this->removeAll($user, 'school_start'); + $this->removeAll($user, 'school_end'); + + $i = 0; + foreach($edus as $edu) { + if (!empty($edu['school'])) { + ++$i; + $this->saveField( + $user, + 'school', + $edu['school'], + null, + $i + ); + $this->saveField( + $user, + 'degree', + $edu['degree'], + null, + $i + ); + $this->saveField( + $user, + 'degree_descr', + $edu['description'], + null, + $i + ); + $this->saveField( + $user, + 'school_start', + null, + null, + $i, + $edu['start'] + ); + + $this->saveField( + $user, + 'school_end', + null, + null, + $i, + $edu['end'] + ); + } + } + } + function arraySplit($array, $pieces) { if ($pieces < 2) { From cd82ff2dcf6a5c7f33778282c9840652829074c3 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Mon, 14 Mar 2011 22:38:34 -0700 Subject: [PATCH 24/46] Extended profile - make IMs display and save --- plugins/ExtendedProfile/extendedprofile.php | 32 +++++++++-- .../ExtendedProfile/extendedprofilewidget.php | 54 +++++++++++++++++++ plugins/ExtendedProfile/js/profiledetail.js | 1 + .../profiledetailsettingsaction.php | 39 ++++++++++++++ 4 files changed, 121 insertions(+), 5 deletions(-) diff --git a/plugins/ExtendedProfile/extendedprofile.php b/plugins/ExtendedProfile/extendedprofile.php index 09d010b090..6d78ddd3d8 100644 --- a/plugins/ExtendedProfile/extendedprofile.php +++ b/plugins/ExtendedProfile/extendedprofile.php @@ -129,6 +129,32 @@ class ExtendedProfile return $pArrays; } + function getIms() + { + $ims = (isset($this->fields['im'])) ? $this->fields['im'] : null; + $iArrays = array(); + + if (empty($ims)) { + $iArrays[] = array( + 'label' => _m('IM'), + 'type' => 'im' + ); + } else { + for ($i = 0; $i < sizeof($ims); $i++) { + $ia = array( + 'label' => _m('IM'), + 'type' => 'im', + 'index' => intval($ims[$i]->value_index), + 'rel' => $ims[$i]->rel, + 'value' => $ims[$i]->field_value, + ); + + $iArrays[] = $ia; + } + } + return $iArrays; + } + function getExperiences() { $companies = (isset($this->fields['company'])) ? $this->fields['company'] : null; @@ -248,11 +274,7 @@ class ExtendedProfile 'label' => _m('Contact'), 'fields' => array( 'phone' => $this->getPhones(), - 'im' => array( - 'label' => _m('IM'), - 'type' => 'im', - 'multi' => true, - ), + 'im' => $this->getIms(), 'website' => array( 'label' => _m('Websites'), 'type' => 'website', diff --git a/plugins/ExtendedProfile/extendedprofilewidget.php b/plugins/ExtendedProfile/extendedprofilewidget.php index 03f70592fc..5d5f1b7ab9 100644 --- a/plugins/ExtendedProfile/extendedprofilewidget.php +++ b/plugins/ExtendedProfile/extendedprofilewidget.php @@ -106,6 +106,7 @@ class ExtendedProfileWidget extends Form switch($fieldName) { case 'phone': + case 'im': case 'experience': case 'education': $this->showMultiple($fieldName, $field); @@ -156,6 +157,53 @@ class ExtendedProfileWidget extends Form $this->out->elementEnd('div'); } + protected function showIm($name, $field) + { + $this->out->elementStart('div', array('class' => 'im-display')); + $this->out->text($field['value']); + if (!empty($field['rel'])) { + $this->out->text(' (' . $field['rel'] . ')'); + } + $this->out->elementEnd('div'); + } + + protected function showEditableIm($name, $field) + { + $index = isset($field['index']) ? $field['index'] : 0; + $id = "extprofile-$name-$index"; + $rel = $id . '-rel'; + $this->out->elementStart( + 'div', array( + 'id' => $id . '-edit', + 'class' => 'im-edit' + ) + ); + $this->out->input( + $id, + null, + isset($field['value']) ? $field['value'] : null + ); + $this->out->dropdown( + $id . '-rel', + 'Type', + array( + 'jabber' => 'Jabber', + 'gtalk' => 'GTalk', + 'aim' => 'AIM', + 'yahoo' => 'Yahoo! Messenger', + 'msn' => 'MSN', + 'skype' => 'Skype', + 'other' => 'Other' + ), + null, + false, + isset($field['rel']) ? $field['rel'] : null + ); + + $this->showMultiControls(); + $this->out->elementEnd('div'); + } + protected function showEditablePhone($name, $field) { $index = isset($field['index']) ? $field['index'] : 0; @@ -373,6 +421,9 @@ class ExtendedProfileWidget extends Form case 'phone': $this->showPhone($name, $field); break; + case 'im': + $this->showIm($name, $field); + break; case 'experience': $this->showExperience($name, $field); break; @@ -413,6 +464,9 @@ class ExtendedProfileWidget extends Form case 'phone': $this->showEditablePhone($name, $field); break; + case 'im': + $this->showEditableIm($name, $field); + break; case 'experience': $this->showEditableExperience($name, $field); break; diff --git a/plugins/ExtendedProfile/js/profiledetail.js b/plugins/ExtendedProfile/js/profiledetail.js index d491b46ba6..cdd7467e93 100644 --- a/plugins/ExtendedProfile/js/profiledetail.js +++ b/plugins/ExtendedProfile/js/profiledetail.js @@ -84,6 +84,7 @@ var init = function() { reorder('phone-edit'); reorder('experience-edit'); reorder('education-edit'); + reorder('im-edit'); } $(document).ready( diff --git a/plugins/ExtendedProfile/profiledetailsettingsaction.php b/plugins/ExtendedProfile/profiledetailsettingsaction.php index 3708f54d65..baac80a482 100644 --- a/plugins/ExtendedProfile/profiledetailsettingsaction.php +++ b/plugins/ExtendedProfile/profiledetailsettingsaction.php @@ -109,6 +109,7 @@ class ProfileDetailSettingsAction extends ProfileSettingsAction } $this->savePhoneNumbers($user); + $this->saveIms($user); $this->saveExperiences($user); $this->saveEducations($user); @@ -159,6 +160,44 @@ class ProfileDetailSettingsAction extends ProfileSettingsAction return $phoneArray; } + function findIms() { + + // Form vals look like this: + // 'extprofile-im-0' => 'jed', + // 'extprofile-im-0-rel' => 'yahoo', + + $ims = $this->sliceParams('im', 2); + $imArray = array(); + + foreach ($ims as $im) { + list($id, $rel) = array_values($im); + $imArray[] = array( + 'value' => $id, + 'rel' => $rel + ); + } + + return $imArray; + } + + function saveIms($user) { + $ims = $this->findIms(); + $this->removeAll($user, 'im'); + $i = 0; + foreach($ims as $im) { + if (!empty($im['value'])) { + ++$i; + $this->saveField( + $user, + 'im', + $im['value'], + $im['rel'], + $i + ); + } + } + } + function findExperiences() { // Form vals look like this: From 7a7e0a2b69e9367c33e52e656c8e28cc9e78adaa Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Mon, 14 Mar 2011 22:47:20 -0700 Subject: [PATCH 25/46] Extended profile - change the name of divs used for sort order --- plugins/ExtendedProfile/js/profiledetail.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/ExtendedProfile/js/profiledetail.js b/plugins/ExtendedProfile/js/profiledetail.js index cdd7467e93..c198132399 100644 --- a/plugins/ExtendedProfile/js/profiledetail.js +++ b/plugins/ExtendedProfile/js/profiledetail.js @@ -81,10 +81,10 @@ var removeRow = function() { }; var init = function() { - reorder('phone-edit'); - reorder('experience-edit'); - reorder('education-edit'); - reorder('im-edit'); + reorder('phone-item'); + reorder('experience-item'); + reorder('education-item'); + reorder('im-item'); } $(document).ready( From b37c33dea2d151dcabf84357b2ea2a0b4f36be3c Mon Sep 17 00:00:00 2001 From: Samantha Doherty Date: Tue, 15 Mar 2011 13:08:41 -0400 Subject: [PATCH 26/46] Whole bunch of style-related changes, including some tasty hackery for the experience and education fields. --- plugins/ExtendedProfile/css/profiledetail.css | 137 ++++++++++++++++-- .../ExtendedProfile/extendedprofilewidget.php | 65 ++++----- plugins/ExtendedProfile/js/profiledetail.js | 8 +- 3 files changed, 164 insertions(+), 46 deletions(-) diff --git a/plugins/ExtendedProfile/css/profiledetail.css b/plugins/ExtendedProfile/css/profiledetail.css index 836b647a10..797d32d415 100644 --- a/plugins/ExtendedProfile/css/profiledetail.css +++ b/plugins/ExtendedProfile/css/profiledetail.css @@ -1,22 +1,139 @@ /* Note the #content is only needed to override weird crap in default styles */ +#profiledetail .entity_actions { + margin-top: 0px; + margin-bottom: 0px; +} + +#profiledetail #content h3 { + margin-bottom: 5px; +} + #content table.extended-profile { width: 100%; border-collapse: separate; - border-spacing: 8px; + border-spacing: 0px 8px; + margin-bottom: 10px; } + #content table.extended-profile th { color: #777; - background-color: #eee; + background-color: #ECECF2; width: 150px; - - padding-top: 0; /* override bizarre theme defaults */ - text-align: right; - padding-right: 8px; + padding: 2px 8px 2px 0px; } -#content table.extended-profile td { - padding: 0; /* override bizarre theme defaults */ - padding-left: 8px; -} \ No newline at end of file +#content table.extended-profile th.employer, #content table.extended-profile th.institution { + display: none; +} + +#content table.extended-profile td { + padding: 2px 0px 2px 8px; +} + +.experience-item, .education-item { + float: left; + padding-bottom: 4px; +} + +.experience-item .label, .education-item .label { + float: left; + clear: left; + position: relative; + left: -8px; + margin-right: 2px; + margin-bottom: 8px; + color: #777; + background-color: #ECECF2; + width: 150px; + text-align: right; + padding: 2px 8px 2px 0px; +} + +.experience-item .field, .education-item .field { + float: left; + padding-top: 2px; + padding-bottom: 2px; +} + +#profiledetailsettings #content table.extended-profile td { + padding: 0px 0px 0px 8px; +} + +#profiledetailsettings input { + margin-right: 8px; +} + +.experience-item input[type=text], .education-item input[type=text] { + float: left; +} + +.extended-profile .current-checkbox { + float: left; + position: relative; + top: 2px; +} + +.form_settings .extended-profile input.checkbox { + margin-left: 0px; + left: 0px; + top: 2px; +} + +.form_settings .extended-profile label.checkbox { + max-width: 100%; + float: none; + left: -20px; +} + +.phone-item label, .im-item label { + display: none; +} + +.extended-profile select { + padding-right: 2px; + font-size: 0.88em; +} + +.extended-profile a.add_row, .extended-profile a.remove_row { + display: block; + height: 16px; + width: 16px; + line-height: 4em; + overflow: hidden; + background-image: url('../../../theme/rebase/images/icons/icons-01.gif'); + background-repeat: no-repeat; +} + +.extended-profile a.remove_row { + background-position: 0px -1252px; + float: right; + position: relative; + top: 6px; +} + +.extended-profile a.add_row { + clear: both; + position: relative; + top: 6px; + left: 2px; + background-position: 0px -1186px; +} + +#content table.extended-profile .supersizeme th { + border-bottom: 28px solid #fff; +} + +#profiledetailsettings .experience-item, #profiledetailsettings .education-item { + margin-bottom: 10px; + width: 100%; +} + +#profiledetailsettings tr:last-child .experience-item, #profiledetailsettings tr:last-child .education-item { + margin-bottom: 0px; +} + +#profiledetailsettings .experience-item a.add_row, #profiledetailsettings .education-item a.add_row { + left: 160px; +} diff --git a/plugins/ExtendedProfile/extendedprofilewidget.php b/plugins/ExtendedProfile/extendedprofilewidget.php index 5d5f1b7ab9..161a524f94 100644 --- a/plugins/ExtendedProfile/extendedprofilewidget.php +++ b/plugins/ExtendedProfile/extendedprofilewidget.php @@ -128,7 +128,7 @@ class ExtendedProfileWidget extends Form { $this->out->elementStart('tr'); - $this->out->element('th', null, $field['label']); + $this->out->element('th', str_replace(' ','_',strtolower($field['label'])), $field['label']); $this->out->elementStart('td'); if ($this->editable) { @@ -175,7 +175,7 @@ class ExtendedProfileWidget extends Form $this->out->elementStart( 'div', array( 'id' => $id . '-edit', - 'class' => 'im-edit' + 'class' => 'im-item' ) ); $this->out->input( @@ -212,7 +212,7 @@ class ExtendedProfileWidget extends Form $this->out->elementStart( 'div', array( 'id' => $id . '-edit', - 'class' => 'phone-edit' + 'class' => 'phone-item' ) ); $this->out->input( @@ -242,6 +242,7 @@ class ExtendedProfileWidget extends Form protected function showExperience($name, $field) { $this->out->elementStart('div', 'experience-item'); + $this->out->element('div', 'label', _m('Company')); $this->out->element('div', 'field', $field['company']); $this->out->element('div', 'label', _m('Start')); $this->out->element('div', array('class' => 'field date'), $field['start']); @@ -264,44 +265,42 @@ class ExtendedProfileWidget extends Form $this->out->elementStart( 'div', array( 'id' => $id . '-edit', - 'class' => 'experience-edit' + 'class' => 'experience-item' ) ); + $this->out->element('div', 'label', _m('Company')); $this->out->input( $id, null, isset($field['company']) ? $field['company'] : null ); - $this->out->elementStart('ul', 'experience-start-and-end'); - $this->out->elementStart('li'); + $this->out->element('div', 'label', _m('Start')); $this->out->input( $id . '-start', - _m('Start'), + null, isset($field['start']) ? $field['start'] : null ); - $this->out->elementEnd('li'); - $this->out->elementStart('li'); + $this->out->element('div', 'label', _m('End')); $this->out->input( $id . '-end', - _m('End'), + null, isset($field['end']) ? $field['end'] : null ); - $this->out->elementEnd('li'); - $this->out->elementStart('li'); $this->out->hidden( $id . '-current', 'false' ); + $this->out->elementStart('div', 'current-checkbox'); $this->out->checkbox( $id . '-current', _m('Current'), $field['current'] ); - $this->out->elementEnd('li'); - $this->out->elementEnd('ul'); + $this->out->elementEnd('div'); + $this->showMultiControls(); $this->out->elementEnd('div'); } @@ -309,6 +308,7 @@ class ExtendedProfileWidget extends Form protected function showEducation($name, $field) { $this->out->elementStart('div', 'education-item'); + $this->out->element('div', 'label', _m('Institution')); $this->out->element('div', 'field', $field['school']); $this->out->element('div', 'label', _m('Degree')); $this->out->element('div', 'field', $field['degree']); @@ -328,9 +328,10 @@ class ExtendedProfileWidget extends Form $this->out->elementStart( 'div', array( 'id' => $id . '-edit', - 'class' => 'education-edit' + 'class' => 'education-item' ) ); + $this->out->element('div', 'label', _m('Institution')); $this->out->input( $id, null, @@ -353,23 +354,19 @@ class ExtendedProfileWidget extends Form isset($field['description']) ? $field['description'] : null ); - $this->out->elementStart('ul', 'education-start-and-end'); - $this->out->elementStart('li'); + $this->out->element('div', 'label', _m('Start')); $this->out->input( $id . '-start', - _m('Start'), + null, isset($field['start']) ? $field['start'] : null ); - $this->out->elementEnd('li'); - $this->out->elementStart('li'); + $this->out->element('div', 'label', _m('End')); $this->out->input( $id . '-end', - _m('End'), + null, isset($field['end']) ? $field['end'] : null ); - $this->out->elementEnd('li'); - $this->out->elementEnd('ul'); $this->showMultiControls(); $this->out->elementEnd('div'); @@ -377,16 +374,6 @@ class ExtendedProfileWidget extends Form function showMultiControls() { - $this->out->element( - 'a', - array( - 'class' => 'add_row', - 'href' => 'javascript://', - 'style' => 'display: none; ' - ), - '+' - ); - $this->out->element( 'a', array( @@ -396,6 +383,16 @@ class ExtendedProfileWidget extends Form ), '-' ); + + $this->out->element( + 'a', + array( + 'class' => 'add_row', + 'href' => 'javascript://', + 'style' => 'display: none; ' + ), + '+' + ); } /** @@ -514,7 +511,7 @@ class ExtendedProfileWidget extends Form function formClass() { - return 'form_profile_details'; + return 'form_profile_details form_settings'; } /** diff --git a/plugins/ExtendedProfile/js/profiledetail.js b/plugins/ExtendedProfile/js/profiledetail.js index c198132399..2821bed275 100644 --- a/plugins/ExtendedProfile/js/profiledetail.js +++ b/plugins/ExtendedProfile/js/profiledetail.js @@ -12,6 +12,9 @@ var reorder = function(class) { replaceIndex(rowIndex(div), i); }); + $this = $(divs).last().closest('tr'); + $this.addClass('supersizeme'); + $(divs).last().find('a.add_row').show(); if (divs.length == 1) { @@ -57,7 +60,8 @@ var addRow = function() { var class = $(div).attr('class'); var index = id.match(/\d+/); console.log("Current row = " + index + ', class = ' + class); - var tr = $(this).closest('tr'); + var trold = $(this).closest('tr'); + var tr = $(trold).removeClass('supersizeme'); var newtr = $(tr).clone(); var newIndex = parseInt(index) + 1; replaceIndex(newtr, index, newIndex); @@ -95,4 +99,4 @@ function() { $('.remove_row').live('click', removeRow); } -); \ No newline at end of file +); From a6ae9ddd418a4bee2173a4188d5c382168f5d51e Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 15 Mar 2011 10:10:18 -0700 Subject: [PATCH 27/46] Extended profile - make websites save --- plugins/ExtendedProfile/extendedprofile.php | 38 ++++++++++--- .../ExtendedProfile/extendedprofilewidget.php | 57 +++++++++++++++++++ .../profiledetailsettingsaction.php | 37 ++++++++++++ 3 files changed, 125 insertions(+), 7 deletions(-) diff --git a/plugins/ExtendedProfile/extendedprofile.php b/plugins/ExtendedProfile/extendedprofile.php index 6d78ddd3d8..673680f027 100644 --- a/plugins/ExtendedProfile/extendedprofile.php +++ b/plugins/ExtendedProfile/extendedprofile.php @@ -98,6 +98,8 @@ class ExtendedProfile } } + // XXX: getPhones, getIms, and getWebsites pretty much do the same thing, + // so refactor. function getPhones() { $phones = (isset($this->fields['phone'])) ? $this->fields['phone'] : null; @@ -155,6 +157,32 @@ class ExtendedProfile return $iArrays; } + function getWebsites() + { + $sites = (isset($this->fields['website'])) ? $this->fields['website'] : null; + $wArrays = array(); + + if (empty($sites)) { + $wArrays[] = array( + 'label' => _m('Website'), + 'type' => 'website' + ); + } else { + for ($i = 0; $i < sizeof($sites); $i++) { + $wa = array( + 'label' => _m('Website'), + 'type' => 'website', + 'index' => intval($sites[$i]->value_index), + 'rel' => $sites[$i]->rel, + 'value' => $sites[$i]->field_value, + ); + + $wArrays[] = $wa; + } + } + return $wArrays; + } + function getExperiences() { $companies = (isset($this->fields['company'])) ? $this->fields['company'] : null; @@ -273,13 +301,9 @@ class ExtendedProfile 'contact' => array( 'label' => _m('Contact'), 'fields' => array( - 'phone' => $this->getPhones(), - 'im' => $this->getIms(), - 'website' => array( - 'label' => _m('Websites'), - 'type' => 'website', - 'multi' => true, - ), + 'phone' => $this->getPhones(), + 'im' => $this->getIms(), + 'website' => $this->getWebsites() ), ), 'personal' => array( diff --git a/plugins/ExtendedProfile/extendedprofilewidget.php b/plugins/ExtendedProfile/extendedprofilewidget.php index 5d5f1b7ab9..99d5852276 100644 --- a/plugins/ExtendedProfile/extendedprofilewidget.php +++ b/plugins/ExtendedProfile/extendedprofilewidget.php @@ -107,6 +107,7 @@ class ExtendedProfileWidget extends Form switch($fieldName) { case 'phone': case 'im': + case 'website': case 'experience': case 'education': $this->showMultiple($fieldName, $field); @@ -147,6 +148,8 @@ class ExtendedProfileWidget extends Form } } + // XXX: showPhone, showIm and showWebsite all work the same, so + // combine protected function showPhone($name, $field) { $this->out->elementStart('div', array('class' => 'phone-display')); @@ -167,6 +170,16 @@ class ExtendedProfileWidget extends Form $this->out->elementEnd('div'); } + protected function showWebsite($name, $field) + { + $this->out->elementStart('div', array('class' => 'website-display')); + $this->out->text($field['value']); + if (!empty($field['rel'])) { + $this->out->text(' (' . $field['rel'] . ')'); + } + $this->out->elementEnd('div'); + } + protected function showEditableIm($name, $field) { $index = isset($field['index']) ? $field['index'] : 0; @@ -239,6 +252,44 @@ class ExtendedProfileWidget extends Form $this->out->elementEnd('div'); } + protected function showEditableWebsite($name, $field) + { + $index = isset($field['index']) ? $field['index'] : 0; + $id = "extprofile-$name-$index"; + $rel = $id . '-rel'; + $this->out->elementStart( + 'div', array( + 'id' => $id . '-edit', + 'class' => 'website-edit' + ) + ); + $this->out->input( + $id, + null, + isset($field['value']) ? $field['value'] : null + ); + $this->out->dropdown( + $id . '-rel', + 'Type', + array( + 'blog' => 'Blog', + 'homepage' => 'Homepage', + 'facebook' => 'Facebook', + 'linkedin' => 'LinkedIn', + 'flickr' => 'Flickr', + 'google' => 'Google Profile', + 'other' => 'Other', + 'twitter' => 'Twitter' + ), + null, + false, + isset($field['rel']) ? $field['rel'] : null + ); + + $this->showMultiControls(); + $this->out->elementEnd('div'); + } + protected function showExperience($name, $field) { $this->out->elementStart('div', 'experience-item'); @@ -421,6 +472,9 @@ class ExtendedProfileWidget extends Form case 'phone': $this->showPhone($name, $field); break; + case 'website': + $this->showWebsite($name, $field); + break; case 'im': $this->showIm($name, $field); break; @@ -467,6 +521,9 @@ class ExtendedProfileWidget extends Form case 'im': $this->showEditableIm($name, $field); break; + case 'website': + $this->showEditableWebsite($name, $field); + break; case 'experience': $this->showEditableExperience($name, $field); break; diff --git a/plugins/ExtendedProfile/profiledetailsettingsaction.php b/plugins/ExtendedProfile/profiledetailsettingsaction.php index baac80a482..2357860884 100644 --- a/plugins/ExtendedProfile/profiledetailsettingsaction.php +++ b/plugins/ExtendedProfile/profiledetailsettingsaction.php @@ -110,6 +110,7 @@ class ProfileDetailSettingsAction extends ProfileSettingsAction $this->savePhoneNumbers($user); $this->saveIms($user); + $this->saveWebsites($user); $this->saveExperiences($user); $this->saveEducations($user); @@ -198,6 +199,42 @@ class ProfileDetailSettingsAction extends ProfileSettingsAction } } + function findWebsites() { + + // Form vals look like this: + + $sites = $this->sliceParams('website', 2); + $wsArray = array(); + + foreach ($sites as $site) { + list($id, $rel) = array_values($site); + $wsArray[] = array( + 'value' => $id, + 'rel' => $rel + ); + } + + return $wsArray; + } + + function saveWebsites($user) { + $sites = $this->findWebsites(); + $this->removeAll($user, 'website'); + $i = 0; + foreach($sites as $site) { + if (!empty($site['value'])) { + ++$i; + $this->saveField( + $user, + 'website', + $site['value'], + $site['rel'], + $i + ); + } + } + } + function findExperiences() { // Form vals look like this: From e4eb6719a5e270430b57425bcb344f0c7971254b Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 15 Mar 2011 15:35:00 -0700 Subject: [PATCH 28/46] Extended profile - make birthday save --- .../ExtendedProfile/extendedprofilewidget.php | 8 +- .../profiledetailsettingsaction.php | 76 +++++++++---------- 2 files changed, 45 insertions(+), 39 deletions(-) diff --git a/plugins/ExtendedProfile/extendedprofilewidget.php b/plugins/ExtendedProfile/extendedprofilewidget.php index 05cfadacc3..fc3d7ca51d 100644 --- a/plugins/ExtendedProfile/extendedprofilewidget.php +++ b/plugins/ExtendedProfile/extendedprofilewidget.php @@ -399,7 +399,7 @@ class ExtendedProfileWidget extends Form $this->out->element('div', 'label', _m('Description')); $this->out->element('div', 'field', $field['description']); - $this->out->input( + $this->out->textarea( $id . '-description', null, isset($field['description']) ? $field['description'] : null @@ -463,6 +463,9 @@ class ExtendedProfileWidget extends Form case 'textarea': $this->out->text($this->ext->getTextValue($name)); break; + case 'date': + $this->out->text($this->ext->getTextValue($name)); + break; case 'tags': $this->out->text($this->ext->getTags()); break; @@ -506,6 +509,9 @@ class ExtendedProfileWidget extends Form case 'text': $out->input($id, null, $this->ext->getTextValue($name)); break; + case 'date': + $out->input($id, null, $this->ext->getTextValue($name)); + break; case 'textarea': $out->textarea($id, null, $this->ext->getTextValue($name)); break; diff --git a/plugins/ExtendedProfile/profiledetailsettingsaction.php b/plugins/ExtendedProfile/profiledetailsettingsaction.php index 2357860884..d3b653bad2 100644 --- a/plugins/ExtendedProfile/profiledetailsettingsaction.php +++ b/plugins/ExtendedProfile/profiledetailsettingsaction.php @@ -100,6 +100,7 @@ class ProfileDetailSettingsAction extends ProfileSettingsAction $profile = $user->getProfile(); $simpleFieldNames = array('title', 'spouse', 'kids'); + $dateFieldNames = array('birthday'); foreach ($simpleFieldNames as $name) { $value = $this->trimmed('extprofile-' . $name); @@ -108,6 +109,15 @@ class ProfileDetailSettingsAction extends ProfileSettingsAction } } + foreach ($dateFieldNames as $name) { + $value = $this->trimmed('extprofile-' . $name); + $this->saveField( + $user, + $name, + $this->parseDate($name, $value) + ); + } + $this->savePhoneNumbers($user); $this->saveIms($user); $this->saveWebsites($user); @@ -123,6 +133,30 @@ class ProfileDetailSettingsAction extends ProfileSettingsAction } + function parseDate($fieldname, $datestr, $required = false) + { + if (empty($datestr) && $required) { + $msg = sprintf( + _m('You must supply a date for "%s".'), + $fieldname + ); + throw new Exception($msg); + } else { + $ts = strtotime($datestr); + if ($ts === false) { + throw new Exception( + sprintf( + _m('Invalid date entered for "%s": %s'), + $fieldname, + $ts + ) + ); + } + return common_sql_date($ts); + } + return null; + } + function savePhoneNumbers($user) { $phones = $this->findPhoneNumbers(); $this->removeAll($user, 'phone'); @@ -249,26 +283,10 @@ class ProfileDetailSettingsAction extends ProfileSettingsAction foreach ($experiences as $exp) { list($company, $current, $end, $start) = array_values($exp); if (!empty($company)) { - $startTs = strtotime($start); - - if ($startTs === false) { - $msg = empty($start) ? _m('You must supply a start date.') - : sprintf(_m("Invalid start date: %s"), $start); - throw new Exception($msg); - } - - $endTs = strtotime($end); - - if ($current === 'false' && $endTs === false) { - $msg = empty($end) ? _m('You must supply an end date.') - : sprintf(_m("Invalid end date: %s"), $end); - throw new Exception($msg); - } - $expArray[] = array( 'company' => $company, - 'start' => common_sql_date($startTs), - 'end' => common_sql_date($endTs), + 'start' => $this->parseDate('Start', $start, true), + 'end' => $this->parseDate('End', $end, true), 'current' => ($current == 'false') ? false : true ); } @@ -344,31 +362,13 @@ class ProfileDetailSettingsAction extends ProfileSettingsAction foreach ($edus as $edu) { list($school, $degree, $description, $end, $start) = array_values($edu); - if (!empty($school)) { - - $startTs = strtotime($start); - - if ($startTs === false) { - $msg = empty($start) ? _m('You must supply a start date.') - : sprintf(_m("Invalid start date: %s"), $start); - throw new Exception($msg); - } - - $endTs = strtotime($end); - - if ($endTs === false) { - $msg = empty($end) ? _m('You must supply an end date.') - : sprintf(_m("Invalid end date: %s"), $end); - throw new Exception($msg); - } - $eduArray[] = array( 'school' => $school, 'degree' => $degree, 'description' => $description, - 'start' => common_sql_date($startTs), - 'end' => common_sql_date($endTs) + 'start' => $this->parseDate('Start', $start, true), + 'end' => $this->parseDate('End', $end, true) ); } } From 903ce7d10cff41b91f6fb83adc3f32bfdfc62acd Mon Sep 17 00:00:00 2001 From: Samantha Doherty Date: Tue, 15 Mar 2011 21:43:28 -0400 Subject: [PATCH 29/46] Hide all unnecessarylabels from profile edit view. --- plugins/ExtendedProfile/css/profiledetail.css | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/plugins/ExtendedProfile/css/profiledetail.css b/plugins/ExtendedProfile/css/profiledetail.css index 797d32d415..e0650d40a1 100644 --- a/plugins/ExtendedProfile/css/profiledetail.css +++ b/plugins/ExtendedProfile/css/profiledetail.css @@ -65,6 +65,10 @@ margin-right: 8px; } +.form_settings .extended-profile label { + display: none; +} + .experience-item input[type=text], .education-item input[type=text] { float: left; } @@ -84,13 +88,10 @@ .form_settings .extended-profile label.checkbox { max-width: 100%; float: none; + display: inline; left: -20px; } -.phone-item label, .im-item label { - display: none; -} - .extended-profile select { padding-right: 2px; font-size: 0.88em; From 95d03e74e940ef8f50e26d8e7a3a4b68509dd9c2 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 15 Mar 2011 18:45:08 -0700 Subject: [PATCH 30/46] Extended profile - autocomplete for manager --- .../ExtendedProfile/ExtendedProfilePlugin.php | 22 +++- .../action/userautocomplete.php | 113 ++++++++++++++++++ .../ExtendedProfile/extendedprofilewidget.php | 6 + plugins/ExtendedProfile/js/profiledetail.js | 5 + .../profiledetailsettingsaction.php | 4 +- 5 files changed, 144 insertions(+), 6 deletions(-) create mode 100644 plugins/ExtendedProfile/action/userautocomplete.php diff --git a/plugins/ExtendedProfile/ExtendedProfilePlugin.php b/plugins/ExtendedProfile/ExtendedProfilePlugin.php index 933b43cad7..d1572ce9fd 100644 --- a/plugins/ExtendedProfile/ExtendedProfilePlugin.php +++ b/plugins/ExtendedProfile/ExtendedProfilePlugin.php @@ -54,6 +54,7 @@ class ExtendedProfilePlugin extends Plugin function onAutoload($cls) { $lower = strtolower($cls); + switch ($lower) { case 'extendedprofile': @@ -62,6 +63,9 @@ class ExtendedProfilePlugin extends Plugin case 'profiledetailsettingsaction': require_once dirname(__FILE__) . '/' . $lower . '.php'; return false; + case 'userautocompleteaction': + require_once dirname(__FILE__) . '/action/' . mb_substr($lower, 0, -6) . '.php'; + return false; case 'profile_detail': require_once dirname(__FILE__) . '/' . ucfirst($lower) . '.php'; return false; @@ -81,11 +85,19 @@ class ExtendedProfilePlugin extends Plugin */ function onStartInitializeRouter($m) { - $m->connect(':nickname/detail', - array('action' => 'profiledetail'), - array('nickname' => Nickname::DISPLAY_FMT)); - $m->connect('settings/profile/detail', - array('action' => 'profiledetailsettings')); + $m->connect( + ':nickname/detail', + array('action' => 'profiledetail'), + array('nickname' => Nickname::DISPLAY_FMT) + ); + $m->connect( + '/settings/profile/finduser', + array('action' => 'Userautocomplete') + ); + $m->connect( + 'settings/profile/detail', + array('action' => 'profiledetailsettings') + ); return true; } diff --git a/plugins/ExtendedProfile/action/userautocomplete.php b/plugins/ExtendedProfile/action/userautocomplete.php new file mode 100644 index 0000000000..d4857429e0 --- /dev/null +++ b/plugins/ExtendedProfile/action/userautocomplete.php @@ -0,0 +1,113 @@ +. + * + * @category Search + * @package StatusNet + * @author Zach Copley + * @copyright 2011 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +if (!defined('STATUSNET')) { + exit(1); +} + + +class UserautocompleteAction extends Action +{ + var $query; + + /** + * Initialization. + * + * @param array $args Web and URL arguments + * + * @return boolean true if nothing goes wrong + */ + function prepare($args) + { + parent::prepare($args); + $this->query = $this->trimmed('term'); + return true; + } + + /** + * Handle a request + * + * @param array $args Arguments from $_REQUEST + * + * @return void + */ + function handle($args) + { + parent::handle($args); + $this->showResults(); + } + + /** + * Search for users matching the query and spit the results out + * as a quick-n-dirty JSON document + * + * @return void + */ + function showResults() + { + $people = array(); + + $profile = new Profile(); + + $search_engine = $profile->getSearchEngine('profile'); + $search_engine->set_sort_mode('nickname_desc'); + $search_engine->limit(0, 10); + $search_engine->query(strtolower($this->query . '*')); + + $cnt = $profile->find(); + + if ($cnt > 0) { + + $sql = 'SELECT profile.* FROM profile, user WHERE profile.id = user.id ' + . ' AND LEFT(LOWER(profile.nickname), ' + . strlen($this->query) + . ') = \'%s\' ' + . ' LIMIT 0, 10'; + + $profile->query(sprintf($sql, $this->query)); + } + + while ($profile->fetch()) { + $people[] = $profile->nickname; + } + + header('Content-Type: application/json; charset=utf-8'); + print json_encode($people); + } + + /** + * Do we need to write to the database? + * + * @return boolean true + */ + function isReadOnly($args) + { + return true; + } +} diff --git a/plugins/ExtendedProfile/extendedprofilewidget.php b/plugins/ExtendedProfile/extendedprofilewidget.php index fc3d7ca51d..dec0512be4 100644 --- a/plugins/ExtendedProfile/extendedprofilewidget.php +++ b/plugins/ExtendedProfile/extendedprofilewidget.php @@ -466,6 +466,9 @@ class ExtendedProfileWidget extends Form case 'date': $this->out->text($this->ext->getTextValue($name)); break; + case 'person': + $this->out->text($this->ext->getTextValue($name)); + break; case 'tags': $this->out->text($this->ext->getTags()); break; @@ -512,6 +515,9 @@ class ExtendedProfileWidget extends Form case 'date': $out->input($id, null, $this->ext->getTextValue($name)); break; + case 'person': + $out->input($id, null, $this->ext->getTextValue($name)); + break; case 'textarea': $out->textarea($id, null, $this->ext->getTextValue($name)); break; diff --git a/plugins/ExtendedProfile/js/profiledetail.js b/plugins/ExtendedProfile/js/profiledetail.js index 2821bed275..7510323a43 100644 --- a/plugins/ExtendedProfile/js/profiledetail.js +++ b/plugins/ExtendedProfile/js/profiledetail.js @@ -89,6 +89,11 @@ var init = function() { reorder('experience-item'); reorder('education-item'); reorder('im-item'); + + $("input#extprofile-manager").autocomplete({ + source: 'finduser', + minLength: 2 }); + } $(document).ready( diff --git a/plugins/ExtendedProfile/profiledetailsettingsaction.php b/plugins/ExtendedProfile/profiledetailsettingsaction.php index d3b653bad2..b0590f7316 100644 --- a/plugins/ExtendedProfile/profiledetailsettingsaction.php +++ b/plugins/ExtendedProfile/profiledetailsettingsaction.php @@ -44,12 +44,14 @@ class ProfileDetailSettingsAction extends ProfileSettingsAction function showStylesheets() { parent::showStylesheets(); $this->cssLink('plugins/ExtendedProfile/css/profiledetail.css'); + $this->cssLink('http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/themes/base/jquery-ui.css'); return true; } function showScripts() { parent::showScripts(); $this->script('plugins/ExtendedProfile/js/profiledetail.js'); + $this->script('http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/jquery-ui.min.js'); return true; } @@ -99,7 +101,7 @@ class ProfileDetailSettingsAction extends ProfileSettingsAction $profile = $user->getProfile(); - $simpleFieldNames = array('title', 'spouse', 'kids'); + $simpleFieldNames = array('title', 'spouse', 'kids', 'manager'); $dateFieldNames = array('birthday'); foreach ($simpleFieldNames as $name) { From b11a2faf5412a73690535df66034a06467e4208e Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 15 Mar 2011 19:33:05 -0700 Subject: [PATCH 31/46] Extended profile - namespace JavaScript functions --- plugins/ExtendedProfile/js/profiledetail.js | 55 ++++++++++----------- 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/plugins/ExtendedProfile/js/profiledetail.js b/plugins/ExtendedProfile/js/profiledetail.js index 7510323a43..98594a46b7 100644 --- a/plugins/ExtendedProfile/js/profiledetail.js +++ b/plugins/ExtendedProfile/js/profiledetail.js @@ -1,4 +1,6 @@ -var reorder = function(class) { +var SN_EXTENDED = SN_EXTENDED || {}; + +SN_EXTENDED.reorder = function(class) { console.log("QQQ Enter reorder"); var divs = $.find('div[class=' + class + ']'); @@ -9,7 +11,7 @@ var reorder = function(class) { $(divs).each(function(i, div) { console.log("ROW " + i); $(div).find('a.remove_row').show(); - replaceIndex(rowIndex(div), i); + SN_EXTENDED.replaceIndex(SN_EXTENDED.rowIndex(div), i); }); $this = $(divs).last().closest('tr'); @@ -23,19 +25,19 @@ var reorder = function(class) { }; -var rowIndex = function(div) { +SN_EXTENDED.rowIndex = function(div) { var idstr = $(div).attr('id'); var id = idstr.match(/\d+/); console.log("id = " + id); return id; }; -var rowCount = function(class) { +SN_EXTENDED.rowCount = function(class) { var divs = $.find('div[class=' + class + ']'); return divs.length; }; -var replaceIndex = function(elem, oldIndex, newIndex) { +SN_EXTENDED.replaceIndex = function(elem, oldIndex, newIndex) { $(elem).find('*').each(function() { $.each(this.attributes, function(i, attrib) { var regexp = /extprofile-.*-\d.*/; @@ -49,12 +51,12 @@ var replaceIndex = function(elem, oldIndex, newIndex) { }); } -var resetRow = function(elem) { +SN_EXTENDED.resetRow = function(elem) { $(elem).find('input').attr('value', ''); $(elem).find("select option[value='office']").attr("selected", true); } -var addRow = function() { +SN_EXTENDED.addRow = function() { var div = $(this).closest('div'); var id = $(div).attr('id'); var class = $(div).attr('class'); @@ -64,44 +66,41 @@ var addRow = function() { var tr = $(trold).removeClass('supersizeme'); var newtr = $(tr).clone(); var newIndex = parseInt(index) + 1; - replaceIndex(newtr, index, newIndex); - resetRow(newtr); + SN_EXTENDED.replaceIndex(newtr, index, newIndex); + SN_EXTENDED.resetRow(newtr); $(tr).after(newtr); - reorder(class); + SN_EXTENDED.reorder(class); }; -var removeRow = function() { +SN_EXTENDED.removeRow = function() { var div = $(this).closest('div'); var id = $(div).attr('id'); var class = $(div).attr('class'); - cnt = rowCount(class); + cnt = SN_EXTENDED.rowCount(class); console.debug("removeRow - cnt = " + cnt); if (cnt > 1) { var target = $(this).closest('tr'); target.remove(); - reorder(class); + SN_EXTENDED.reorder(class); } }; -var init = function() { - reorder('phone-item'); - reorder('experience-item'); - reorder('education-item'); - reorder('im-item'); +$(document).ready( + +function() { + + var multifields = ["phone-item", "experience-item", "education-item", "im-item"]; + + for (f in multifields) { + SN_EXTENDED.reorder(multifields[f]); + } $("input#extprofile-manager").autocomplete({ source: 'finduser', minLength: 2 }); -} + $('.add_row').live('click', SN_EXTENDED.addRow); + $('.remove_row').live('click', SN_EXTENDED.removeRow); -$(document).ready( - -function() { - init(); - $('.add_row').live('click', addRow); - $('.remove_row').live('click', removeRow); -} - -); +}); From bde85a668551251493ab5343d3a8a02db29bb87e Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 15 Mar 2011 21:23:34 -0700 Subject: [PATCH 32/46] Extended profile - fix issue with JavaScript not executing in Firefox --- .../ExtendedProfile/extendedprofilewidget.php | 4 +- plugins/ExtendedProfile/js/profiledetail.js | 49 ++++++++----------- 2 files changed, 22 insertions(+), 31 deletions(-) diff --git a/plugins/ExtendedProfile/extendedprofilewidget.php b/plugins/ExtendedProfile/extendedprofilewidget.php index dec0512be4..5a9eb7e4f9 100644 --- a/plugins/ExtendedProfile/extendedprofilewidget.php +++ b/plugins/ExtendedProfile/extendedprofilewidget.php @@ -430,7 +430,7 @@ class ExtendedProfileWidget extends Form array( 'class' => 'remove_row', 'href' => 'javascript://', - 'style' => 'display: none; ' + 'style' => 'display: none;' ), '-' ); @@ -440,7 +440,7 @@ class ExtendedProfileWidget extends Form array( 'class' => 'add_row', 'href' => 'javascript://', - 'style' => 'display: none; ' + 'style' => 'display: none;' ), '+' ); diff --git a/plugins/ExtendedProfile/js/profiledetail.js b/plugins/ExtendedProfile/js/profiledetail.js index 98594a46b7..9fb935f153 100644 --- a/plugins/ExtendedProfile/js/profiledetail.js +++ b/plugins/ExtendedProfile/js/profiledetail.js @@ -1,39 +1,32 @@ var SN_EXTENDED = SN_EXTENDED || {}; -SN_EXTENDED.reorder = function(class) { - console.log("QQQ Enter reorder"); +SN_EXTENDED.reorder = function(cls) { - var divs = $.find('div[class=' + class + ']'); - console.log('divs length = ' + divs.length); - - $(divs).find('a').hide(); + var divs = $('div[class=' + cls + ']'); $(divs).each(function(i, div) { - console.log("ROW " + i); $(div).find('a.remove_row').show(); SN_EXTENDED.replaceIndex(SN_EXTENDED.rowIndex(div), i); }); - $this = $(divs).last().closest('tr'); - $this.addClass('supersizeme'); + var lastDiv = $(divs).last().closest('tr'); + lastDiv.addClass('supersizeme'); $(divs).last().find('a.add_row').show(); if (divs.length == 1) { $(divs).find('a.remove_row').hide(); } - }; SN_EXTENDED.rowIndex = function(div) { var idstr = $(div).attr('id'); var id = idstr.match(/\d+/); - console.log("id = " + id); return id; }; -SN_EXTENDED.rowCount = function(class) { - var divs = $.find('div[class=' + class + ']'); +SN_EXTENDED.rowCount = function(cls) { + var divs = $.find('div[class=' + cls + ']'); return divs.length; }; @@ -45,7 +38,6 @@ SN_EXTENDED.replaceIndex = function(elem, oldIndex, newIndex) { var match = value.match(regexp); if (match !== null) { attrib.value = value.replace("-" + oldIndex, "-" + newIndex); - console.log('match: oldIndex = ' + oldIndex + ' newIndex = ' + newIndex + ' name = ' + attrib.name + ' value = ' + attrib.value); } }); }); @@ -54,41 +46,40 @@ SN_EXTENDED.replaceIndex = function(elem, oldIndex, newIndex) { SN_EXTENDED.resetRow = function(elem) { $(elem).find('input').attr('value', ''); $(elem).find("select option[value='office']").attr("selected", true); -} +}; SN_EXTENDED.addRow = function() { var div = $(this).closest('div'); - var id = $(div).attr('id'); - var class = $(div).attr('class'); + var id = div.attr('id'); + var cls = div.attr('class'); var index = id.match(/\d+/); - console.log("Current row = " + index + ', class = ' + class); - var trold = $(this).closest('tr'); - var tr = $(trold).removeClass('supersizeme'); - var newtr = $(tr).clone(); var newIndex = parseInt(index) + 1; + var newtr = $(div).closest('tr').clone(); SN_EXTENDED.replaceIndex(newtr, index, newIndex); + $(newtr).removeClass('supersizeme'); SN_EXTENDED.resetRow(newtr); - $(tr).after(newtr); - SN_EXTENDED.reorder(class); + $(div).closest('tr').after(newtr); + SN_EXTENDED.reorder(cls); }; SN_EXTENDED.removeRow = function() { var div = $(this).closest('div'); var id = $(div).attr('id'); - var class = $(div).attr('class'); + var cls = $(div).attr('class'); - cnt = SN_EXTENDED.rowCount(class); - console.debug("removeRow - cnt = " + cnt); + var cnt = SN_EXTENDED.rowCount(cls); if (cnt > 1) { var target = $(this).closest('tr'); target.remove(); - SN_EXTENDED.reorder(class); + SN_EXTENDED.reorder(cls); } }; -$(document).ready( +$(document).ready(function() { -function() { + $("input#extprofile-manager").autocomplete({ + source: 'finduser', + minLength: 2 }); var multifields = ["phone-item", "experience-item", "education-item", "im-item"]; From 40e1fc82466cf370d05ff7e380e3a99964a851c2 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 15 Mar 2011 21:55:47 -0700 Subject: [PATCH 33/46] Extended profile - prettier date formatting --- .../ExtendedProfile/extendedprofilewidget.php | 50 +++++++++++++++---- 1 file changed, 40 insertions(+), 10 deletions(-) diff --git a/plugins/ExtendedProfile/extendedprofilewidget.php b/plugins/ExtendedProfile/extendedprofilewidget.php index 5a9eb7e4f9..ebf4c0422c 100644 --- a/plugins/ExtendedProfile/extendedprofilewidget.php +++ b/plugins/ExtendedProfile/extendedprofilewidget.php @@ -295,10 +295,22 @@ class ExtendedProfileWidget extends Form $this->out->elementStart('div', 'experience-item'); $this->out->element('div', 'label', _m('Company')); $this->out->element('div', 'field', $field['company']); + $this->out->element('div', 'label', _m('Start')); - $this->out->element('div', array('class' => 'field date'), $field['start']); + $this->out->element( + 'div', + array('class' => 'field date'), + date('j M Y', strtotime($field['start']) + ) + ); $this->out->element('div', 'label', _m('End')); - $this->out->element('div', array('class' => 'field date'), $field['end']); + $this->out->element( + 'div', + array('class' => 'field date'), + date('j M Y', strtotime($field['end']) + ) + ); + if ($field['current']) { $this->out->element( 'div', @@ -331,14 +343,14 @@ class ExtendedProfileWidget extends Form $this->out->input( $id . '-start', null, - isset($field['start']) ? $field['start'] : null + isset($field['start']) ? date('j M Y', strtotime($field['start'])) : null ); $this->out->element('div', 'label', _m('End')); $this->out->input( $id . '-end', null, - isset($field['end']) ? $field['end'] : null + isset($field['end']) ? date('j M Y', strtotime($field['end'])) : null ); $this->out->hidden( $id . '-current', @@ -366,9 +378,19 @@ class ExtendedProfileWidget extends Form $this->out->element('div', 'label', _m('Description')); $this->out->element('div', 'field', $field['description']); $this->out->element('div', 'label', _m('Start')); - $this->out->element('div', array('class' => 'field date'), $field['start']); + $this->out->element( + 'div', + array('class' => 'field date'), + date('j M Y', strtotime($field['start']) + ) + ); $this->out->element('div', 'label', _m('End')); - $this->out->element('div', array('class' => 'field date'), $field['end']); + $this->out->element( + 'div', + array('class' => 'field date'), + date('j M Y', strtotime($field['end']) + ) + ); $this->out->elementEnd('div'); } @@ -409,14 +431,14 @@ class ExtendedProfileWidget extends Form $this->out->input( $id . '-start', null, - isset($field['start']) ? $field['start'] : null + isset($field['start']) ? date('j M Y', strtotime($field['start'])) : null ); $this->out->element('div', 'label', _m('End')); $this->out->input( $id . '-end', null, - isset($field['end']) ? $field['end'] : null + isset($field['end']) ? date('j M Y', strtotime($field['end'])) : null ); $this->showMultiControls(); @@ -464,7 +486,11 @@ class ExtendedProfileWidget extends Form $this->out->text($this->ext->getTextValue($name)); break; case 'date': - $this->out->text($this->ext->getTextValue($name)); + $this->out->element( + 'div', + array('class' => 'field date'), + date('j M Y', strtotime($this->ext->getTextValue($name))) + ); break; case 'person': $this->out->text($this->ext->getTextValue($name)); @@ -513,7 +539,11 @@ class ExtendedProfileWidget extends Form $out->input($id, null, $this->ext->getTextValue($name)); break; case 'date': - $out->input($id, null, $this->ext->getTextValue($name)); + $out->input( + $id, + null, + date('j M Y', strtotime($this->ext->getTextValue($name))) + ); break; case 'person': $out->input($id, null, $this->ext->getTextValue($name)); From b9065d7bc19e55309204e8beb485b9cad496f0da Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 15 Mar 2011 23:02:05 -0700 Subject: [PATCH 34/46] Extended profile - add fancy datepicker widgets --- plugins/ExtendedProfile/js/profiledetail.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/ExtendedProfile/js/profiledetail.js b/plugins/ExtendedProfile/js/profiledetail.js index 9fb935f153..d24b4aabe8 100644 --- a/plugins/ExtendedProfile/js/profiledetail.js +++ b/plugins/ExtendedProfile/js/profiledetail.js @@ -81,6 +81,10 @@ $(document).ready(function() { source: 'finduser', minLength: 2 }); + $.datepicker.formatDate('yy-mm-dd'); + + $("input[name$=-start], input[name$=-end], #extprofile-birthday").datepicker({ dateFormat: 'd M yy' }); + var multifields = ["phone-item", "experience-item", "education-item", "im-item"]; for (f in multifields) { From bda9d43c56c2282583bd3a870219a4bb7a128800 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 15 Mar 2011 23:51:28 -0700 Subject: [PATCH 35/46] Extended profile - add fancy JQuery UI confirm dialog when deleting items --- .../ExtendedProfile/extendedprofilewidget.php | 7 ++++ plugins/ExtendedProfile/js/profiledetail.js | 36 ++++++++++++++----- 2 files changed, 35 insertions(+), 8 deletions(-) diff --git a/plugins/ExtendedProfile/extendedprofilewidget.php b/plugins/ExtendedProfile/extendedprofilewidget.php index ebf4c0422c..5be149a0cb 100644 --- a/plugins/ExtendedProfile/extendedprofilewidget.php +++ b/plugins/ExtendedProfile/extendedprofilewidget.php @@ -77,6 +77,13 @@ class ExtendedProfileWidget extends Form */ public function formData() { + // For JQuery UI modal dialog + $this->out->elementStart( + 'div', + array('id' => 'confirm-dialog', 'title' => 'Confirmation Required') + ); + $this->out->text('Really delete this entry?'); + $this->out->elementEnd('div'); $this->showSections(); } diff --git a/plugins/ExtendedProfile/js/profiledetail.js b/plugins/ExtendedProfile/js/profiledetail.js index d24b4aabe8..fbcefe730d 100644 --- a/plugins/ExtendedProfile/js/profiledetail.js +++ b/plugins/ExtendedProfile/js/profiledetail.js @@ -44,7 +44,7 @@ SN_EXTENDED.replaceIndex = function(elem, oldIndex, newIndex) { } SN_EXTENDED.resetRow = function(elem) { - $(elem).find('input').attr('value', ''); + $(elem).find('input, textarea').attr('value', ''); $(elem).find("select option[value='office']").attr("selected", true); }; @@ -63,27 +63,47 @@ SN_EXTENDED.addRow = function() { }; SN_EXTENDED.removeRow = function() { + var div = $(this).closest('div'); var id = $(div).attr('id'); var cls = $(div).attr('class'); - var cnt = SN_EXTENDED.rowCount(cls); + + var that = this; + + $("#confirm-dialog").dialog({ + buttons : { + "Confirm" : function() { + var target = $(that).closest('tr'); + target.fadeOut("slow", function() { + $(that).remove(); + }); + SN_EXTENDED.reorder(cls); + $(this).dialog("close"); + }, + "Cancel" : function() { + $(this).dialog("close"); + } + } + }); + if (cnt > 1) { - var target = $(this).closest('tr'); - target.remove(); - SN_EXTENDED.reorder(cls); + $("#confirm-dialog").dialog("open"); } }; $(document).ready(function() { + $("#confirm-dialog").dialog({ + autoOpen: false, + modal: true + }); + $("input#extprofile-manager").autocomplete({ source: 'finduser', minLength: 2 }); - $.datepicker.formatDate('yy-mm-dd'); - - $("input[name$=-start], input[name$=-end], #extprofile-birthday").datepicker({ dateFormat: 'd M yy' }); + $("input[name$=-start], input[name$=-end], #extprofile-birthday").datepicker({ dateFormat: 'd M yy' }); var multifields = ["phone-item", "experience-item", "education-item", "im-item"]; From d51625ab3ddc26a8819c3eb0e1682b4767ca057f Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 15 Mar 2011 23:58:45 -0700 Subject: [PATCH 36/46] Extended profile - hide add button when not needed (regression) --- plugins/ExtendedProfile/js/profiledetail.js | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/ExtendedProfile/js/profiledetail.js b/plugins/ExtendedProfile/js/profiledetail.js index fbcefe730d..7960cee83f 100644 --- a/plugins/ExtendedProfile/js/profiledetail.js +++ b/plugins/ExtendedProfile/js/profiledetail.js @@ -5,6 +5,7 @@ SN_EXTENDED.reorder = function(cls) { var divs = $('div[class=' + cls + ']'); $(divs).each(function(i, div) { + $(div).find('a.add_row').hide(); $(div).find('a.remove_row').show(); SN_EXTENDED.replaceIndex(SN_EXTENDED.rowIndex(div), i); }); From 665dd1de78785e6a9176c5533f5a29bbc33166d5 Mon Sep 17 00:00:00 2001 From: Samantha Doherty Date: Wed, 16 Mar 2011 03:09:06 -0400 Subject: [PATCH 37/46] Remove supersizeme class as appropriate. --- plugins/ExtendedProfile/js/profiledetail.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/plugins/ExtendedProfile/js/profiledetail.js b/plugins/ExtendedProfile/js/profiledetail.js index 7960cee83f..24191d4ad9 100644 --- a/plugins/ExtendedProfile/js/profiledetail.js +++ b/plugins/ExtendedProfile/js/profiledetail.js @@ -55,9 +55,8 @@ SN_EXTENDED.addRow = function() { var cls = div.attr('class'); var index = id.match(/\d+/); var newIndex = parseInt(index) + 1; - var newtr = $(div).closest('tr').clone(); + var newtr = $(div).closest('tr').removeClass('supersizeme').clone(); SN_EXTENDED.replaceIndex(newtr, index, newIndex); - $(newtr).removeClass('supersizeme'); SN_EXTENDED.resetRow(newtr); $(div).closest('tr').after(newtr); SN_EXTENDED.reorder(cls); From a715b133ffcda328f4dbc67e9490ccedfe4c0f77 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 16 Mar 2011 00:23:34 -0700 Subject: [PATCH 38/46] Extended profile - fix regression whereby if there was only one item, you could still delete it! --- plugins/ExtendedProfile/js/profiledetail.js | 10 +++++----- .../ExtendedProfile/profiledetailsettingsaction.php | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/plugins/ExtendedProfile/js/profiledetail.js b/plugins/ExtendedProfile/js/profiledetail.js index 7960cee83f..f475046385 100644 --- a/plugins/ExtendedProfile/js/profiledetail.js +++ b/plugins/ExtendedProfile/js/profiledetail.js @@ -68,19 +68,17 @@ SN_EXTENDED.removeRow = function() { var div = $(this).closest('div'); var id = $(div).attr('id'); var cls = $(div).attr('class'); - var cnt = SN_EXTENDED.rowCount(cls); - var that = this; $("#confirm-dialog").dialog({ buttons : { "Confirm" : function() { + $(this).dialog("close"); var target = $(that).closest('tr'); target.fadeOut("slow", function() { - $(that).remove(); + $(target).remove(); + SN_EXTENDED.reorder(cls); }); - SN_EXTENDED.reorder(cls); - $(this).dialog("close"); }, "Cancel" : function() { $(this).dialog("close"); @@ -88,6 +86,8 @@ SN_EXTENDED.removeRow = function() { } }); + var cnt = SN_EXTENDED.rowCount(cls); + if (cnt > 1) { $("#confirm-dialog").dialog("open"); } diff --git a/plugins/ExtendedProfile/profiledetailsettingsaction.php b/plugins/ExtendedProfile/profiledetailsettingsaction.php index b0590f7316..01a8fa9c7b 100644 --- a/plugins/ExtendedProfile/profiledetailsettingsaction.php +++ b/plugins/ExtendedProfile/profiledetailsettingsaction.php @@ -60,7 +60,7 @@ class ProfileDetailSettingsAction extends ProfileSettingsAction // CSRF protection $token = $this->trimmed('token'); if (!$token || $token != common_session_token()) { - $this->show_form( + $this->showForm( _m( 'There was a problem with your session token. ' . 'Try again, please.' From b80b9f31fc3c2941c38d1977a554ff777c7e3399 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 16 Mar 2011 00:25:02 -0700 Subject: [PATCH 39/46] Small smattering of pixie dust --- plugins/ExtendedProfile/js/profiledetail.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/ExtendedProfile/js/profiledetail.js b/plugins/ExtendedProfile/js/profiledetail.js index ecc89f8151..c96732b835 100644 --- a/plugins/ExtendedProfile/js/profiledetail.js +++ b/plugins/ExtendedProfile/js/profiledetail.js @@ -16,7 +16,7 @@ SN_EXTENDED.reorder = function(cls) { $(divs).last().find('a.add_row').show(); if (divs.length == 1) { - $(divs).find('a.remove_row').hide(); + $(divs).find('a.remove_row').fadeOut("slow"); } }; From 724dba668af45690a9122f49e24d89f8c3e6ede7 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 16 Mar 2011 00:34:00 -0700 Subject: [PATCH 40/46] Extended profile - allow adding more than one website --- plugins/ExtendedProfile/extendedprofilewidget.php | 2 +- plugins/ExtendedProfile/js/profiledetail.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/ExtendedProfile/extendedprofilewidget.php b/plugins/ExtendedProfile/extendedprofilewidget.php index 5be149a0cb..25a0ab8b20 100644 --- a/plugins/ExtendedProfile/extendedprofilewidget.php +++ b/plugins/ExtendedProfile/extendedprofilewidget.php @@ -267,7 +267,7 @@ class ExtendedProfileWidget extends Form $this->out->elementStart( 'div', array( 'id' => $id . '-edit', - 'class' => 'website-edit' + 'class' => 'website-item' ) ); $this->out->input( diff --git a/plugins/ExtendedProfile/js/profiledetail.js b/plugins/ExtendedProfile/js/profiledetail.js index c96732b835..e1b06562e0 100644 --- a/plugins/ExtendedProfile/js/profiledetail.js +++ b/plugins/ExtendedProfile/js/profiledetail.js @@ -105,7 +105,7 @@ $(document).ready(function() { $("input[name$=-start], input[name$=-end], #extprofile-birthday").datepicker({ dateFormat: 'd M yy' }); - var multifields = ["phone-item", "experience-item", "education-item", "im-item"]; + var multifields = ["phone-item", "experience-item", "education-item", "im-item", 'website-item']; for (f in multifields) { SN_EXTENDED.reorder(multifields[f]); From 974d0c48f6234a99b0d28f6c54033434cace877c Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 16 Mar 2011 00:50:43 -0700 Subject: [PATCH 41/46] Extended profile - don't check end date if experience entry has current checked --- plugins/ExtendedProfile/profiledetailsettingsaction.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/ExtendedProfile/profiledetailsettingsaction.php b/plugins/ExtendedProfile/profiledetailsettingsaction.php index 01a8fa9c7b..13bf43b927 100644 --- a/plugins/ExtendedProfile/profiledetailsettingsaction.php +++ b/plugins/ExtendedProfile/profiledetailsettingsaction.php @@ -288,7 +288,7 @@ class ProfileDetailSettingsAction extends ProfileSettingsAction $expArray[] = array( 'company' => $company, 'start' => $this->parseDate('Start', $start, true), - 'end' => $this->parseDate('End', $end, true), + 'end' => ($current == 'false') ? $this->parseDate('End', $end, true) : null, 'current' => ($current == 'false') ? false : true ); } From bb087a965009fd93a5c02a9e10ab90adcc6b7963 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 16 Mar 2011 01:09:38 -0700 Subject: [PATCH 42/46] Extended profile - fix some issues saving and displaying dates --- plugins/ExtendedProfile/extendedprofile.php | 9 +++++++++ plugins/ExtendedProfile/extendedprofilewidget.php | 15 +++++++++------ .../profiledetailsettingsaction.php | 6 +++++- 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/plugins/ExtendedProfile/extendedprofile.php b/plugins/ExtendedProfile/extendedprofile.php index 673680f027..fa632e5073 100644 --- a/plugins/ExtendedProfile/extendedprofile.php +++ b/plugins/ExtendedProfile/extendedprofile.php @@ -98,6 +98,15 @@ class ExtendedProfile } } + function getDateValue($name) { + $key = strtolower($name); + if (array_key_exists($key, $this->fields)) { + return $this->fields[$key][0]->date; + } else { + return null; + } + } + // XXX: getPhones, getIms, and getWebsites pretty much do the same thing, // so refactor. function getPhones() diff --git a/plugins/ExtendedProfile/extendedprofilewidget.php b/plugins/ExtendedProfile/extendedprofilewidget.php index 25a0ab8b20..622beff32f 100644 --- a/plugins/ExtendedProfile/extendedprofilewidget.php +++ b/plugins/ExtendedProfile/extendedprofilewidget.php @@ -493,11 +493,14 @@ class ExtendedProfileWidget extends Form $this->out->text($this->ext->getTextValue($name)); break; case 'date': - $this->out->element( - 'div', - array('class' => 'field date'), - date('j M Y', strtotime($this->ext->getTextValue($name))) - ); + $value = $this->ext->getDateValue($name); + if (!empty($value)) { + $this->out->element( + 'div', + array('class' => 'field date'), + date('j M Y', strtotime($value)) + ); + } break; case 'person': $this->out->text($this->ext->getTextValue($name)); @@ -549,7 +552,7 @@ class ExtendedProfileWidget extends Form $out->input( $id, null, - date('j M Y', strtotime($this->ext->getTextValue($name))) + date('j M Y', strtotime($this->ext->getDateValue($name))) ); break; case 'person': diff --git a/plugins/ExtendedProfile/profiledetailsettingsaction.php b/plugins/ExtendedProfile/profiledetailsettingsaction.php index 13bf43b927..719717e088 100644 --- a/plugins/ExtendedProfile/profiledetailsettingsaction.php +++ b/plugins/ExtendedProfile/profiledetailsettingsaction.php @@ -113,10 +113,14 @@ class ProfileDetailSettingsAction extends ProfileSettingsAction foreach ($dateFieldNames as $name) { $value = $this->trimmed('extprofile-' . $name); + $dateVal = $this->parseDate($name, $value); $this->saveField( $user, $name, - $this->parseDate($name, $value) + null, + null, + null, + $dateVal ); } From 17afe068059f426db04c4b2bf85d31bf4e03953a Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 16 Mar 2011 01:23:47 -0700 Subject: [PATCH 43/46] Extended profile - linkify related URLs added by the user --- .../ExtendedProfile/extendedprofilewidget.php | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/plugins/ExtendedProfile/extendedprofilewidget.php b/plugins/ExtendedProfile/extendedprofilewidget.php index 622beff32f..d4a3f21a52 100644 --- a/plugins/ExtendedProfile/extendedprofilewidget.php +++ b/plugins/ExtendedProfile/extendedprofilewidget.php @@ -79,7 +79,7 @@ class ExtendedProfileWidget extends Form { // For JQuery UI modal dialog $this->out->elementStart( - 'div', + 'div', array('id' => 'confirm-dialog', 'title' => 'Confirmation Required') ); $this->out->text('Really delete this entry?'); @@ -180,7 +180,19 @@ class ExtendedProfileWidget extends Form protected function showWebsite($name, $field) { $this->out->elementStart('div', array('class' => 'website-display')); - $this->out->text($field['value']); + + $url = $field['value']; + + $this->out->element( + "a", + array( + 'href' => $url, + 'class' => 'extended-profile-link', + 'target' => "_blank" + ), + $url + ); + if (!empty($field['rel'])) { $this->out->text(' (' . $field['rel'] . ')'); } From 82023d388a5a060b2b10964bf0cace27fa0a1ae5 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 16 Mar 2011 01:26:53 -0700 Subject: [PATCH 44/46] Extended profile - don't show empty company entry in view --- .../ExtendedProfile/extendedprofilewidget.php | 39 ++++++++++--------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/plugins/ExtendedProfile/extendedprofilewidget.php b/plugins/ExtendedProfile/extendedprofilewidget.php index d4a3f21a52..fb519cfffc 100644 --- a/plugins/ExtendedProfile/extendedprofilewidget.php +++ b/plugins/ExtendedProfile/extendedprofilewidget.php @@ -313,29 +313,32 @@ class ExtendedProfileWidget extends Form { $this->out->elementStart('div', 'experience-item'); $this->out->element('div', 'label', _m('Company')); - $this->out->element('div', 'field', $field['company']); - $this->out->element('div', 'label', _m('Start')); - $this->out->element( - 'div', - array('class' => 'field date'), - date('j M Y', strtotime($field['start']) - ) - ); - $this->out->element('div', 'label', _m('End')); - $this->out->element( - 'div', - array('class' => 'field date'), - date('j M Y', strtotime($field['end']) - ) - ); + if (!empty($field['company'])) { + $this->out->element('div', 'field', $field['company']); - if ($field['current']) { + $this->out->element('div', 'label', _m('Start')); $this->out->element( 'div', - array('class' => 'field current'), - '(' . _m('Current') . ')' + array('class' => 'field date'), + date('j M Y', strtotime($field['start']) + ) ); + $this->out->element('div', 'label', _m('End')); + $this->out->element( + 'div', + array('class' => 'field date'), + date('j M Y', strtotime($field['end']) + ) + ); + + if ($field['current']) { + $this->out->element( + 'div', + array('class' => 'field current'), + '(' . _m('Current') . ')' + ); + } } $this->out->elementEnd('div'); } From 365b7ab56ea70f6fa70ab46358cd794c7892683b Mon Sep 17 00:00:00 2001 From: Samantha Doherty Date: Wed, 16 Mar 2011 04:32:33 -0400 Subject: [PATCH 45/46] More style for profile edit. --- plugins/ExtendedProfile/css/profiledetail.css | 28 +++++++++++++++++-- .../ExtendedProfile/extendedprofilewidget.php | 2 +- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/plugins/ExtendedProfile/css/profiledetail.css b/plugins/ExtendedProfile/css/profiledetail.css index e0650d40a1..3af9bcba4a 100644 --- a/plugins/ExtendedProfile/css/profiledetail.css +++ b/plugins/ExtendedProfile/css/profiledetail.css @@ -69,6 +69,22 @@ display: none; } +.extended-profile textarea { + width: 280px; +} + +.extended-profile input[type=text] { + width: 280px; +} + +.extended-profile .phone-item input[type=text], .extended-profile .im-item input[type=text], .extended-profile .website-item input[type=text] { + width: 175px; +} + +.extended-profile input.hasDatepicker { + width: 100px; +} + .experience-item input[type=text], .education-item input[type=text] { float: left; } @@ -101,7 +117,6 @@ display: block; height: 16px; width: 16px; - line-height: 4em; overflow: hidden; background-image: url('../../../theme/rebase/images/icons/icons-01.gif'); background-repeat: no-repeat; @@ -112,14 +127,18 @@ float: right; position: relative; top: 6px; + line-height: 4em; } .extended-profile a.add_row { clear: both; position: relative; top: 6px; - left: 2px; + left: 2px; background-position: 0px -1186px; + width: 120px; + padding-left: 20px; + line-height: 1.2em; } #content table.extended-profile .supersizeme th { @@ -131,6 +150,11 @@ width: 100%; } +#profiledetailsettings .education-item textarea { + float: left; + margin-bottom: 8px; +} + #profiledetailsettings tr:last-child .experience-item, #profiledetailsettings tr:last-child .education-item { margin-bottom: 0px; } diff --git a/plugins/ExtendedProfile/extendedprofilewidget.php b/plugins/ExtendedProfile/extendedprofilewidget.php index fb519cfffc..7f62d3eae4 100644 --- a/plugins/ExtendedProfile/extendedprofilewidget.php +++ b/plugins/ExtendedProfile/extendedprofilewidget.php @@ -486,7 +486,7 @@ class ExtendedProfileWidget extends Form 'href' => 'javascript://', 'style' => 'display: none;' ), - '+' + 'Add another item' ); } From 368cfd8facac4e69a00b1d6c0e7eb43299e61cf4 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 16 Mar 2011 02:41:32 -0700 Subject: [PATCH 46/46] * Extended profile - make cloned datefields work correctly with calendar popup * Validate URLs --- .../ExtendedProfile/extendedprofilewidget.php | 1 + plugins/ExtendedProfile/js/profiledetail.js | 23 +++++++++++++++++++ .../profiledetailsettingsaction.php | 15 +++++++++++- 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/plugins/ExtendedProfile/extendedprofilewidget.php b/plugins/ExtendedProfile/extendedprofilewidget.php index 7f62d3eae4..1ef6440ed6 100644 --- a/plugins/ExtendedProfile/extendedprofilewidget.php +++ b/plugins/ExtendedProfile/extendedprofilewidget.php @@ -369,6 +369,7 @@ class ExtendedProfileWidget extends Form ); $this->out->element('div', 'label', _m('End')); + $this->out->input( $id . '-end', null, diff --git a/plugins/ExtendedProfile/js/profiledetail.js b/plugins/ExtendedProfile/js/profiledetail.js index e1b06562e0..99a3f78a43 100644 --- a/plugins/ExtendedProfile/js/profiledetail.js +++ b/plugins/ExtendedProfile/js/profiledetail.js @@ -46,7 +46,13 @@ SN_EXTENDED.replaceIndex = function(elem, oldIndex, newIndex) { SN_EXTENDED.resetRow = function(elem) { $(elem).find('input, textarea').attr('value', ''); + $(elem).find('input').removeAttr('disabled'); $(elem).find("select option[value='office']").attr("selected", true); + $(elem).find("input:checkbox").attr('checked', false); + $(elem).find("input[name$=-start], input[name$=-end]").each(function() { + $(this).removeClass('hasDatepicker'); + $(this).datepicker({ dateFormat: 'd M yy' }); + }); }; SN_EXTENDED.addRow = function() { @@ -118,4 +124,21 @@ $(document).ready(function() { $('.add_row').live('click', SN_EXTENDED.addRow); $('.remove_row').live('click', SN_EXTENDED.removeRow); + $('input:checkbox[name$=current]').each(function() { + var input = $(this).parent().siblings('input[id$=-end]'); + if ($(this).is(':checked')) { + $(input).attr('disabled', 'true'); + } + }); + + $('input:checkbox[name$=current]').live('click', function() { + var input = $(this).parent().siblings('input[id$=-end]'); + if ($(this).is(':checked')) { + $(input).val(''); + $(input).attr('disabled', 'true'); + } else { + $(input).removeAttr('disabled'); + } + }); + }); diff --git a/plugins/ExtendedProfile/profiledetailsettingsaction.php b/plugins/ExtendedProfile/profiledetailsettingsaction.php index 719717e088..7b03f247ed 100644 --- a/plugins/ExtendedProfile/profiledetailsettingsaction.php +++ b/plugins/ExtendedProfile/profiledetailsettingsaction.php @@ -262,6 +262,14 @@ class ProfileDetailSettingsAction extends ProfileSettingsAction $this->removeAll($user, 'website'); $i = 0; foreach($sites as $site) { + + if (!Validate::uri( + $site['value'], + array('allowed_schemes' => array('http', 'https'))) + ) { + throw new Exception(sprintf(_m('Invalid URL: %s'), $site['value'])); + } + if (!empty($site['value'])) { ++$i; $this->saveField( @@ -287,7 +295,12 @@ class ProfileDetailSettingsAction extends ProfileSettingsAction $expArray = array(); foreach ($experiences as $exp) { - list($company, $current, $end, $start) = array_values($exp); + if (sizeof($experiences) == 4) { + list($company, $current, $end, $start) = array_values($exp); + } else { + $end = null; + list($company, $current, $start) = array_values($exp); + } if (!empty($company)) { $expArray[] = array( 'company' => $company,