From 065f77230276b634ca2efbc623bd5dcbbfaef28d Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Wed, 8 Oct 2014 09:09:02 +0000 Subject: [PATCH] * Mail: allow to enter name+mail eg. "Ralf Becker " in compose, automatic fix unquoted commas in entered mail addresses --- .../inc/class.etemplate_widget_date.inc.php | 70 ++++++++++++++----- .../class.etemplate_widget_nextmatch.inc.php | 33 ++++++++- etemplate/js/et2_widget_taglist.js | 59 +++++++++++++++- .../magicsuggest/src/magicsuggest-1.3.1.js | 5 +- 4 files changed, 144 insertions(+), 23 deletions(-) diff --git a/etemplate/inc/class.etemplate_widget_date.inc.php b/etemplate/inc/class.etemplate_widget_date.inc.php index 4cc8a80579..3939d4d414 100644 --- a/etemplate/inc/class.etemplate_widget_date.inc.php +++ b/etemplate/inc/class.etemplate_widget_date.inc.php @@ -65,30 +65,62 @@ class etemplate_widget_date extends etemplate_widget_transformer $form_name = self::form_name($cname, $this->id, $expand); $value =& self::get_array(self::$request->content, $form_name, false, true); - + if($this->type != 'date-duration' && $value) { - // string with formatting letters like for php's date() method - if ($this->attrs['dataformat'] && !is_numeric($value)) - { - $date = date_create_from_format($this->attrs['dataformat'], $value, egw_time::$user_timezone); - } - else - { - $date = new egw_time($value); - } - if($this->type == 'date-timeonly') - { - $date->setDate(1970, 1, 1); - } - if($date) - { - // postfix date-string with "Z" so javascript doesn't add/subtract anything - $value = $date->format('Y-m-d\TH:i:s\Z'); - } + $value = $this->format_date($value); } } + /** + * Perform any needed data manipulation on each row + * before sending it to client. + * + * This is used by etemplate_widget_nextmatch on each row to do any needed + * adjustments. If not needed, don't implement it. + * + * @param type $cname + * @param array $expand + * @param array $data Row data + * @return type + */ + public function set_row_value($cname, Array $expand, Array &$data) + { + if($this->type == 'date-duration') return; + + $form_name = self::form_name($cname, $this->id, $expand); + $value =& $this->get_array($data, $form_name, true); + + $value = $this->format_date($value); + } + + /** + * Put date in the proper format for sending to client + * @param string|int $value + * @param string $format + */ + public function format_date($value) + { + if ($this->attrs['dataformat'] && !is_numeric($value)) + { + $date = date_create_from_format($this->attrs['dataformat'], $value, egw_time::$user_timezone); + } + else + { + $date = new egw_time($value); + } + if($this->type == 'date-timeonly') + { + $date->setDate(1970, 1, 1); + } + if($date) + { + // postfix date-string with "Z" so javascript doesn't add/subtract anything + $value = $date->format('Y-m-d\TH:i:s\Z'); + } + return $value; + } + /** * Validate input * diff --git a/etemplate/inc/class.etemplate_widget_nextmatch.inc.php b/etemplate/inc/class.etemplate_widget_nextmatch.inc.php index 5106c15b18..4ba23c7af5 100644 --- a/etemplate/inc/class.etemplate_widget_nextmatch.inc.php +++ b/etemplate/inc/class.etemplate_widget_nextmatch.inc.php @@ -356,6 +356,24 @@ class etemplate_widget_nextmatch extends etemplate_widget $row_id = isset($value['row_id']) ? $value['row_id'] : 'id'; $row_modified = $value['row_modified']; + + if($template && $template->attrs['template']) + { + $row_template = $template->getElementById($template->attrs['template']); + if(!$row_template) + { + $row_template = etemplate_widget_template::instance($template->attrs['template']); + } + + // Try to find just the repeating part + $repeating_child = null; + // First child should be a grid, we want last row + foreach($row_template->children[0]->children[1]->children as $child) + { + if($child->type == 'row') $repeating_child = $child; + } + $row_template = $repeating_child ? $repeating_child : null; + } foreach($rows as $n => $row) { @@ -373,8 +391,21 @@ class etemplate_widget_nextmatch extends etemplate_widget if (!$row_id || !$knownUids || ($kUkey = array_search($id, $knownUids)) === false || !$lastModified || !isset($row[$row_modified]) || $row[$row_modified] > $lastModified) { - $result['data'][$id] = self::run_beforeSendToClient($row); + if($row_template) + { + // Change anything by widget for each row ($row set to 1) + $_row = array(1 => &$row); + $row_template->run('set_row_value', array('',array('row' => 1), &$_row), true); + $result['data'][$id] = $row; + } + else if (!$template && !get_class($template) != 'etemplate_widget_historylog') + { + // Fallback based on widget names + error_log(self::$request->template['name'] . ' had to fallback to run_beforeSendToClient() because it could not find the row' ); + $result['data'][$id] = self::run_beforeSendToClient($row); + } } + if ($kUkey !== false) unset($knownUids[$kUkey]); } else // non-row data set by get_rows method diff --git a/etemplate/js/et2_widget_taglist.js b/etemplate/js/et2_widget_taglist.js index 48c36c2ca9..17e143957f 100644 --- a/etemplate/js/et2_widget_taglist.js +++ b/etemplate/js/et2_widget_taglist.js @@ -99,7 +99,13 @@ var et2_taglist = et2_selectbox.extend( // Selectbox attributes that are not applicable "multiple": { ignore: true}, "rows": { ignore: true}, - "tags": { ignore: true} + "tags": { ignore: true}, + useCommaKey: { + name: "comma will start validation", + type: "boolean", + "default": true, + description: "Set to false to allow comma in entered content" + } }, // Allows sub-widgets to override options to the library @@ -160,6 +166,7 @@ var et2_taglist = et2_selectbox.extend( required: this.options.required, allowFreeEntries: this.options.allowFreeEntries, useTabKey: true, + useCommaKey: this.options.useCommaKey, disabled: this.options.disabled || this.options.readonly, editable: !(this.options.disabled || this.options.readonly), selectionRenderer: jQuery.proxy(this.options.tagRenderer || this.selectionRenderer,this), @@ -474,8 +481,14 @@ var et2_taglist_email = et2_taglist.extend( description:"Include mailing lists in search results", default: false, type: "boolean" - } }, + useCommaKey: { + name: "comma will start validation", + type: "boolean", + "default": false, + description: "Set to false to allow comma in entered content" + } + }, lib_options: { // Search function limits to 3 anyway minChars: 3 @@ -507,6 +520,48 @@ var et2_taglist_email = et2_taglist.extend( // We check free entries for valid email, and render as invalid if it's not. var valid = item.id != item.label || et2_url.prototype.EMAIL_PREG.test(item.id || ''); + if (!valid && item.id) + { + // automatic quote 'Becker, Ralf ' as '"Becker, Ralf" ' + var matches = item.id.match(/^(.*) ?<(.*)>$/); + if (matches && et2_url.prototype.EMAIL_PREG.test('"'+matches[1].trim()+'" <'+matches[2].trim()+'>')) + { + item.id = item.label = '"'+matches[1].trim()+'" <'+matches[2].trim()+'>'; + valid = true; + } + // automatic insert multiple comma-separated emails like "rb@stylite.de, hn@stylite.de" + if (!valid) + { + var parts = item.id.split(/, */); + if (parts.length > 1) + { + valid = true; + for(var i=0; i < parts.length; ++i) + { + parts[i] = parts[i].trim(); + if (!et2_url.prototype.EMAIL_PREG.test(parts[i])) + { + valid = false; + break; + } + } + if (valid) + { + item.id = item.label = parts.shift(); + // insert further parts into taglist, after validation first one + var taglist = this.taglist; + window.setTimeout(function() + { + for(var i=0; i < parts.length; ++i) + { + taglist.addToSelection({id: parts[i], label: parts[i]}); + } + }, 10); + } + } + } + } + var label = jQuery('').text(item.label); if (item.class) label.addClass(item.class); if (typeof item.title != 'undefined') label.attr('title', item.title); diff --git a/phpgwapi/js/jquery/magicsuggest/src/magicsuggest-1.3.1.js b/phpgwapi/js/jquery/magicsuggest/src/magicsuggest-1.3.1.js index 20a4b91c86..2bd590aba7 100644 --- a/phpgwapi/js/jquery/magicsuggest/src/magicsuggest-1.3.1.js +++ b/phpgwapi/js/jquery/magicsuggest/src/magicsuggest-1.3.1.js @@ -1291,7 +1291,9 @@ } break; case 188: // comma + if(!cfg.useCommaKey) break; if(e.shiftKey) break; // Shift + , = < on some keyboards + if(e.originalEvent && e.originalEvent.keyIdentifier && e.originalEvent.keyIdentifier != "U+002C") break; case 9: // tab case 13: // enter e.preventDefault(); @@ -1348,7 +1350,8 @@ break; case 13:case 9:case 188:// enter, tab, comma // Shift + comma = < on English keyboard - if(e.keyCode !== 188 || (cfg.useCommaKey === true && !e.shiftKey)) { + if(e.keyCode !== 188 || (cfg.useCommaKey === true && + !(e.shiftKey || e.originalEvent && e.originalEvent.keyIdentifier && e.originalEvent.keyIdentifier != "U+002C"))) { e.preventDefault(); if(cfg.expanded === true){ // if a selection is performed, select it and reset field selected = ms.combobox.find('.ms-res-item-active:first');