From 3b1bed540f343202fc606961f117fab0d7aafc78 Mon Sep 17 00:00:00 2001 From: coderkun Date: Thu, 31 Jul 2014 11:21:31 +0200 Subject: [PATCH] implement task editing for Questtype ?Textinput? (issue #36) --- locale/de_DE/LC_MESSAGES/The Legend of Z.mo | Bin 23342 -> 23897 bytes locale/de_DE/LC_MESSAGES/The Legend of Z.po | 82 +++++++++--- .../TextinputQuesttypeController.inc | 125 ++++++++++++++++++ .../textinput/TextinputQuesttypeModel.inc | 103 +++++++++++++++ questtypes/textinput/html/edittask.tpl | 105 +++++++++++++++ views/html/html.tpl | 1 + www/js/misc.js | 52 ++++++++ 7 files changed, 449 insertions(+), 19 deletions(-) create mode 100644 questtypes/textinput/html/edittask.tpl create mode 100644 www/js/misc.js diff --git a/locale/de_DE/LC_MESSAGES/The Legend of Z.mo b/locale/de_DE/LC_MESSAGES/The Legend of Z.mo index adab17a1963c85ef226566563ea924161188f91f..5a65b95640830f9c844841e820842001a9371cbb 100644 GIT binary patch delta 8017 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'task', $task); $this->set('fields', $fields); } + + + /** + * Action: edittask. + * + * Edit the task of a Quest. + * + * @param array $seminary Current Seminary data + * @param array $questgroup Current Questgroup data + * @param array $quest Current Quest data + */ + public function edittask($seminary, $questgroup, $quest) + { + // Get Task + $task = $this->Textinput->getTextinputQuest($quest['id']); + $text = $task['text']; + + // Get fields + $fields = $this->Textinput->getTextinputFields($quest['id']); + + // Get field sizes + $fieldSizes = $this->Textinput->getFieldSizes(); + + // Values + $validations = array(); + + // Save data + if($this->request->getRequestMethod() == 'POST') + { + if(!is_null($this->request->getPostParam('preview')) || !is_null($this->request->getPostParam('save'))) + { + // Get params and validate them + if(is_null($this->request->getPostParam('text'))) { + throw new \nre\exceptions\ParamsNotValidException('text'); + } + $text = $this->request->getPostParam('text'); + if(is_null($this->request->getPostParam('fields'))) { + throw new \nre\exceptions\ParamsNotValidException('fields'); + } + $fields = $this->request->getPostParam('fields'); + $fields = array_values($fields); + $fieldIndex = 0; + foreach($fields as &$field) + { + // Validate regex + $regex = $field['regex']; + //$fieldValidation = $this->Validation->validate($regex, \nre\configs\AppConfig::$validation['regex']); + $fieldValidation = @preg_match($regex, '') !== false; + if($fieldValidation !== true) + { + if(!array_key_exists($fieldIndex, $validations) || !is_array($validations[$fieldIndex])) { + $validations[$fieldIndex] = array(); + } + $validations[$fieldIndex] = $this->Validation->addValidationResults($validations[$fieldIndex], 'regex', $fieldValidation); + } + + // Validate size + foreach($fieldSizes as $sizeIndex => &$size) + { + if($size['size'] == $field['size']) + { + $field['sizeIndex'] = $sizeIndex; + break; + } + } + if(!array_key_exists('sizeIndex', $field)) { + throw new \nre\exceptions\ParamsNotValidException($fieldIndex); + } + + $fieldIndex++; + } + + // Save and redirect + if(!is_null($this->request->getPostParam('save')) && empty($validations)) + { + // Save text + $this->Textinput->setTextForQuest( + $this->Auth->getUserId(), + $quest['id'], + $text + ); + + // Save field + foreach($fields as $index => &$field) + { + // Add regex modifiers + $modifiers = substr($field['regex'], strrpos($field['regex'], $field['regex'][0]) + 1); + if(strpos($modifiers, 'u') === false) { + $field['regex'] .= 'u'; + } + + // Save field + $this->Textinput->setFieldForText( + $quest['id'], + $index + 1, + $fieldSizes[$field['sizeIndex']]['id'], + $field['regex'] + ); + } + + // Redirect + $this->redirect($this->linker->link(array('quest', $seminary['url'], $questgroup['url'], $quest['url']), 1)); + } + } + } + + // Set colors for fields + foreach($fields as &$field) { + $field['color'] = str_pad(sprintf('%x%x%x', rand(0,255), rand(0,255), rand(0,255)), 6, 9); + } + + + // Pass data to view + $this->set('task', $task); + $this->set('text', $text); + $this->set('fields', $fields); + $this->set('fieldSizes', $fieldSizes); + $this->set('validations', $validations); + } diff --git a/questtypes/textinput/TextinputQuesttypeModel.inc b/questtypes/textinput/TextinputQuesttypeModel.inc index 0960fb3f..daf0edde 100644 --- a/questtypes/textinput/TextinputQuesttypeModel.inc +++ b/questtypes/textinput/TextinputQuesttypeModel.inc @@ -112,6 +112,109 @@ return ''; } + + + /** + * Set the text for a Quest and correct fields count. + * + * @param int $userId ID of user setting text + * @param int $questId ID of Quest to set text for + * @param string $text Text for Quset + */ + public function setTextForQuest($userId, $questId, $text) + { + $this->db->setAutocommit(false); + try { + // Set text + $this->db->query( + 'INSERT INTO questtypes_textinput '. + '(quest_id, created_user_id, text) '. + 'VALUES '. + '(?, ?, ?) '. + 'ON DUPLICATE KEY UPDATE '. + 'text = ?', + 'iiss', + $questId, + $userId, + $text, + $text + ); + + // Count fields + $fieldCount = substr_count($text, '[textinput]'); + + // Remove fields + $this->db->query( + 'DELETE FROM questtypes_textinput_fields '. + 'WHERE questtypes_textinput_quest_id = ? AND number > ?', + 'ii', + $questId, + $fieldCount + ); + + // Add fields + for($i=1; $i<=$fieldCount; $i++) + { + $this->db->query( + 'INSERT IGNORE INTO questtypes_textinput_fields '. + '(questtypes_textinput_quest_id, number, regex) '. + 'VALUES '. + '(?, ?, ?) ', + 'iis', + $questId, + $i, + '' + ); + } + + $this->db->commit(); + } + catch(\Exception $e) { + $this->db->rollback(); + $this->db->setAutocommit(true); + throw $e; + } + + $this->db->setAutocommit(true); + } + + + /** + * Set values for a field of a text. + * + * @param int $questId ID of Quest to set field for + * @param int $number Field number + * @param int $sizeId ID of field size + * @param string $regex RegEx for field + */ + public function setFieldForText($questId, $number, $sizeId, $regex) + { + $this->db->query( + 'UPDATE questtypes_textinput_fields '. + 'SET questtypes_textinput_fieldsize_id = ?, regex = ? '. + 'WHERE questtypes_textinput_quest_id = ? AND number = ?', + 'isii', + $sizeId, + $regex, + $questId, + $number + ); + } + + + /** + * Get all registered field sizes. + * + * @return List of field sizes + */ + public function getFieldSizes() + { + return $this->db->query( + 'SELECT id, size '. + 'FROM questtypes_textinput_fieldsizes '. + 'ORDER BY size' + ); + } } diff --git a/questtypes/textinput/html/edittask.tpl b/questtypes/textinput/html/edittask.tpl new file mode 100644 index 00000000..e8413333 --- /dev/null +++ b/questtypes/textinput/html/edittask.tpl @@ -0,0 +1,105 @@ + +
    + &$settings) : ?> +
  • +
      + $value) : ?> +
    • + +
    • + +
    +
  • + +
+ +
+
+ +
+ +
+
+ +
    + &$field) : ?> +
  • + + class="invalid" /> +
  • + +
+
+ + +
+

+

+ + + + t(mb_substr($text, $posStart, $posEnd-$posStart, 'UTF-8'))?> + class="" /> + + + t(mb_substr($text, $posStart, mb_strlen($text, 'UTF-8')-$posStart, 'UTF-8'))?> +

+ + diff --git a/views/html/html.tpl b/views/html/html.tpl index 085111ea..40b021db 100644 --- a/views/html/html.tpl +++ b/views/html/html.tpl @@ -34,6 +34,7 @@ + diff --git a/www/js/misc.js b/www/js/misc.js new file mode 100644 index 00000000..8bc8a0dd --- /dev/null +++ b/www/js/misc.js @@ -0,0 +1,52 @@ +/** + * http://stackoverflow.com/questions/1064089/inserting-a-text-where-cursor-is-using-javascript-jquery/1064139#1064139 + */ +function getCaret(textareaId) +{ + var textarea = document.getElementById(textareaId); + var strPos = 0; + if(textarea.selectionStart || textarea.selectionStart == '0') { + strPos = textarea.selectionStart + } + else if(document.selection) + { + textarea.focus(); + var range = document.selection.createRange(); + range.moveStart('character', -textarea.value.length); + strPos = range.text.length; + } + else { + strPos = -1; + } + + return strPos; +} + + +function insertAtCaret(textareaId, caret, text) +{ + var textarea = document.getElementById(textareaId); + var scrollPos = textarea.scrollTop; + + var front = (textarea.value).substring(0, caret); + var back = (textarea.value).substring(caret, textarea.value.length); + textarea.value = front + text + back; + caret = caret + text.length; + + if(textarea.selectionStart || textarea.selectionStart == '0') + { + textarea.selectionStart = caret; + textarea.selectionEnd = caret; + textarea.focus(); + } + else if(document.selection) + { + textarea.focus(); + var range = document.selection.createRange(); + range.moveStart('character', -textarea.value.length); + range.moveStart('character', caret); + range.moveEnd('character', 0); + range.select(); + } + textarea.scrollTop = scrollPos; +}