461 lines
16 KiB
JavaScript
Executable File
461 lines
16 KiB
JavaScript
Executable File
/* [0] Constructeur -> définit le conteneur et le bouton d'ajout
|
|
=========================================================*/
|
|
function inputFacebookMini(container, navContainer){
|
|
this.container = container;
|
|
this.nav_container = navContainer;
|
|
}
|
|
|
|
|
|
/* [1] Attributs
|
|
=========================================================*/
|
|
inputFacebookMini.prototype = {
|
|
container: this.container, // Conteneur des mini fiches relation
|
|
nav_container: this.nav_container, // Conteneur de la navigation entre les MINI fiches
|
|
selected: null, // UID de la MINI fiche sélectionnée
|
|
handler: null, // Fonction pour l'enregistrement et la synchronisation des données
|
|
defaultData: { // Valeur par défaut
|
|
contact: null,
|
|
sexe: '2',
|
|
age: '.',
|
|
studies: '0',
|
|
loc: '.',
|
|
reltype: '9',
|
|
reltypeSpecial: '',
|
|
unknown: false,
|
|
timestamp: 0,
|
|
valid: false
|
|
}
|
|
};
|
|
|
|
|
|
/* [2] Gestion de l'enregistrement des formulaires mini fiches relation
|
|
=========================================================*/
|
|
inputFacebookMini.prototype.fieldsToStorage = function(){
|
|
console.group('[facebook.mini] fields to storage');
|
|
|
|
var i, l, deflater, deflated, existingData, obj, hash;
|
|
|
|
/* (1) Pour chaque formulaire de MINI fiche à l'écran
|
|
---------------------------------------------------------*/
|
|
var existingMiniFiches = $$('[data-sublink="facebook"] article.mini-relation-panel .mini-fiche-relation');
|
|
for( i = 0, l = existingMiniFiches.length ; i < l ; i++ ){
|
|
|
|
/* (1) On initialise notre deflater pour récupérer les valeurs */
|
|
deflater = new FormDeflater(existingMiniFiches[i], ['input', 'select'], ['data-name']);
|
|
|
|
/* (2) On récupère les données */
|
|
deflated = deflater.deflate();
|
|
|
|
/* (3) On récupère les données du LSI si elles existent */
|
|
existingData = lsi.get('f_mini-fiches', deflated.uid);
|
|
|
|
// Si erreur, on passe à la fiche suivante
|
|
if( !existingData )
|
|
continue;
|
|
|
|
/* (4) On récupère et met en forme les valeurs du deflater */
|
|
obj = {
|
|
contact: parseInt(deflated.uid),
|
|
sexe: deflated.sexe,
|
|
age: deflated.age,
|
|
studies: deflated.studies,
|
|
loc: deflated.loc,
|
|
reltype: deflated.reltype,
|
|
reltypeSpecial: deflated.reltypeSpecial,
|
|
unknown: deflated.unknown != null,
|
|
uid: parseInt(deflated.uid)
|
|
};
|
|
|
|
/* (5) On calcule/compare le hash */
|
|
|
|
// {5.1} On calcule le hash //
|
|
hash = crc32( JSON.stringify(obj) );
|
|
|
|
// {5.2} Si le hash est identique, on ne fait rien //
|
|
if( existingData.hasOwnProperty('hash') && hash == existingData.hash )
|
|
continue;
|
|
|
|
// {5.3} On enregistre le hash //
|
|
obj.hash = hash;
|
|
|
|
|
|
/* (6) On calcule la validité des données */
|
|
obj.valid = this.check(obj);
|
|
|
|
/* (7) On met à jour le `timestamp` (car à ce point, on a une modification) */
|
|
obj.timestamp = Date.now();
|
|
console.warn('> MINI UPDATE ('+(obj.timestamp-input_ts)+')');
|
|
|
|
/* (8) On enregistre les données dans le 'localStorage' */
|
|
lsi.set('f_mini-fiches', obj.uid, obj);
|
|
|
|
}
|
|
|
|
console.groupEnd();
|
|
};
|
|
|
|
|
|
/* [3] Gestion de l'ajout physique d'un nouveau contact
|
|
=========================================================*/
|
|
/*
|
|
*
|
|
* @objectData<Object> Objet contenant les informations nécessaires à l'affichage
|
|
*
|
|
*/
|
|
inputFacebookMini.prototype.add = function(objectData){
|
|
|
|
// Si pas d'UID, on retourne une erreur
|
|
if( objectData == null || objectData.uid == null )
|
|
return false;
|
|
|
|
/* (0) Gestion du formattage des valeur */
|
|
objectData.age = (objectData.age != null) ? objectData.age : this.defaultData.age;
|
|
objectData.sexe = (objectData.sexe != null) ? objectData.sexe : this.defaultData.sexe;
|
|
objectData.studies = (objectData.studies != null) ? objectData.studies : this.defaultData.studies;
|
|
objectData.reltype = (objectData.reltype != null) ? objectData.reltype : this.defaultData.reltype;
|
|
objectData.reltypeSpecial = (objectData.reltypeSpecial != null) ? objectData.reltypeSpecial : this.defaultData.reltypeSpecial;
|
|
objectData.loc = (objectData.loc != null) ? objectData.loc : this.defaultData.loc;
|
|
objectData.unknown = (objectData.unknown != null) ? objectData.unknown : this.defaultData.unknown;
|
|
|
|
|
|
// {1} On récupère username/firstname/lastname du contact associé //
|
|
var associatedContact = lsi.get('f_contacts', objectData.uid);
|
|
|
|
// Si on ne trouve pas le contact, on ne fais rien
|
|
if( associatedContact === false )
|
|
return false;
|
|
|
|
// {2} Si lié à un contact d'une autre étude, on utilise ses informations //
|
|
if( !isNaN(associatedContact.existing) ){
|
|
var existingData = lsi.get('f_friends', associatedContact.existing);
|
|
|
|
// On récupère les données communes
|
|
associatedContact.username = existingData.name;
|
|
objectData.contact = existingData.contact;
|
|
objectData.age = existingData.age;
|
|
objectData.sexe = existingData.sexe;
|
|
objectData.loc = existingData.dist;
|
|
|
|
// DISTANCE (LOC) : Si valeur
|
|
if( !isNaN(existingData.reltype) ){
|
|
objectData.reltype = existingData.reltype;
|
|
objectData.reltypeSpecial = '';
|
|
|
|
// DISTANCE (LOC) : Si extra
|
|
}else{
|
|
objectData.reltype = 10;
|
|
objectData.reltypeSpecial = existingData.reltype;
|
|
}
|
|
|
|
// On met à jour les études uniquement si 'studies1' est défini //
|
|
if( existingData.studies1 != null )
|
|
objectData.studies = existingData.studies1;
|
|
|
|
}
|
|
|
|
|
|
// {2} Création physique //
|
|
this.container.innerHTML += fMiniFicheBuilder.build({
|
|
name: associatedContact.username,
|
|
uid: objectData.uid,
|
|
reltypespecial: objectData.reltypeSpecial
|
|
});
|
|
|
|
|
|
/* {3} On sélectionne la valeur dans le select (manuellement) de la PROFESSION */
|
|
var selectedOption = $('[data-sublink="facebook"] article.mini-fiche-relation input[data-name="uid"][value="'+objectData.uid+'"] ~ h5>span>select[data-name="studies"]>option[value="'+objectData.studies+'"]');
|
|
if( selectedOption != null )
|
|
selectedOption.setAttribute('selected', 'selected');
|
|
|
|
/* {4} On sélectionne la valeur dans le select (manuellement) de l'AGE */
|
|
selectedOption = $('[data-sublink="facebook"] article.mini-fiche-relation input[data-name="uid"][value="'+objectData.uid+'"] ~ h5>span>select[data-name="age"]>option[value="'+objectData.age+'"]');
|
|
if( selectedOption != null )
|
|
selectedOption.setAttribute('selected', 'selected');
|
|
|
|
/* {5} On sélectionna la valeur des boutons <radio> pour le SEXE */
|
|
var sexeCreated = $$('[data-sublink="facebook"] article.mini-fiche-relation input[data-name="uid"][value="'+objectData.uid+'"] ~ h5>input[type="radio"][data-name="sexe"]');
|
|
for( var i = 0 ; i < sexeCreated.length ; i++ )
|
|
if( sexeCreated[i].value == objectData.sexe ) sexeCreated[i].setAttribute('checked', 'checked');
|
|
else sexeCreated[i].removeAttribute('checked');
|
|
|
|
/* {6} On sélectionna la valeur des boutons <radio> pour le TYPE DE RELATION */
|
|
var reltypeCreated = $$('[data-sublink="facebook"] article.mini-fiche-relation input[data-name="uid"][value="'+objectData.uid+'"] ~ h5>input[type="radio"][data-name="reltype"]');
|
|
for( var i = 0 ; i < reltypeCreated.length ; i++ )
|
|
if( reltypeCreated[i].value == objectData.reltype ) reltypeCreated[i].setAttribute('checked', 'checked');
|
|
else reltypeCreated[i].removeAttribute('checked');
|
|
|
|
/* {7} On sélectionna la valeur des boutons <radio> pour la LOCATION */
|
|
var locCreated = $$('[data-sublink="facebook"] article.mini-fiche-relation input[data-name="uid"][value="'+objectData.uid+'"] ~ h5>input[type="radio"][data-name="loc"]');
|
|
for( var i = 0 ; i < locCreated.length ; i++ )
|
|
if( locCreated[i].value == objectData.loc ) locCreated[i].setAttribute('checked', 'checked');
|
|
else locCreated[i].removeAttribute('checked');
|
|
|
|
/* (8) On coche ou non 'unknonw' */
|
|
var unknownCreated = $('[data-sublink="facebook"] article.mini-fiche-relation input[data-name="uid"][value="'+objectData.uid+'"] ~ h5>input[type="checkbox"][data-name="unknown"]');
|
|
if( unknownCreated != null && objectData.unknown )
|
|
unknownCreated.setAttribute('checked', 'checked');
|
|
|
|
};
|
|
|
|
|
|
/* [4] Gestion de l'affichage depuis le 'localStorage'
|
|
=========================================================*/
|
|
inputFacebookMini.prototype.storageToFields = function(){
|
|
console.group('[facebook.mini] storage to fields');
|
|
|
|
/* (1) On charge le contact selectionné
|
|
---------------------------------------------------------*/
|
|
var miniData = lsi.export('f_mini-fiches');
|
|
var miniKeys = lsi.keys('f_mini-fiches');
|
|
var selectedMini = miniData[this.selected] != undefined ? miniData[this.selected] : null;
|
|
|
|
/* (2) Si aucune mini sélectionnée, on prend la première
|
|
---------------------------------------------------------*/
|
|
if( selectedMini === null ){
|
|
|
|
/* (2.1) Si `selected` n'est pas encore défini
|
|
---------------------------------------------------------*/
|
|
if( this.selected === null ){
|
|
|
|
/* (1) Si aucune mini, on quitte */
|
|
if( miniKeys.length == 0 )
|
|
return false;
|
|
|
|
/* (2) Sinon, on prend la première */
|
|
this.selected = miniKeys[0];
|
|
return this.storageToFields();
|
|
|
|
/* (2.2) S'il est déja défini, on met à jour la nav
|
|
---------------------------------------------------------*/
|
|
}else{
|
|
this.updateNavBar();
|
|
return false;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/* (3) Affichage de la fiche sélectionnée
|
|
---------------------------------------------------------*/
|
|
var clone, hash;
|
|
|
|
/* (1) On réinitialise le HTML */
|
|
this.container.innerHTML = '';
|
|
|
|
/* (2) Pour chaque mini */
|
|
for( var key in miniData ){
|
|
|
|
// {3.1} On calcule/enregistre le hash (sans `timestamp`, `hash`, `valid`) //
|
|
clone = cloneObject( miniData[key] );
|
|
delete clone['hash'];
|
|
delete clone['timestamp'];
|
|
delete clone['valid'];
|
|
miniData[key].hash = crc32( JSON.stringify(clone) );
|
|
|
|
// On enregistre dans le `localStorage`
|
|
lsi.set('f_mini-fiches', miniData[key].uid, miniData[key]);
|
|
|
|
// {2.2} Pour la fiche à rendre graphiquement //
|
|
if( miniData[key].uid == this.selected )
|
|
this.add(miniData[key]);
|
|
|
|
|
|
}
|
|
|
|
|
|
/* (3) On met à jour la navigation */
|
|
this.updateNavBar();
|
|
|
|
|
|
console.groupEnd();
|
|
};
|
|
|
|
|
|
/* [5] Synchronisation des CONTACT vers les MINI fiches
|
|
=========================================================*/
|
|
inputFacebookMini.prototype.sync = function(){
|
|
console.group('[facebook.mini] synchronisation');
|
|
|
|
/* (1) On récupère les clés de tous les CONTACTS */
|
|
var contactData = lsi.export('f_contacts');
|
|
var ficheData, miniData;
|
|
|
|
/* (2) On enregistre les contacts qui ne sont pas déja dans les FICHES */
|
|
ficheIndexes = lsi.keys('f_fiches');
|
|
|
|
for( var i in ficheIndexes )
|
|
delete contactData[ ficheIndexes[i] ];
|
|
|
|
/* (3) Pour chaque CONTACT restant, on met à jour/crée la MINI fiche associée */
|
|
for( var key in contactData ){
|
|
|
|
/* (4) Si le contact n'a aucun nominatif, on met inconnu par défaut, mais on ne l'affiche pas */
|
|
var noName = contactData[key].username.length == 0;
|
|
|
|
// On rajoute un '-' après pour dire qu'on affichera pas
|
|
var uid = noName ? key.toString()+'-' : key;
|
|
|
|
/* (5) On récupère les informations de la MINI (si elle existe) */
|
|
miniData = lsi.get('f_mini-fiches', uid);
|
|
|
|
|
|
/* (6) Si la MINI fiche n'exise pas, on la crée avec les valeurs par défaut */
|
|
if( miniData == null ){
|
|
miniData = this.defaultData;
|
|
miniData.contact = contactData[key].uid;
|
|
miniData.valid = false;
|
|
}
|
|
|
|
/* (7) On met à jour la MINI fiche */
|
|
miniData.uid = parseInt( key );
|
|
|
|
/* (8) On enregistre les modification */
|
|
lsi.set('f_mini-fiches', uid, miniData);
|
|
|
|
}
|
|
|
|
/* (9) On met à jour la mini-fiche en cours */
|
|
miniData = lsi.export('f_mini-fiches');
|
|
|
|
// Si la clé n'existe plus
|
|
if( miniData[this.selected] == null ){
|
|
|
|
// On cherche la première clé numérique
|
|
for( var key in miniData )
|
|
if( !isNaN(key) ){ // La première qu'on trouve, on la définit
|
|
this.selected = parseInt(key);
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
console.groupEnd();
|
|
};
|
|
|
|
|
|
/* [6] Gestion de la navigation entre les fiches
|
|
=========================================================*/
|
|
inputFacebookMini.prototype.nav = function(element){
|
|
/* (1) On vérifie que l'élément contient un nombre et existe */
|
|
if( !(element instanceof Element) )
|
|
return false;
|
|
|
|
if( !element.getData('n') || isNaN(element.getData('n')) || element.parentNode.id != 'f_nav-mini' )
|
|
return false;
|
|
|
|
/* (2) On désactive tous les éléments actifs */
|
|
var activeElements = $$('[data-sublink="facebook"] #f_nav-mini > span.active');
|
|
for( var i = 0 ; i < activeElements.length ; i++ )
|
|
activeElements[i].remClass('active');
|
|
|
|
/* (3) On active l'élément courant */
|
|
element.addClass('active');
|
|
this.selected = parseInt(element.getData('n'));
|
|
};
|
|
|
|
|
|
/* [7] Mise à jour de la navigation
|
|
=========================================================*/
|
|
inputFacebookMini.prototype.updateNavBar = function(){
|
|
var miniData = lsi.export('f_mini-fiches');
|
|
|
|
|
|
/* (1) On vide et remplit la barre de nav, si elle n'est pas à jour */
|
|
this.nav_container.innerHTML = '';
|
|
var i = 0;
|
|
|
|
for( var key in miniData )
|
|
if( !isNaN(key) ) // On affiche que les clés numériques
|
|
this.nav_container.innerHTML += '<span data-n="'+key+'">'+(++i)+'</span>';
|
|
|
|
|
|
/* (2) On montre les MINI fiches qui sont correctes dans la navbar */
|
|
for( var key in miniData ){
|
|
|
|
// Si la clé n'est pas numérique, on ne gère pas
|
|
if( isNaN(key) )
|
|
continue;
|
|
|
|
var currentElement = $('[data-sublink="facebook"] #f_nav-mini [data-n="'+miniData[key].uid+'"]');
|
|
|
|
if( currentElement == null )
|
|
continue;
|
|
|
|
// On remplit avec le numéro de la MINI fiche
|
|
// currentElement.setAttribute('data-n', miniData[key].uid);
|
|
// currentElement.innerHTML = miniData[key].uid + 1;
|
|
|
|
// Si la MINI fiche est valide
|
|
if( miniData[key].valid === true ) currentElement.addClass('done');
|
|
// Si elle est invalide
|
|
else currentElement.remClass('done');
|
|
|
|
}
|
|
|
|
|
|
|
|
/* (3) On séléctionne par défaut la dernière MINI fiche sélectionnée */
|
|
this.nav( $('[data-sublink="facebook"] #f_nav-mini [data-n="'+this.selected+'"]') );
|
|
};
|
|
|
|
|
|
/* [8] Vérification des données du formulaire
|
|
=========================================================*/
|
|
inputFacebookMini.prototype.check = function(miniData){
|
|
|
|
// 0. Si inconnu coché, on valide
|
|
if( miniData.unknown )
|
|
return true;
|
|
|
|
// 1. Le sexe est défini
|
|
if( miniData.sexe == '' )
|
|
return false;
|
|
// 2. Le métier est défini
|
|
if( miniData.studies == '.' )
|
|
return false;
|
|
// 3. L'age est définie
|
|
if( miniData.age == '.' )
|
|
return false;
|
|
// 4. La distance de localisation est définie
|
|
if( miniData.loc == '' )
|
|
return false;
|
|
// 5. Le TYPE DE RELATION a un et un seul choix
|
|
if( miniData.reltype == '' )
|
|
return false;
|
|
// 6. TYPE DE RELATION si autre est coché (indice 10), reltypeSpecial doit avoir au moins 2 caractère
|
|
if( miniData.reltype == '10' && miniData.reltypeSpecial.length < 2 )
|
|
return false;
|
|
|
|
|
|
// Si aucune erreur, tout est ok
|
|
return true;
|
|
};
|
|
|
|
|
|
/* [9] Point d'amorçage de la gestion des contacts
|
|
=========================================================*/
|
|
inputFacebookMini.prototype.attach = function(handler){
|
|
console.group('[facebook.mini] attaching events');
|
|
|
|
/* (1) On initialise le jeu de données */
|
|
lsi.createDataset('f_mini-fiches');
|
|
|
|
/* (2) On charge les mini fiches depuis la mémoire ('localStorage') */
|
|
this.storageToFields();
|
|
|
|
/* (3) On attache la barre de navigation à une fonction */
|
|
// On enregistre le handler
|
|
this.handler = handler;
|
|
|
|
/* (2) On attache l'évènement sur le conteneur de navigation */
|
|
this.nav_container.addEventListener('click', function(e){
|
|
// 1. On gère la navigation
|
|
this.nav(e.target);
|
|
// 2. On gere le chargement dynamique
|
|
this.handler(e.target);
|
|
}.bind(this), false);
|
|
|
|
|
|
console.groupEnd();
|
|
};
|