diff --git a/VERSIONS_WIP/dev_#12996 b/VERSIONS_WIP/dev_#12996 new file mode 100644 index 0000000000000000000000000000000000000000..b05680f33faaa328cdfb375fdfe3c72b71421ec4 --- /dev/null +++ b/VERSIONS_WIP/dev_#12996 @@ -0,0 +1 @@ +* Champs personnalisés : ajout d'un nouveau champ 'texte riche/html' \ No newline at end of file diff --git a/library/Class/CustomField/Meta.php b/library/Class/CustomField/Meta.php index 23da3ad537d4f842627f5492dd2b69293e2ce76d..b48671899da8b24a1c2c066569882d684b802639 100644 --- a/library/Class/CustomField/Meta.php +++ b/library/Class/CustomField/Meta.php @@ -16,23 +16,24 @@ * * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE * along with AFI-OPAC 2.0; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ class Class_CustomField_Meta extends Storm_Model_Abstract { use Trait_Translator; - const + const TEXT_INPUT = 'text', TEXT_AREA = 'textarea', + CKEDITOR = 'ckeditor', SELECT = 'select'; protected static $_models = []; - protected + protected $_table_name = 'custom_field_meta', - $_has_many = ['custom_fields' => + $_has_many = ['custom_fields' => ['model' => 'Class_CustomField', 'role' => 'meta', 'dependents' => 'delete']], @@ -40,11 +41,18 @@ class Class_CustomField_Meta extends Storm_Model_Abstract { 'field_type' => self::TEXT_INPUT, 'options_list' => '']; - public function getLibelle() { return $this->getLabel(); } + public function getFieldTypes() { + return + [Class_CustomField_Meta::TEXT_INPUT => $this->_('Texte'), + Class_CustomField_Meta::TEXT_AREA => $this->_('Zone de texte simple'), + Class_CustomField_Meta::CKEDITOR => $this->_('Zone de texte HTML'), + Class_CustomField_Meta::SELECT => $this->_("Liste d'options")]; + } + public function getOptionsListAsArray() { $options = explode(';',$this->getOptionsList()); @@ -54,11 +62,7 @@ class Class_CustomField_Meta extends Storm_Model_Abstract { public function getFieldTypeLabel() { - $field_type_array = - [Class_CustomField_Meta::TEXT_INPUT => $this->_('Champ texte'), - Class_CustomField_Meta::TEXT_AREA => $this->_('Champ zone de texte'), - Class_CustomField_Meta::SELECT => $this->_("Liste d'options")]; - return $field_type_array[$this->getFieldType()]; + return $this->getFieldTypes()[$this->getFieldType()]; } } ?> \ No newline at end of file diff --git a/library/ZendAfi/Controller/Action.php b/library/ZendAfi/Controller/Action.php index 0086773c0b3004e24fd6f7ad061e0ae5af0a73ea..caf443014572f33074cdc345f8b386354a6719f0 100644 --- a/library/ZendAfi/Controller/Action.php +++ b/library/ZendAfi/Controller/Action.php @@ -209,6 +209,7 @@ class ZendAfi_Controller_Action extends Zend_Controller_Action { protected function _setupFormAndSave($model) { $form = $this->_getForm($model); + $this->view->form = $form; if ($this->_request->isPost()) { // for multicheckboxes, if none is checked nothing is posted, default to empty @@ -218,13 +219,14 @@ class ZendAfi_Controller_Action extends Zend_Controller_Action { $post = array_merge($defaults, $this->_getPost()); $custom_values = []; + foreach ($post as $k=>$v) if (preg_match('/field_[0-9]+/', $k)) { $custom_values[$k] = $v; unset($post[$k]); } $model->updateAttributes($post); - if ((!$form->isValid($model))) + if ((!$form->isValidModelAndArray($model,$this->_getPost()))) return false; if (!$model->save()) return false; @@ -273,9 +275,15 @@ class ZendAfi_Controller_Action extends Zend_Controller_Action { protected function _getFormWith($model, $custom_form) { $formClass = $this->_definitions->getFormClassName(); + foreach ($custom_form->getElements() as $element) { + if (!$value=$this->_request->getParam($element->getName())) + continue; + $element->setValue($value); + } + $form = $formClass::newWith( - array_merge($this->_getFormValues($model), $this->_request->getParams()), - $custom_form + array_merge($this->_getFormValues($model), $this->_request->getParams()), + $custom_form ); $form->setAction($this->view->url()); return $form; diff --git a/library/ZendAfi/Form.php b/library/ZendAfi/Form.php index 09f8ceb00e1df3608b59b6f48d53fc4cc7c29697..66f4ff19770d86fa27808ba277716b54e54d5ba6 100644 --- a/library/ZendAfi/Form.php +++ b/library/ZendAfi/Form.php @@ -32,6 +32,7 @@ class ZendAfi_Form extends Zend_Form { public static function newWith($datas = [], $custom_form = null) { + return (new static()) ->populate($datas) ->setCustomForm($custom_form); @@ -115,6 +116,13 @@ class ZendAfi_Form extends Zend_Form { return $valid; } + public function isValidModelAndArray($model, $array) { + $valid = parent::isValid($array) && $model->isValid(); + $this->addModelErrors($model); + + $this->_errorsExist = !$valid; + return $valid; + } /** * @param Storm_Model_Abstrict $model @@ -129,6 +137,7 @@ class ZendAfi_Form extends Zend_Form { public function populateFormFromGroupsDefinitions($groups_definitions) { + foreach($groups_definitions as $name => $definition) $this ->addElementsFromDefinition($definition['elements']) diff --git a/library/ZendAfi/Form/Admin/CustomFields.php b/library/ZendAfi/Form/Admin/CustomFields.php index 681ba733e9d7359c25ce8f933ad2a8f30527ce3d..fd73f570be1b474b6b7aaa887381f2fd8d1035e5 100644 --- a/library/ZendAfi/Form/Admin/CustomFields.php +++ b/library/ZendAfi/Form/Admin/CustomFields.php @@ -16,12 +16,12 @@ * * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE * along with AFI-OPAC 2.0; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ class ZendAfi_Form_Admin_CustomFields extends ZendAfi_Form { - + public function init() { parent::init(); $this->_toggleOptionsList(); @@ -35,10 +35,10 @@ class ZendAfi_Form_Admin_CustomFields extends ZendAfi_Form { 'size' => 50, 'required' => true, 'allowEmpty' => false]) - ->addElement('select', + ->addElement('select', 'field_type', ['label' => $this->_('Type de champ'), - 'multioptions' => $this->_getFieldTypes(), + 'multioptions' => (new Class_CustomField_Meta())->getFieldTypes(), 'required' => true, 'allowEmpty' => false]) ->addElement('text', @@ -49,17 +49,17 @@ class ZendAfi_Form_Admin_CustomFields extends ZendAfi_Form { } - protected function _getFieldTypes() { - return [Class_CustomField_Meta::TEXT_INPUT => $this->_('champ texte'), - Class_CustomField_Meta::TEXT_AREA => $this->_('champ zone de texte'), - Class_CustomField_Meta::SELECT => $this->_("liste d'options")]; - } - + protected function _toggleOptionsList() { return Class_ScriptLoader::getInstance() ->addJQueryBackEnd('formSelectToggleVisibilityForElement("#field_type", "#fieldset-options", "'.Class_CustomField_Meta::SELECT.'");'); } + public function getFieldTypeLabel($fieldType) { + return (new Class_CustomField_Meta())->getFieldTypes()[$fieldType]; + + } + } ?> \ No newline at end of file diff --git a/library/ZendAfi/Form/Admin/CustomFields/CustomFieldMeta.php b/library/ZendAfi/Form/Admin/CustomFields/CustomFieldMeta.php index 1aab8c753dd4405c3eeaadc82d496c0c67a448cf..e6014f14e6412e741f16b3426873cf9cbd1925c8 100644 --- a/library/ZendAfi/Form/Admin/CustomFields/CustomFieldMeta.php +++ b/library/ZendAfi/Form/Admin/CustomFields/CustomFieldMeta.php @@ -16,12 +16,12 @@ * * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE * along with AFI-OPAC 2.0; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ class ZendAfi_Form_Admin_CustomFields_CustomFieldMeta extends ZendAfi_Form_Admin_CustomFields { - public static function newWith($custom_field_meta_array) { + public static function newWith($custom_field_meta_array=[], $custom_form=null) { $form = new self(); $form ->populate($custom_field_meta_array) diff --git a/library/ZendAfi/Form/Admin/CustomFields/CustomFieldModel.php b/library/ZendAfi/Form/Admin/CustomFields/CustomFieldModel.php index dcb6672820c69f1d3eafefa46a5f9b4e80d86cf0..40899b26eca702e65723b24734b675557ec34956 100644 --- a/library/ZendAfi/Form/Admin/CustomFields/CustomFieldModel.php +++ b/library/ZendAfi/Form/Admin/CustomFields/CustomFieldModel.php @@ -16,13 +16,13 @@ * * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE * along with AFI-OPAC 2.0; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ class ZendAfi_Form_Admin_CustomFields_CustomFieldModel extends ZendAfi_Form_Admin_CustomFields { - public static function newWith($custom_field_array) { + public static function newWith($custom_field_array=[], $custom_form=null) { $form = new self(); $form ->addElement('hidden', 'model') diff --git a/library/ZendAfi/Form/Admin/CustomFields/ModelValues.php b/library/ZendAfi/Form/Admin/CustomFields/ModelValues.php index 73e6b7eb4d76414c4c33ff0bc8072e88c3250063..1702c9d26172c03502ee5e53b69aafee3c5ab834 100644 --- a/library/ZendAfi/Form/Admin/CustomFields/ModelValues.php +++ b/library/ZendAfi/Form/Admin/CustomFields/ModelValues.php @@ -16,19 +16,19 @@ * * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE * along with AFI-OPAC 2.0; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ class ZendAfi_Form_Admin_CustomFields_ModelValues extends ZendAfi_Form { const FIELD_PREFIX = 'field_'; - protected + protected $_model_values; public function setModel_Values($model_values) { $this->_model_values = $model_values; - $this->setAttrib('data-backurl', + $this->setAttrib('data-backurl', Class_Url::assemble($this->_model_values->getEditURL())); } @@ -76,13 +76,13 @@ class ZendAfi_Form_Admin_CustomFields_ModelValues_Field_Strategy { public function addElement($field, $label, $value) { $this->_field = $field; - $this->_form->addElement($field->getFieldType(), - $label, + $this->_form->addElement($field->getFieldType(), + $label, array_merge(['label' => $field->getLabel(), - 'value' => $value], + 'value' => $value], $this->getOptions())); } - + protected function getOptions() { return []; @@ -106,6 +106,13 @@ class ZendAfi_Form_Admin_CustomFields_ModelValues_Field_Strategy_textarea extend } +class ZendAfi_Form_Admin_CustomFields_ModelValues_Field_Strategy_ckeditor extends ZendAfi_Form_Admin_CustomFields_ModelValues_Field_Strategy { + protected function getOptions() { + return ['cols' => 35, 'rows' => 10]; + } +} + + class ZendAfi_Form_Admin_CustomFields_ModelValues_Field_Strategy_select extends ZendAfi_Form_Admin_CustomFields_ModelValues_Field_Strategy { protected function getOptions() { diff --git a/tests/application/modules/admin/controllers/CmsControllerTest.php b/tests/application/modules/admin/controllers/CmsControllerTest.php index 66676a7502120b55192463fb587d49c8c1d99811..d2e15f8e9a292db4c85687249fb25642d185fde6 100644 --- a/tests/application/modules/admin/controllers/CmsControllerTest.php +++ b/tests/application/modules/admin/controllers/CmsControllerTest.php @@ -983,6 +983,10 @@ class CmsControllerArticleConcertEditActionPostRenderPopupTest extends CmsContro 'id_cat' => 34, 'contenu' => 'Ici: <img src="../../images/bonlieu.jpg" />', 'description' => '', + 'debut' => '', + 'fin' => '', + 'events_debut' => '', + 'events_fin' => '', 'id_items' => ['1']]; $_SERVER['HTTP_REFERER'] = 'opac/index'; @@ -1030,6 +1034,10 @@ class CmsControllerArticleConcertEditActionPostWithWrongDataRenderPopupTest exte $this->_data = ['titre' => '', 'id_cat' => 34, 'contenu' => 'Ici: <img src="../../images/bonlieu.jpg" />', + 'debut' => '', + 'fin' => '', + 'events_debut' => '', + 'events_fin' => '', 'description' => '', 'id_items' => ['1']]; @@ -1089,7 +1097,8 @@ class CmsControllerArticleConcertEditActionPostWithErrorTest extends CmsControll 'events_debut' => '', 'events_fin' => '01/04/2011', 'description' => '', - 'contenu' => ''); + 'contenu' => '', + 'id_cat' => 23); $this @@ -1120,7 +1129,9 @@ class CmsControllerArticleConcertEditActionPostWithErrorTest extends CmsControll /** @test */ function errorShouldContainsDateDebutError() { - $this->assertXPathContentContains('//ul[@class="errors"]', "La date de début de publication doit être plus récente que la date de fin"); + $this->assertXPathContentContains('//ul[@class="errors"]', + "La date de début de publication doit être plus récente que la date de fin", + $this->_response->getBody()); } @@ -1670,7 +1681,8 @@ class CmsControllerArticleAddActionInvalidDatePostTest extends CmsControllerTest 'events_debut' => '', 'events_fin' => '', 'description' => '', - 'contenu' => ''); + 'contenu' => '', + 'id_cat' => 23); $this ->getRequest() @@ -2133,6 +2145,10 @@ class CmsControllerNewsAddToCatALaUneInNewsModuleActionTest extends CmsControlle $this->postDispatch('/admin/cms/add/id_module/10/id_cat/34', ['titre' => 'Erik Truffaz - Ladyland quartet en concert', + 'debut' => '', + 'fin' => '', + 'events_debut' => '', + 'events_fin' => '', 'auteur' => Class_Users::newInstanceWithId(1, ['login' => 'tom']), 'id_cat' => 34, 'contenu' => 'Ici: <img src="../../images/bonlieu.jpg" />', diff --git a/tests/application/modules/admin/controllers/CustomFieldsControllerTest.php b/tests/application/modules/admin/controllers/CustomFieldsControllerTest.php index ca40439a0e024ac4d5f3aee266f3cbee2a74f85a..9d2e7acd59ab116d56e1a148a2c922b58c53cf2f 100644 --- a/tests/application/modules/admin/controllers/CustomFieldsControllerTest.php +++ b/tests/application/modules/admin/controllers/CustomFieldsControllerTest.php @@ -74,6 +74,13 @@ abstract class CustomFieldControllerTestCase extends AbstractControllerTestCase 'field_type' => Class_CustomField_Meta::TEXT_INPUT, 'model' => 'UserGroup']); + $this->fixture('Class_CustomField', + ['id' => 7, + 'priority' => 5, + 'label' => 'Notes', + 'field_type' => Class_CustomField_Meta::CKEDITOR, + 'model' => 'UserGroup']); + $this->fixture('Class_UserGroup', ['id' => 1, @@ -228,17 +235,11 @@ class CustomFieldsControllerAddIndexTest extends CustomFieldControllerTestCase { } - public function getFieldTypeValues() { - return [ [Class_CustomField_Meta::TEXT_INPUT, 'champ texte'], - [Class_CustomField_Meta::TEXT_AREA, 'champ zone de texte'], - [Class_CustomField_Meta::SELECT, "liste d'options"]]; - } - - /** @test - * @dataProvider getFieldTypeValues - */ - public function fieldTypeValueShouldBeAsExpected($value, $label) { - $this->assertXpathContentContains('//form//select/option[@value="'.$value.'"]', $label); + /** @test */ + public function fieldTypeValueShouldBeAsExpected() { + foreach((new Class_CustomField_Meta())->getFieldTypes() as $value => $label) + $this->assertXpathContentContains('//form//select/option[@value="'.$value.'"]', + $label); } @@ -394,14 +395,14 @@ class CustomFieldsControllerUpDownActionTest extends CustomFieldControllerTestCa public function updownForFieldExpectedOrder() { // at start we have: Address, Age, Status return [ - ['down', 3, ['Age', 'Address', 'Status', 'Zip code']], - ['down', 4, ['Address', 'Status', 'Age', 'Zip code']], - ['down', 6, ['Address', 'Age', 'Status', 'Zip code']], - ['down', 0, ['Address', 'Age', 'Status', 'Zip code']], - - ['up', 0, ['Address', 'Age', 'Status', 'Zip code']], - ['up', 4, ['Age', 'Address', 'Status', 'Zip code']], - ['up', 5, ['Address', 'Status', 'Age', 'Zip code']] + ['down', 3, ['Age', 'Address', 'Status', 'Zip code','Notes']], + ['down', 4, ['Address', 'Status', 'Age', 'Zip code','Notes']], + ['down', 6, ['Address', 'Age', 'Status','Notes' , 'Zip code']], + ['down', 0, ['Address', 'Age', 'Status', 'Zip code','Notes']], + + ['up', 0, ['Address', 'Age', 'Status', 'Zip code','Notes']], + ['up', 4, ['Age', 'Address', 'Status', 'Zip code','Notes']], + ['up', 5, ['Address', 'Status', 'Age', 'Zip code','Notes']] ]; } @@ -521,6 +522,7 @@ class CustomFieldsControllerValuesForUserGroupPostTest extends CustomFieldContro 'field_4' => 12, // age 'field_5' => 0, // status 'field_6' => 74000, //zip code + 'field_7' => 'blabla<br/>', //notes ]); Class_CustomField_Value::clearCache(); @@ -535,7 +537,7 @@ class CustomFieldsControllerValuesForUserGroupPostTest extends CustomFieldContro } - /** @test */ + /** @test */ public function adresseShouldBeMenardeix() { $this->assertEquals('1, menardeix', $this->_getValueOfField(3)); } @@ -552,6 +554,13 @@ class CustomFieldsControllerValuesForUserGroupPostTest extends CustomFieldContro $this->assertEquals(74000, $this->_getValueOfField(6)); } + /** @test */ + public function notesCodeShouldBeCreatedWithValueBlabla() { + $this->assertEquals( + 'blabla<br/>', + Class_CustomField_Value::findFirstBy(['order' => 'id desc'])->getValue()); + } + /** @test */ public function pageShouldNotifySuccessfulSave() { diff --git a/tests/application/modules/admin/controllers/CustomFieldsMetaControllerTest.php b/tests/application/modules/admin/controllers/CustomFieldsMetaControllerTest.php index 1eadc41e0af99c98e9393abf643a4de3d8bb5328..f6cbeb78c152960fff274901eb5cfb05c09eb106 100644 --- a/tests/application/modules/admin/controllers/CustomFieldsMetaControllerTest.php +++ b/tests/application/modules/admin/controllers/CustomFieldsMetaControllerTest.php @@ -16,19 +16,19 @@ * * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE * along with AFI-OPAC 2.0; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ abstract class CustomFieldsMetaControllerTestCase extends AbstractControllerTestCase { public function setUp() { parent::setUp(); - + $this->fixture('Class_CustomField_Meta', [ 'id' => 1, 'label' => 'Address', 'field_type' => Class_CustomField_Meta::TEXT_INPUT, 'options_list' => '']); - + $this->fixture('Class_CustomField_Meta', [ 'id' => 2, 'label' => 'Status', @@ -61,7 +61,7 @@ class CustomFieldsMetaControllerIndexActionTest extends CustomFieldsMetaControll /** @test */ public function fieldTypeForAddressShouldBeChampTexte() { - $this->assertXPathContentContains('//table[@id="custom-fields-meta"]//td', 'Champ texte'); + $this->assertXPathContentContains('//table[@id="custom-fields-meta"]//td', 'Texte'); } @@ -97,13 +97,13 @@ class CustomFieldsMetaControllerEditActionTest extends CustomFieldsMetaControlle $this->dispatch('admin/custom-fields-meta/edit/id/1', true); } - + /** @test */ public function inputLabelShouldContainsAdress() { $this->assertXPath('//input[@name="label"][@value="Address"]'); } - + /** @test */ public function fieldTypeShouldBeText() { $this->assertXPath('//select/option[@value="text"][@selected="selected"]'); @@ -132,7 +132,7 @@ class CustomFieldsMetaControllerPostEditActionTest extends CustomFieldsMetaContr public function setup() { parent::setup(); - $this->postDispatch('admin/custom-fields-meta/edit/id/1', + $this->postDispatch('admin/custom-fields-meta/edit/id/1', ['label' => 'public', 'field_type' => Class_CustomField_Meta::SELECT, 'options_list' => 'teens; parents ; all public ; ']); @@ -144,11 +144,11 @@ class CustomFieldsMetaControllerPostEditActionTest extends CustomFieldsMetaContr $this->assertEquals('public', Class_CustomField_Meta::find(1)->getLabel()); } - + /** @test */ public function fieldTypeShouldBeSelect() { $this->assertEquals( - Class_CustomField_Meta::SELECT, + Class_CustomField_Meta::SELECT, Class_CustomField_Meta::find(1)->getFieldType()); } @@ -156,7 +156,7 @@ class CustomFieldsMetaControllerPostEditActionTest extends CustomFieldsMetaContr /** @test */ public function optionsListShouldBeTeensAndParents() { $this->assertEquals( - ['teens', 'parents', 'all public'], + ['teens', 'parents', 'all public'], Class_CustomField_Meta::find(1)->getOptionsListAsArray()); } } diff --git a/tests/application/modules/admin/controllers/UserGroupControllerTest.php b/tests/application/modules/admin/controllers/UserGroupControllerTest.php index 31288992a4651424982bf84f6638ae15f8d6fb5f..6e2a03a1174699ab59c631cfdc0d29367be4bbfe 100644 --- a/tests/application/modules/admin/controllers/UserGroupControllerTest.php +++ b/tests/application/modules/admin/controllers/UserGroupControllerTest.php @@ -387,8 +387,10 @@ class Admin_UserGroupControllerAddPostTest extends Admin_UserGroupControllerTest class Admin_UserGroupControllerAddPostInvalidDataTest extends Admin_UserGroupControllerTestCase { public function setUp() { parent::setUp(); + $this->beCustomized(); $this->postDispatch('admin/usergroup/add', - ['libelle' => '']); + ['libelle' => '', + 'field_6' => '74000']); $groups = Class_UserGroup::findAll(); $this->last = $groups[(count($groups)-1)]; } @@ -399,6 +401,10 @@ class Admin_UserGroupControllerAddPostInvalidDataTest extends Admin_UserGroupCon $this->assertFalse($this->last->getLibelle===''); } + /** @test */ + public function zipCodeShouldKeepDefaultValue() { + $this->assertXPath('//input[contains(@value,"74000")]',$this->_response->getBody()); + } /** @test */ public function errorsShouldContainsUneValeurEstRequise() { @@ -817,7 +823,6 @@ class Admin_UserGroupControllerEditStagiairesPostDataWithEmptyCustomFieldsTest e - class Admin_UserGroupControllerDeleteGroupWithCustomValuesTest extends Admin_UserGroupControllerTestCase { public function setUp() {