mirror of
https://gitlab.easter-eggs.com/ee/ldapsaisie.git
synced 2024-11-22 18:09:06 +01:00
LSattr_html :: mail : add autocomplete feature
This commit is contained in:
parent
103689d6ad
commit
ffdb8d4cf7
5 changed files with 465 additions and 15 deletions
|
@ -1,13 +1,51 @@
|
|||
<sect4 id="config-LSattr_html_mail">
|
||||
<title>LSattr_html_mail</title>
|
||||
<para>Ce type est utilisé pour la gestion des attributs dont la valeur est
|
||||
une adresse e-mail. Il propose directement dans l'interface, la possibilité
|
||||
d'envoyer des mails à l'adresse saisie.</para>
|
||||
une adresse e-mail. Il offre les fonctionnalités suivantes :
|
||||
<itemizedlist>
|
||||
<listitem><simpara>la possibilité d'envoyer des mails directement depuis l'interface
|
||||
de l'application ;</simpara></listitem>
|
||||
<listitem><simpara>l'autocomplétion lors de la saisie d'une adresse.</simpara></listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
|
||||
<programlisting linenumbering="unnumbered">
|
||||
<citetitle>Structure</citetitle>...
|
||||
<![CDATA['html_options' => array(
|
||||
'disableMailSending' => [booléen]
|
||||
'disableMailSending' => [booléen],
|
||||
|
||||
// Autocomplétion pour un type d'LSobject donné
|
||||
'autocomplete' => array (
|
||||
'object_type' => '[Type d'LSobject]',
|
||||
'mail_attributes' => array (
|
||||
'mail',
|
||||
'mailAlternateAddress',
|
||||
[...]
|
||||
),
|
||||
'filter' => '[filtre LDAP]',
|
||||
'basedn' => '[base DN spécifique]',
|
||||
'scope' => '[scope de recherche]',
|
||||
'displayFormat' => '[LSformat]',
|
||||
'onlyAccessible' => [booléen],
|
||||
),
|
||||
|
||||
// Autocomplétion sur la base d'une recherche LDAP brute
|
||||
'autocomplete' => array (
|
||||
'mail_attributes' => array (
|
||||
'mail',
|
||||
'mailAlternateAddress',
|
||||
[...]
|
||||
),
|
||||
'filter' => '[filtre LDAP]',
|
||||
'basedn' => '[base DN spécifique]',
|
||||
'scope' => '[scope de recherche]',
|
||||
'displayFormat' => '[LSformat]',
|
||||
'onlyAccessible' => [booléen],
|
||||
),
|
||||
|
||||
// Autocomplétion (par défaut)
|
||||
'autocomplete' => true,
|
||||
|
||||
),]]>
|
||||
...
|
||||
</programlisting>
|
||||
|
@ -25,6 +63,86 @@
|
|||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>autocomplete</term>
|
||||
<listitem>
|
||||
<para>Paramètrage de l'autocomplétion des adresses mails saisies : Il peut s'agir
|
||||
d'un tableau configurant les paramètres de l'autocomplétion ou simplement
|
||||
<literal>true</literal> pour activer l'autocomplétion par défaut, c'est à dire la recherche brute
|
||||
dans l'annuaire de n'importe quel objet ayant l'attribut <literal>mail</literal>.</para>
|
||||
<para>En cas de configuration avancée, il est possible de faire une recherche :
|
||||
<itemizedlist>
|
||||
<listitem><simpara>Sur la base d'un type d'&LSobject; donné : l'autocomplétion se fera
|
||||
alors comme n'importe quelle recherche d'un type d'objet donné.</simpara></listitem>
|
||||
<listitem><simpara>Sur la base d'une recherche brute dans l'annuaire : l'autocomplétion se
|
||||
fera alors sur la valeur de l'adresse mail recherchée et au travers une recherche brute dans
|
||||
l'annuaire sur n'importe quels objets ayant une adresse email correspondant.</simpara></listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
<para>Les paramètres associés à ces deux cas de figure sont décrits ci-dessous :
|
||||
<variablelist>
|
||||
|
||||
<varlistentry>
|
||||
<term>object_type</term>
|
||||
<listitem>
|
||||
<simpara>Le type d'&LSobject; recherché.</simpara>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>mail_attributes</term>
|
||||
<listitem>
|
||||
<simpara>Le(s) nom de l'attribut stockant les adresses emails recherchées. Il peut s'agir d'une chaîne
|
||||
de caractères ou d'un tableau s'il y a plusieurs attributs.</simpara>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>filter</term>
|
||||
<listitem>
|
||||
<simpara>Un filtre de recherche falcultatif venant en plus de celui calculé automatiquement à partir
|
||||
du mot clé de recherche.</simpara>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>basedn</term>
|
||||
<listitem>
|
||||
<simpara>Le <emphasis>basedn</emphasis> de la recherche. <emphasis>Paramètre
|
||||
facultatif.</emphasis></simpara>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>scope</term>
|
||||
<listitem>
|
||||
<simpara>Le <emphasis>scope</emphasis> de la recherche. <emphasis>Paramètre
|
||||
facultatif, par défaut : <literal>sub</literal>.</emphasis></simpara>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>displayFormat</term>
|
||||
<listitem>
|
||||
<simpara>Le &LSformat; d'affichage des objets trouvés. Ce paramètre est facultatif et par défaut,
|
||||
il s'agira du format d'affichage propre au type d'&LSobject; (si défini) et à défaut, l'adresse
|
||||
mail trouvée sera affichée.</simpara>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>onlyAccessible</term>
|
||||
<listitem>
|
||||
<simpara>Booléen falcultatif définissant si seul les &LSobjects; auxquels l'utilisateur connecté à accès
|
||||
doivent être considérés comme sélectionnables (Faux par défaut). Ce paramètre n'est appliqué que dans
|
||||
le cas d'une recherche pour un type d'&LSobject; donné.</simpara>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
|
||||
<important><simpara>Ce type d'attribut HTML est dérivé du type
|
||||
|
|
29
public_html/css/default/LSformElement_mail.css
Normal file
29
public_html/css/default/LSformElement_mail.css
Normal file
|
@ -0,0 +1,29 @@
|
|||
ul.LSformElement_mail_autocomplete {
|
||||
border: 1px solid #ccc;
|
||||
width: 200px;
|
||||
margin: 0;
|
||||
margin-top: 0.1em;
|
||||
max-height: 10em;
|
||||
overflow: auto;
|
||||
padding: 0;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
li.LSformElement_mail_autocomplete {
|
||||
cursor: pointer;
|
||||
border-bottom: 1px dotted #ccc;
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
li.LSformElement_mail_autocomplete:last-of-type {
|
||||
border: none;
|
||||
}
|
||||
|
||||
li.LSformElement_mail_autocomplete_over {
|
||||
background-color: #ccc;
|
||||
}
|
||||
|
||||
li.LSformElement_mail_autocomplete_current {
|
||||
font-style: italic;
|
||||
color: #777;
|
||||
}
|
|
@ -34,9 +34,14 @@ LSsession :: loadLSclass('LSformElement_text');
|
|||
class LSformElement_mail extends LSformElement_text {
|
||||
|
||||
var $JSscripts = array(
|
||||
'LSformElement_mail_field.js',
|
||||
'LSformElement_mail.js'
|
||||
);
|
||||
|
||||
var $CSSfiles = array(
|
||||
'LSformElement_mail.css',
|
||||
);
|
||||
|
||||
var $fetchVariables = array(
|
||||
'uriClass' => 'LSformElement_mail',
|
||||
'uriPrefix' => 'mailto:'
|
||||
|
@ -54,6 +59,9 @@ class LSformElement_mail extends LSformElement_text {
|
|||
if (LSsession :: loadLSclass('LSmail')) {
|
||||
LSmail :: loadDependenciesDisplay();
|
||||
}
|
||||
if (!$this -> isFreeze() && $this -> getParam('html_options.autocomplete')) {
|
||||
LSsession :: addJSconfigParam('LSformElement_mail_autocomplete_noResultLabel', _('No result'));
|
||||
}
|
||||
return parent :: getDisplay();
|
||||
}
|
||||
|
||||
|
@ -61,8 +69,135 @@ class LSformElement_mail extends LSformElement_text {
|
|||
if ($this -> getParam('html_options.disableMailSending', false, 'bool')) {
|
||||
$this -> fetchVariables['uriClass'] .= " LSformElement_mail_disableMailSending";
|
||||
}
|
||||
if ($this -> getParam('html_options.autocomplete', false, 'bool')) {
|
||||
$this -> fetchVariables['uriClass'] .= " LSformElement_mail_autocomplete";
|
||||
}
|
||||
return parent :: fetchTemplate($template,$variables);
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* Autocomplete email
|
||||
*
|
||||
* @param[in] $pattern The pattern of the search
|
||||
*
|
||||
* @retval array(mail -> displayName) Found emails
|
||||
*/
|
||||
public function autocomplete($pattern) {
|
||||
$ret = array();
|
||||
if ($this -> getParam('html_options.autocomplete')) {
|
||||
$mail_attributes = $this -> getParam('html_options.autocomplete.mail_attributes', array('mail'));
|
||||
if (!is_array($mail_attributes)) $mail_attributes = array($mail_attributes);
|
||||
|
||||
$obj_type = $this -> getParam('html_options.autocomplete.object_type');
|
||||
if ($obj_type) {
|
||||
// Search with a specific objectType
|
||||
if (LSsession :: loadLSobject($obj_type)) {
|
||||
$obj = new $obj_type();
|
||||
$filters = array();
|
||||
foreach($mail_attributes as $attr) {
|
||||
$filters[] = Net_LDAP2_Filter::create($attr, 'present');
|
||||
}
|
||||
$filter = (count($filters)==1?$filters[0]:Net_LDAP2_Filter::combine('or', $filters));
|
||||
if ($this -> getParam('html_options.autocomplete.filter')) {
|
||||
$filter = Net_LDAP2_Filter::combine(
|
||||
'and',
|
||||
array(
|
||||
Net_LDAP2_Filter::parse($this -> getParam('html_options.autocomplete.filter')),
|
||||
$filter,
|
||||
)
|
||||
);
|
||||
}
|
||||
$sparams = array(
|
||||
'pattern' => $pattern,
|
||||
'attributes' => $mail_attributes,
|
||||
'displayFormat' => $this -> getParam('html_options.autocomplete.display_name_format'),
|
||||
'filter' => $filter,
|
||||
'onlyAccessible' => $this -> getParam('html_options.autocomplete.onlyAccessible', false, 'bool'),
|
||||
);
|
||||
LSdebug($filter->as_string());
|
||||
$search = new LSsearch(
|
||||
$obj_type,
|
||||
'LSformElement_mail::autocomplete',
|
||||
$sparams,
|
||||
true
|
||||
);
|
||||
$search -> run();
|
||||
foreach($search -> getSearchEntries() as $e) {
|
||||
foreach($mail_attributes as $attr) {
|
||||
$mails = $e->get($attr);
|
||||
if (!$mails) continue;
|
||||
if (!is_array($mails)) $mails = array($mails);
|
||||
foreach($mails as $mail)
|
||||
$ret[$mail] = $e->displayName;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
$filters = array();
|
||||
foreach($mail_attributes as $attr) {
|
||||
$filters[] = Net_LDAP2_Filter::create($attr, 'contains', $pattern);
|
||||
}
|
||||
$filter = (count($filters)==1?$filters[0]:Net_LDAP2_Filter::combine('or', $filters));
|
||||
if ($this -> getParam('html_options.autocomplete.filter')) {
|
||||
$filter = Net_LDAP2_Filter::combine(
|
||||
'and',
|
||||
array(
|
||||
Net_LDAP2_Filter::parse($this -> getParam('html_options.autocomplete.filter')),
|
||||
$filter,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$displayNameFormat = $this -> getParam('html_options.autocomplete.display_name_format', false);
|
||||
$attributes = $mail_attributes;
|
||||
if ($displayNameFormat)
|
||||
foreach(getFieldInFormat($displayNameFormat) as $attr)
|
||||
if(!in_array($attr, $attributes))
|
||||
$attributes[] = $attr;
|
||||
|
||||
$objects = LSldap :: search (
|
||||
$filter,
|
||||
$this -> getParam('html_options.autocomplete.basedn', null),
|
||||
array (
|
||||
'attributes' => $attributes,
|
||||
'scope' => $this -> getParam('html_options.autocomplete.scope', 'sub'),
|
||||
)
|
||||
);
|
||||
|
||||
if (is_array($objects)) {
|
||||
foreach($objects as $object) {
|
||||
$displayName = ($displayNameFormat?getFData($displayNameFormat, $object['attrs']):null);
|
||||
foreach($mail_attributes as $attr) {
|
||||
if (!isset($object['attrs'][$attr])) continue;
|
||||
$mails = $object['attrs'][$attr];
|
||||
if (!is_array($mails)) $mails = array($mails);
|
||||
foreach($mails as $mail)
|
||||
$ret[$mail] = ($displayName?$displayName:$mail);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* This ajax method is used by the autocomplete function of the form element.
|
||||
*
|
||||
* @param[in] $data The address to the array of data witch will be return by the ajax request
|
||||
*
|
||||
* @retval void
|
||||
**/
|
||||
public static function ajax_autocomplete(&$data) {
|
||||
if ((isset($_REQUEST['attribute'])) && (isset($_REQUEST['objecttype'])) && (isset($_REQUEST['pattern'])) && (isset($_REQUEST['idform'])) ) {
|
||||
if (LSsession ::loadLSobject($_REQUEST['objecttype'])) {
|
||||
$object = new $_REQUEST['objecttype']();
|
||||
$form = $object -> getForm($_REQUEST['idform']);
|
||||
$field=$form -> getElement($_REQUEST['attribute']);
|
||||
$data['mails'] = $field -> autocomplete($_REQUEST['pattern']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
var LSformElement_mail = new Class({
|
||||
initialize: function(){
|
||||
this.fields = [];
|
||||
this.initialiseLSformElement_mail();
|
||||
if (typeof(varLSform) != "undefined") {
|
||||
varLSform.addModule("LSformElement_mail",this);
|
||||
|
@ -21,6 +22,16 @@ var LSformElement_mail = new Class({
|
|||
this.addBtnAfter.bind(this)(a);
|
||||
}
|
||||
}, this);
|
||||
var getName = /^(.*)\[\]$/;
|
||||
el.getElements('input.LSformElement_mail_autocomplete').each(function(input) {
|
||||
this.fields.push(
|
||||
new LSformElement_mail_field(
|
||||
getName.exec(input.name)[1],
|
||||
input
|
||||
)
|
||||
);
|
||||
}, this);
|
||||
|
||||
},
|
||||
|
||||
addBtnAfter: function(el) {
|
||||
|
|
157
public_html/includes/js/LSformElement_mail_field.js
Normal file
157
public_html/includes/js/LSformElement_mail_field.js
Normal file
|
@ -0,0 +1,157 @@
|
|||
var LSformElement_mail_field = new Class({
|
||||
initialize: function(name, input){
|
||||
this.name = name;
|
||||
this.input = input;
|
||||
this.ul = input.getParent('ul');
|
||||
this.li = input.getParent('li');
|
||||
this.keyUpTimer = null;
|
||||
this.lastKeyUpValue = null;
|
||||
this.lastAutocompletePattern = null;
|
||||
this.lastAutocompleteMails = null;
|
||||
this.initialiseLSformElement_mail_field();
|
||||
},
|
||||
|
||||
initialiseLSformElement_mail_field: function() {
|
||||
this.input.addEvent('keyup',this.onKeyUp.bindWithEvent(this));
|
||||
this.input.addEvent('keydown',this.onKeyDown.bindWithEvent(this));
|
||||
},
|
||||
|
||||
onKeyDown: function(event) {
|
||||
event = new Event(event);
|
||||
if (event.key=='tab' && this.input.value) {
|
||||
event.stop();
|
||||
if (this.keyUpTimer) {
|
||||
clearTimeout(this.keyUpTimer);
|
||||
}
|
||||
this.launchAutocomplete(this.input.value);
|
||||
}
|
||||
},
|
||||
|
||||
onKeyUp: function(event) {
|
||||
this.lastKeyUpValue = this.input.value;
|
||||
if (this.keyUpTimer) {
|
||||
clearTimeout(this.keyUpTimer);
|
||||
}
|
||||
if (this.lastKeyUpValue) {
|
||||
this.keyUpTimer = this.onkeyUpTimeout.delay(800, this);
|
||||
}
|
||||
},
|
||||
|
||||
onkeyUpTimeout: function() {
|
||||
this.keyUpTimer = null;
|
||||
if (this.lastKeyUpValue == this.input.value) {
|
||||
this.launchAutocomplete(this.input.value);
|
||||
}
|
||||
},
|
||||
|
||||
launchAutocomplete: function(pattern) {
|
||||
if (this.lastAutocompletePattern == pattern) {
|
||||
if (!this.autocompleteIsOpen()) this.showAutocompleteMails();
|
||||
return true;
|
||||
}
|
||||
this.input.set('disabled', 'disabled');
|
||||
this.lastAutocompletePattern=pattern;
|
||||
var data = {
|
||||
template: 'LSformElement_mail',
|
||||
action: 'autocomplete',
|
||||
attribute: this.name,
|
||||
objecttype: varLSform.objecttype,
|
||||
idform: varLSform.idform,
|
||||
pattern: pattern
|
||||
};
|
||||
data.imgload=varLSdefault.loadingImgDisplay(this.input);
|
||||
new Request({url: 'index_ajax.php', data: data, onSuccess: this.onAutocompleteComplete.bind(this)}).send();
|
||||
},
|
||||
|
||||
onAutocompleteComplete: function(responseText, responseXML) {
|
||||
var data = JSON.decode(responseText);
|
||||
this.input.erase('disabled');
|
||||
if ( varLSdefault.checkAjaxReturn(data) ) {
|
||||
this.lastAutocompleteMails = new Hash(data.mails);
|
||||
this.showAutocompleteMails();
|
||||
}
|
||||
},
|
||||
|
||||
showAutocompleteMails: function() {
|
||||
if (!this.lastAutocompleteMails) return;
|
||||
if (!$type(this.autocompleteUl)) {
|
||||
this.autocompleteUl = new Element('ul');
|
||||
this.autocompleteUl.addClass('LSformElement_mail_autocomplete');
|
||||
this.autocompleteUl.injectInside(this.li);
|
||||
document.addEvent('click', this.closeAutocompleteIfOpen.bind(this));
|
||||
}
|
||||
this.autocompleteUl.empty();
|
||||
if (this.lastAutocompleteMails) {
|
||||
this.lastAutocompleteMails.each(this.addAutocompleteLi, this);
|
||||
}
|
||||
this.addAutocompleteNoValueLabelIfEmpty();
|
||||
|
||||
this.autocompleteUl.setStyle('display','block');
|
||||
},
|
||||
|
||||
addAutocompleteLi: function(name, mail) {
|
||||
var current = 0;
|
||||
this.ul.getElements("input").each(function(input){
|
||||
if (input.value==mail && input != this.input) {
|
||||
current=1;
|
||||
}
|
||||
},this);
|
||||
|
||||
var li = new Element('li');
|
||||
li.addClass('LSformElement_mail_autocomplete');
|
||||
li.set('data-mail', mail);
|
||||
li.set('html', name);
|
||||
li.addEvent('mouseenter',this.onAutocompleteLiMouseEnter.bind(this,li));
|
||||
li.addEvent('mouseleave',this.onAutocompleteLiMouseLeave.bind(this,li));
|
||||
if (current) {
|
||||
li.addClass('LSformElement_mail_autocomplete_current');
|
||||
}
|
||||
else {
|
||||
li.addEvent('click',this.onAutocompleteLiClick.bind(this,li));
|
||||
}
|
||||
li.injectInside(this.autocompleteUl);
|
||||
},
|
||||
|
||||
addAutocompleteNoValueLabelIfEmpty: function() {
|
||||
if (this.autocompleteUl.getElement('li') == null) {
|
||||
var li = new Element('li');
|
||||
li.addClass('LSformElement_mail_autocomplete');
|
||||
li.set('html', varLSdefault.LSjsConfig['LSformElement_mail_autocomplete_noResultLabel']);
|
||||
li.injectInside(this.autocompleteUl);
|
||||
}
|
||||
},
|
||||
|
||||
onAutocompleteLiMouseEnter: function(li) {
|
||||
li.addClass('LSformElement_mail_autocomplete_over');
|
||||
},
|
||||
|
||||
onAutocompleteLiMouseLeave: function(li) {
|
||||
li.removeClass('LSformElement_mail_autocomplete_over');
|
||||
},
|
||||
|
||||
onAutocompleteLiClick: function(li) {
|
||||
this.closeAutocomplete();
|
||||
if (li.get('data-mail')) {
|
||||
this.input.value = li.get('data-mail');
|
||||
}
|
||||
},
|
||||
|
||||
autocompleteIsOpen: function() {
|
||||
return ($type(this.autocompleteUl) == 'element' && this.autocompleteUl.getStyle('display') != 'none');
|
||||
},
|
||||
|
||||
closeAutocomplete: function() {
|
||||
if (!this.autocompleteIsOpen()) return true;
|
||||
this.autocompleteUl.setStyle('display', 'none');
|
||||
},
|
||||
|
||||
closeAutocompleteIfOpen: function(event) {
|
||||
event = new Event(event);
|
||||
if (!this.autocompleteIsOpen())
|
||||
return true;
|
||||
if (event.target==this.input || event.target==this.autocompleteUl)
|
||||
return true;
|
||||
this.closeAutocomplete();
|
||||
},
|
||||
|
||||
});
|
Loading…
Reference in a new issue