/* [0] Constructeur -> définit le conteneur et le bouton d'ajout =========================================================*/ function inputPhoneMini(container, navContainer){ this.container = container; this.nav_container = navContainer; } /* [1] Attributs =========================================================*/ inputPhoneMini.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 =========================================================*/ inputPhoneMini.prototype.fieldsToStorage = function(){ console.group('[phone.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="phone"] 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('p_mini-fiches', deflated.uid); // Si erreur, on passe à la fiche suivante if( existingData === false ) 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['hash'] != undefined && 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('p_mini-fiches', obj.uid, obj); } console.groupEnd(); }; /* [3] Gestion de l'ajout physique d'un nouveau contact =========================================================*/ /* * * @objectData Objet contenant les informations nécessaires à l'affichage * */ inputPhoneMini.prototype.add = function(objectData){ // console.log('MINI FICHE: ADD'); // 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('p_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('p_friends', associatedContact.existing); // On récupère les données communes associatedContact.username = existingData.name; objectData.contact = associatedContact.uid; 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 += pMiniFicheBuilder.build({ name: associatedContact.username, countcall: associatedContact.countcall, countsms: associatedContact.countsms, uid: objectData.uid, reltypespecial: objectData.reltypeSpecial }); /* {3} On sélectionne la valeur dans le select (manuellement) de la PROFESSION */ var selectedOption = $('[data-sublink="phone"] 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="phone"] 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 pour le SEXE */ var sexeCreated = $$('[data-sublink="phone"] 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 pour le TYPE DE RELATION */ var reltypeCreated = $$('[data-sublink="phone"] 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 pour la LOCATION */ var locCreated = $$('[data-sublink="phone"] 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="phone"] 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' =========================================================*/ inputPhoneMini.prototype.storageToFields = function(){ console.group('[phone.mini] storage to fields'); /* (1) On charge le contact selectionné ---------------------------------------------------------*/ var miniData = lsi.export('p_mini-fiches'); var miniKeys = lsi.keys('p_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('p_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 =========================================================*/ inputPhoneMini.prototype.sync = function(){ console.group('[phone.mini] synchronisation'); /* (1) On récupère les clés de tous les CONTACTS */ var contactData = lsi.export('p_contacts'); var ficheData, miniData; /* (2) On enregistre les contacts qui ne sont pas déja dans les FICHES */ ficheIndexes = lsi.keys('p_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('p_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('p_mini-fiches', uid, miniData); } /* (9) On met à jour la mini-fiche en cours */ miniData = lsi.export('p_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 =========================================================*/ inputPhoneMini.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 != 'p_nav-mini' ) return false; /* (2) On désactive tous les éléments actifs */ var activeElements = $$('[data-sublink="phone"] #p_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 =========================================================*/ inputPhoneMini.prototype.updateNavBar = function(){ var miniData = lsi.export('p_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 += ''+(++i)+''; /* (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="phone"] #p_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="phone"] #p_nav-mini [data-n="'+this.selected+'"]') ); }; /* [8] Vérification des données du formulaire =========================================================*/ inputPhoneMini.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 =========================================================*/ inputPhoneMini.prototype.attach = function(handler){ console.group('[phone.mini] attaching events'); /* (1) On initialise le jeu de données */ lsi.createDataset('p_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(); };