mercredi 24 décembre 2014

Gestion d'une palette flottante en Javascript


Il est possible en Javascript de gérer une fenêtre de type <palette flottante>.

Ce type de composant est très utile pour les applications / sites Web qui veulent se "rapprocher" des applications natives en termes de facilité de navigation et d'expérience utilisateur (IHM - Interface Homme - Machine).

Nous nous baserons sur JQuery, la célébre API.

Nous proposerons dans cet article une <palette flottante> qui peut s'afficher verticalement ou horizontalement.

  • Dans un premier temps, il faut choisir les icônes qui seront utilisés dans notre palette flottante.

Veuillez choisir des icônes qui "retranscrivent" les fonctionnalités que vous souhaitez mettre en oeuvre.

Il est conseillé d'utiliser la même largeur et hauteur pour tous les icônes afin de garantir un meilleur effet visuel.

Pour chaque icône, prévoir la version <over> (lorsque la souris passe sur l'icône).

Exemple : <outil.png> et <outil_over.png>

  • Veuillez ensuite initialiser JQuery dans votre page

<html>

<head>

<title>mon titre</title>

<link rel="stylesheet" type="text/css"
href="css/jquery-ui-x.x.x.custom.css" />

<script type="text/javascript" src="js/jquery-x.x.x.min.js"></script>

<script type="text/javascript" src="js/jquery-ui-x.x.x.custom.min.js"></script>

</head>

...

</html>

<x.x.x> = version de JQuery que vous utilisez.

Nous partons du principe que vous avez ajouté JQuery (JS + CSS) dans votre projet.

A NOTER : vous pouvez si vous le souhaitez customiser le style par défaut proposé par JQuery pour ses composants notamment les composants liés à notre <palette flottante>.

  • Déclaration de la <palette flottante> horizontale

Dans notre exemple, nous avons organisé les outils par groupe (<GROUPE1> et <GROUPE2>) avec deux outils par groupe.

Nous avons donc les fichiers <image> suivants : outil1.png, outil2.png, outil3.png et outil4.png ainsi que les versions <over> de ces fichiers.

Voici le script Javascript :

function affPaletteOutilsHorizontale() {
var dataHTML = "<table cellspacing='2' cellpadding='2' style='position: relative; left: -10px'>";

La première ligne de la <palette flottante> affiche le libellé des groupes

dataHTML += "<tr>";

dataHTML += "<thead>";
dataHTML += "<th style='color: white; background-color: darkgray; text-align: center;'><b>GROUPE 1</b></th>";
dataHTML += "<th style='color: white; background-color: darkgray; text-align: center;'><b>GROUPE 2</b></th>";
dataHTML += "</thead>";

dataHTML += "</tr>";

La deuxième ligne affiche les outils regroupés par groupe

  dataHTML += "<tr>";
 
  // partie GROUPE 1
  dataHTML += "<td>";
  dataHTML += "<table cellspacing='2' cellpadding='2'>";

  dataHTML += "<tr>";

dataHTML += "<td><img style='cursor: pointer;' id='outil1' " +
"onmouseover='mouse_over(\"outil1\");' onmouseout='mouse_out(\"outil1\");' " +
"onclick='go_outil1();' " +
"src='images/outil1.png' title=\"titre de mon outil 1 pour le groupe 1\" /></td>";

dataHTML += "<td><img style='cursor: pointer;' id='outil2' " +
  "onmouseover='mouse_over(\"outil2\");' onmouseout='mouse_out(\"outil2\");' " +
  "onclick='go_outil2();' " +
  "src='images/outil2.png' title=\"titre de mon outil 2 pour le groupe 1\" /></td>";

  dataHTML += "</tr>";
 
  dataHTML += "</table>";
  dataHTML += "</td>";

// partie GROUPE 2
  dataHTML += "<td>";
  dataHTML += "<table cellspacing='2' cellpadding='2'>";

  dataHTML += "<tr>";

dataHTML += "<td><img style='cursor: pointer;' id='outil3' " +
"onmouseover='mouse_over(\"outil3\");' onmouseout='mouse_out(\"outil3\");' " +
"onclick='go_outil3();' " +
"src='images/outil3.png' title=\"titre de mon outil 3 pour le groupe 2\" /></td>";

dataHTML += "<td><img style='cursor: pointer;' id='outil4' " +
  "onmouseover='mouse_over(\"outil4\");' onmouseout='mouse_out(\"outil4\");' " +
  "onclick='go_outil4();' " +
  "src='images/outil4.png' title=\"titre de mon outil 4 pour le groupe 2\" /></td>";

  dataHTML += "</tr>";
 
  dataHTML += "</table>";
  dataHTML += "</td>";

  dataHTML += "</tr>";
  dataHTML += "</table>";

Le titre de la <palette flottante> :

var lib_etiq = "<span style='position:relative; top: -10px; font-size: 12px;'><u>Outils</u>" +
"<span style='position: relative; top: 4px; left: 240px;'>" +
"<img id='vertical' src='images/swap.png' style='cursor: pointer' title='barre verticale' />" +
"</span></span>";

<swap.png> = outil qui permet de switcher en mode vertical - nous vous laissons le soin de choisir l'icône qui convient le mieux à la fonction

var fadeEffectDuration = 750;

<fadeEffectDuration> = délai avant l'affichage de la <palette flottante> par exemple 750 millisecondes.

  $(document).ready(function() {
  $dialog = $("<div style='background-color: #F2F2F2;'></div>").html(dataHTML).dialog( {
  autoOpen: true,
  closeOnEscape: false, 
  modal: false,

Vous avez noté que votre <palette flottante> peut être déplacée

    draggable: true,
  title: lib_etiq,
  width: 'YYYpx',
  height: 'auto',
  minHeight : 'YYYpx',
  show: {
         effect: "fade",
         duration: fadeEffectDuration
     },

Passer en mode <palette flottante> vertical si click sur <swap.png>

  open: function(event, ui) {
    $('#vertical').bind('click', function() {
    $dialog.dialog('close');
$dialog.dialog('destroy').remove();

  affPaletteOutils();
    });

Vous pouvez définir par défaut la position de votre <palette flottante>

        $(this).parent().css('position', 'fixed');
        $(this).parent().css('top', 'YYpx');
        $(this).parent().css('left', 'YYpx');

Cacher bouton "fermer" 

  $(this).parent().children().children(".ui-dialog-titlebar-close").hide(); 

Désactiver scrolling

  $(this).css('overflow', 'hidden');
  }
  });

Supprimer l'opacité

  $(".ui-widget-overlay").attr('style','opacity: 0;');

Centrer le titre

  $(".ui-dialog-title").attr('style','float:none !important; display: block; text-align: center; width: YYYpx;');

Modifier la hauteur du titre
  $(".ui-dialog-titlebar").attr('style','height: YYpx;');
  });
}

<Y> largeur, hauteur, position en pixels - valeur à définir selon vos besoins

  • Déclaration de la <palette flottante> verticale

Nous partons sur le même exemple que la <palette flottante> horizontale mais en vertical.

Cette <palette> pourra aussi se "collapser" (se réduire - seul le titre de la <palette> apparaîtra).

Voici le script Javascript :

var isCollapse = false;

<isCollapse> est un flag qui permet de tester si la <palette> est réduite ou pas.

function affPaletteOutils() {
var dataHTML = "<table cellspacing='2' cellpadding='2' style='position: relative; left: -10px'>";

  // partie GROUPE 1
dataHTML += "<tr><td colspan='2' style='color: white; background-color: darkgray; text-align: center;'><b>Groupe 1</b></td></tr>";
 
  dataHTML += "<tr>";

  dataHTML += "<td><img style='cursor: pointer;' id='outil1' " +
  "onmouseover='mouse_over(\"outil1\");' onmouseout='mouse_out(\"outil1\");' " +
  "onclick='go_outil1();' " +
  "src='images/outil1.png' title=\"mon titre pour outil1 pour groupe 1\" /></td>";
 
  dataHTML += "<td><img style='cursor: pointer;' id='outil2' " +
  "onmouseover='mouse_over(\"outil2\");' onmouseout='mouse_out(\"outil2\");' " +
  "onclick='go_outil2();' " +
  "src='images/outil2.png' title=\"mon titre pour outil 2 pour groupe 1\" /></td>";

  dataHTML += "</tr>";
 
dataHTML += "<tr style='height: 10px;'></tr>";

// partie GROUPE 2
dataHTML += "<tr><td colspan='2' style='color: white; background-color: darkgray; text-align: center;'><b>Groupe 2</b></td></tr>";
 
  dataHTML += "<tr>";

  dataHTML += "<td><img style='cursor: pointer;' id='outil3' " +
  "onmouseover='mouse_over(\"outil3\");' onmouseout='mouse_out(\"outil3\");' " +
  "onclick='go_outil3();' " +
  "src='images/outil3.png' title=\"mon titre pour outil3 pour groupe 2\" /></td>";
 
  dataHTML += "<td><img style='cursor: pointer;' id='outil4' " +
  "onmouseover='mouse_over(\"outil4\");' onmouseout='mouse_out(\"outil4\");' " +
  "onclick='go_outil4();' " +
  "src='images/outil4.png' title=\"mon titre pour outil 4 pour groupe 2\" /></td>";

  dataHTML += "</tr>";

  dataHTML += "<tr style='height: 10px;'></tr>";
 
  dataHTML += "</table>";

  var lib_etiq = "<span style='position:relative; top: -10px; font-size: 12px;'><u>Outils</u>" +
  "<span style='position: relative; top: 4px; left: 20px;'>" +
  "<span style='position: relative; top: -1px;'><img id='horizontal' src='images/swap.png' style='cursor: pointer' title='barre horizontale' /></span>&nbsp;" +
  "<img id='collapse' src='images/collapse.png' style='cursor: pointer' " +
  "title='r&eacute;duire ou agrandir la palette des outils !' /></span></span>";
 
<swap.png> = outil qui permet de switcher en mode horizontal - nous vous laissons le soin de choisir l'icône qui convient le mieux à la fonction

<collapse.png>  = outil qui permet de réduire la <palette flottante> à son strict minimum (son titre) - choisir l'icône qui convient le mieux à la fonction

  var fadeEffectDuration = 750;
 
<width_window> permet de positionner horizontalement la <palette> par défaut

var width_window = (window.innerWidth - YYY);
 
  $(document).ready(function() {
  $dialog = $("<div style='background-color: #F2F2F2;'></div>").html(dataHTML).dialog( {
  autoOpen: true,
  closeOnEscape: false, 
  modal: false,
    draggable: true,
  title: lib_etiq,
  width: 'YYYpx',
  height: 'auto',
  minHeight : 'YYYpx',
  show: {
         effect: "fade",
         duration: fadeEffectDuration
     },

Selon la valeur de <isCollapse> nous ajustons la hauteur de la <palette> - nous associons une petite animation pour plus de fluidité

  open: function(event, ui) {
    $('#collapse').bind('click', function() {
    if (isCollapse) {
    isCollapse = false;

    $(this).parents('.ui-dialog').animate({
    height: 'YYYpx'
            }, 200);
    }
    else  {
    isCollapse = true;
   
    $(this).parents('.ui-dialog').animate({
    height: 'YYpx'
              }, 200);
    }    
    });

    $('#horizontal').bind('click', function() {
    $dialog.dialog('close');
  $dialog.dialog('destroy').remove();
   
    affPaletteOutilsHorizontale();
    });
   
    $(this).bind( "dialogdragstop", function(event, ui) {
    if (isCollapse)
    $(this).parents('.ui-dialog').css('height', 'YYpx');
        });
     
  // position
        $(this).parent().css('position', 'fixed');
        $(this).parent().css('top', 'YYYpx');
        $(this).parent().css('left', width_window + 'px');
       
// cacher bouton "fermer" 
  $(this).parent().children().children(".ui-dialog-titlebar-close").hide(); 

  // désactiver scrolling
  $(this).css('overflow', 'hidden');
  }
  });

  // supprimer l'opacité
  $(".ui-widget-overlay").attr('style','opacity: 0;');

  // centrer le titre
  $(".ui-dialog-title").attr('style','float:none !important; display: block; text-align: center; width: YYpx;');
 
  // modifier la hauteur du titre
  $(".ui-dialog-titlebar").attr('style','height: YYpx;');
  });
  }

<Y> largeur, hauteur, position en pixels - valeur à définir selon vos besoins

  • Comment utiliser notre <palette flottante> ?

<body>
...
<?php
echo "<script>";
echo "affPaletteOutilsHorizontale();";
echo "</script>";
?>
...
</body>

Dans cet exemple nous lancons la <palette flottante> en mode horizontal lors de l'affichage de la page.

Une fois qu'elle est affichée, nous pouvons switcher entre le mode vertical et le mode horizontal avec la possibilité de réduire la <palette> en mode vertical.

Comment détecter un navigateur en PHP ?

Comment détecter en PHP le navigateur utilisé ?

Vous trouverez ci-joint un script fort utile.

function recupererBrowser()
{
$u_agent = $_SERVER['HTTP_USER_AGENT'];
$bname = 'Inconnu';
$platform = 'Inconnu';
$version= "";

if (preg_match('/linux/i', $u_agent)) {
$platform = 'linux';
}
elseif (preg_match('/macintosh|mac os x/i', $u_agent)) {
$platform = 'mac';
}
elseif (preg_match('/windows|win32/i', $u_agent)) {
$platform = 'windows';
}

if(preg_match('/MSIE/i',$u_agent) && !preg_match('/Opera/i',$u_agent))
{
$bname = 'Internet Explorer';
$ub = "MSIE";
}
elseif(preg_match('~MSIE|Internet Explorer~i', $u_agent) || (strpos($u_agent, 'Trident/7.0; rv:11.0') !== false)) {
$bname = 'Internet Explorer';
$ub = "MSIE";
}
elseif(preg_match('/Firefox/i',$u_agent))
{
$bname = 'Mozilla Firefox';
$ub = "Firefox";
}
elseif(preg_match('/Chrome/i',$u_agent))
{
$bname = 'Google Chrome';
$ub = "Chrome";
}
elseif(preg_match('/Safari/i',$u_agent))
{
$bname = 'Apple Safari';
$ub = "Safari";
}
elseif(preg_match('/Opera/i',$u_agent))
{
$bname = 'Opera';
$ub = "Opera";
}
elseif(preg_match('/Netscape/i',$u_agent))
{
$bname = 'Netscape';
$ub = "Netscape";
}

$known = array('Version', $ub, 'other');
$pattern = '#(?<browser>' . join('|', $known) .
    ')[/ ]+(?<version>[0-9.|a-zA-Z.]*)#';

$i = count($matches['browser']);

if ($i != 1) {
if (strripos($u_agent,"Version") < strripos($u_agent,$ub))
$version= $matches['version'][0];
else
$version= $matches['version'][1];
}
else
$version= $matches['version'][0];

if ($version==null || $version=="") {$version="?";}

return array(
        'userAgent' => $u_agent,
        'name'      => $bname,
        'version'   => $version,
        'platform'  => $platform,
        'pattern'    => $pattern
);
}

comment utiliser cette fonction ?

Cette fonction retourne un tableau  : son utilisation est donc simple.

Par exemple :

$browser = recupererBrowser();

if ($browser ['name'] == "Internet Explorer") {
    // faire quelque chose
}

dimanche 21 décembre 2014

Démarrer sur Swift ou Objective-C ?

Le nouveau langage SWIFT mis en avant par Apple il y a quelques mois a pour objectif (dans un délai plus au moins long) de remplacer le langage actuel des applications OS X / IOS à savoir Objective-C.

Apple a dans le passé déjà effectué ce type de "migration" technique avec un certain succès.

Les applications "publiées" (entre 1 à 2 millions) écrites en Objective-C ne seront pas toutes réécrites en SWIFT, c'est un fait.

Réécriture partielle en SWIFT ? réécriture totale en SWIFT ? ajout de nouvelles fonctionnalités en SWIFT ?

Nous aurons probablement tous les cas de figures.

Ce qui est sûr c'est qu'il va falloir maintenir toutes ces applications - encore de beaux jours en perspective pour le code en Objective-C.

Pour finir ce constat, SWIFT est un langage plus moderne et plus "robuste" (d'après Apple) que Objective-C.

SWIFT est donc en droit de prendre la suite et de s'imposer "naturellement" chez les développeurs.

Mais de l'aveu de certains développeurs, SWIFT restera quand même lié à Objective-C.

Mais les choses sont un peu plus compliquées lorsque nous devons faire réellement le choix entre ces deux langages ?

Apprendre un langage, le maîtriser est un investissement important et assez long.

Il n'y a pas une réponse simple à la question posée par cet article.

Nous allons examiner quelques aspects qui vous aideront à prendre une décision.


Le premier aspect à prendre en considération est la nature de votre activité : exercez-vous le développement dans un contexte particulier ou professionel ?

Nous sommes d'accord que les conséquences ne sont pas les mêmes.

  • Pour un particulier, apprendre SWIFT peut être très intéressant, sans réel impact économique, financier et professionnel.

Peut-être maîtrise t-il déjà Objective-C ?

Que du "bonus" !

Etant "dégagé" de la "pression" professionnelle, il peut acquérir des compétences dans un délai que lui seul fixe; compétences qui pourront au demeurant lui être utiles.

  • Pour un professionnel, ses compétences sont liées à son Curriculum Vitae, à sa "carte de visite"

Une compétence est "validée" au bout d'un certain temps (validation par applications publiées, expertise technique reconnue).

Lorsqu'elle est "validée", il a plutôt intérêt à asseoir son expertise et à la maintenir à niveau.

Acquérir une autre compétence est évidemment un plus très intéressant, nécessaire à tout développeur professionnel moderne mais doit être bien réfléchie.

Si le développeur débute dans l'environnement Apple, l'apprentissage de SWIFT est judicieux.

Il investit au moins sur les 5 prochaines années.

Ce qui ne l'empêchera pas (et c'est fortement conseillé) d'apprendre Objective-C dans un deuxième temps.

Si le développeur est déjà un développeur Objective-C, qu'il a publié des applications pour le compte de ses clients ou pour le compte des clients de son entreprise alors l'apprentissage de SWIFT peut se faire en "tâche de fond".

Il pourra ainsi progressivement acquérir des compétences en SWIFT, les appliquer à ces projets actuels, voire futurs.

Une double compétence est très appréciée.

En "tâche de fond" implique à la fois de se fixer une période "butoire" (délai raisonnable) pour l'apprentissage et de consacrer une partie réelle de notre activité à cet apprentissage.


Un deuxième aspect est le degré de facilité d'apprentissage entre Objective-C et SWIFT.

Pour beaucoup de développeurs Objective-C est plus "rapide" à apprendre que SWIFT.

D'autre part, la communauté mondiale Objective-C est importante offrant ainsi un support technique riche de plusieurs années de maîtrise et d'expériences.

Avoir accès à un support technique d'un langage qui existe depuis plusieurs années peut rassurer le développeur.

SWIFT étant plus moderne, il "embarque" des concepts certes plus concis et plus faciles à lire (code plus allégé) mais qui peuvent nécessiter un apprentissage plus approfondi et donc plus long.


Un dernier aspect est la possibilité qu'offre Apple de "mixer" ces deux langages.

Nous pouvons "aisément" faire cohabiter du code SWIFT avec du code Objective-C au sein d'une même application.

Analysez votre projet sous XCode

Cette fonctionnalité sous XCode est très importante et puissante.

Comme cela a déjà été dit dans un précédent article, un projet doit être analysé avant publication sur un App Store.

XCode intégre cette fonctionnalité, ce qui est très pratique nous n'avons pas besoin d'un outil externe.

Les résultats de l'analyse sont ainsi "affichés" dans XCode.

L'analyse est toujours liée à une application (ou à un projet).

Pour l'exécuter, cliquez dans le menu <Product> / <Analyze>.

L'analyse ainsi effectuée va permettre par exemple de détecter les <memory leaks> ("fuite" de mémoire - très important si votre application gére manuellement les allocations <mémoire>).

Les <memory leaks> peuvent apparaître en cours d'utilisation de votre application et sont quelque fois difficile à trouver, à recréer et donc à résoudre.

Ce type d'erreur (potentielle) doit être traitée sans tarder.

L'analyseur de XCode vous prévient du risque éventuel.

Cette analyse va aussi vous avertir des Ivars non utilisées, des <dead code> (code non utilisé), des fonctions obsolètes.

A vous de juger quelles sont les warnings / erreurs importantes et de les traiter.

Bien d'autres classes d'erreurs sont traitées, en voici une liste :


Vous pouvez demander à XCode d'effectuer l'analyse de votre projet à chaque Build (<Build settings> / <Analyze during "Build">) :


Android Studio Mac : conseils d'installation

Lorsque nous installons Android Studio version Mac pour la première fois, quelques erreurs peuvent apparaître.

Par définition les développeurs n'aiment pas les erreurs - autant partir sur une base "saine".

Par exemple une erreur sur une version du JDK Java non installée.

OS X n'installe plus depuis un certain temps les dernières versions du JDK Java - c'est donc à la charge de l'utilisateur de le faire.

Vous devez donc vous assurer que le bon JDK Java soit installé et que le <SDK Location> "pointe" bien sur ce JDK.

Pour la plateforme Android 5 (Lollipop) par exemple le JDK 7 est requis.

Autre erreur : lorsque Gradle (outil d'automation du build de votre application) est exécuté, ce message peut aussi apparaître :

"Gradle : No resource found that matches the given name ..."

En général vous pouvez avoir une centaine d'erreurs de ce type.
Pour résoudre ce problème, cliquez dans un premier temps sur le SDK Manager    et vérifiez que les composants ci-dessous soient installés :



Ensuite quelques modifications dans les propriétés de votre <App> (<open Module settings>).

Dans l'onglet "Properties", veuillez choisir comme <compile SDK version> la dernière version du build d'Android.



Il n'est pas obligatoire de changer la version du SDK pour la <target> de votre application (onglet "Flavors") mais il est recommandé de choisir la dernière version du build d'Android.



Vous pouvez faire la même chose en modifiant directement le fichier <build.gradle>.

Une fois ces modification appliquées, synchronisez votre projet à nouveau.

vendredi 19 décembre 2014

Alerte sur espace disponible d'une base de données SQL Server

Ce script TRANSACT / SQL ci-dessous va vous permettre de "surveiller" l'espace disponible de votre base de données et de vous alerter par mail si le "seuil" minimal est atteint.

Nous utiliserons le mail manager propre à SQL Server.

Vous pouvez "encapsuler" cette requête dans un Job SQL Server avec une planification associée.

Voici le script :

FOR READ ONLY 

DECLARE @database_name sysname 

OPEN db_cur 
FETCH NEXT FROM db_cur INTO @database_name 
WHILE @@fetch_status = 0 
BEGIN 
  DELETE  @database_file_space 

  SET @exec_sql = 'EXEC ' + @database_name + '.dbo.sp_executeSQL N''' + @sql + '' 

  BEGIN TRY 
    INSERT  @database_file_space 
    EXEC  (@exec_sql) 
  END TRY 
  BEGIN CATCH 
    PRINT @database_name + ' : ' + ERROR_MESSAGE() 
  END CATCH 
  
  INSERT  @instance_database_file_space 
  SELECT  @database_name 
    , file_logical_name 
    , file_physical_name 
    , file_growth 
    , file_size_MB 
    , file_used_space_MB 
    , file_size_MB - file_used_space_MB AS file_free_space_MB 
    , CAST((CAST(file_used_space_MB AS numeric(14, 2)) / file_size_MB) * 100 AS numeric(14, 2)) AS file_used_space_percent 
    , CAST((CAST(file_size_MB - file_used_space_MB AS numeric(14, 2)) / file_size_MB) * 100 AS numeric(14, 2)) AS file_free_space_percent 
  FROM  @database_file_space 

  WHERE file_logical_name  = 'ma_base'

  FETCH NEXT FROM db_cur INTO @database_name 
END 
CLOSE db_cur 
DEALLOCATE db_cur 

-- xx exprimé en MB

if exists ( 
SELECT  *
FROM  @instance_database_file_space WHERE file_free_space_MB <= xx
)
BEGIN
exec msdb.dbo.sp_send_dbmail
@profile_name = 'mon_profil_mail',
@recipients = 'mon_adresse_mail_en_copie',
@body = 'mon text',
@subject = 'mon sujet',
@body_format = 'TEXT';
END

Requête pour lister les tables en SQL SERVER

Il est possible par l'intermédiaire d'une requête de lister les tables que vous avez créé dans votre base de données SQL Server.

Sont exclues bien évidemment de cette requête les tables systèmes propres à SQL Server.

Vous noterez au passage les informations extraites, par exemple le nombre d'occurences d'une table.

Voici la requête :

SELECT 
    t.NAME AS TableName,
    --i.name as indexName,
    p.[Rows],
    sum(a.total_pages) as TotalPages, 
    sum(a.used_pages) as UsedPages, 
    sum(a.data_pages) as DataPages,
    (sum(a.total_pages) * 8) / 1024 as TotalSpaceMB, 
    (sum(a.used_pages) * 8) / 1024 as UsedSpaceMB, 
    (sum(a.data_pages) * 8) / 1024 as DataSpaceMB
FROM 
    sys.tables t
INNER JOIN      
    sys.indexes i ON t.OBJECT_ID = i.object_id
INNER JOIN 
    sys.partitions p ON i.object_id = p.OBJECT_ID AND i.index_id = p.index_id
INNER JOIN 
    sys.allocation_units a ON p.partition_id = a.container_id
WHERE 
    t.NAME NOT LIKE 'dt%' AND
    i.OBJECT_ID > 255 AND   
    i.index_id <= 1
GROUP BY 
    t.NAME, i.object_id, i.index_id, i.name, p.[Rows]
ORDER BY 
    --object_name(i.object_id) 
p.[Rows] desc

PHP : générer du PDF

La génération de fichiers PDF est un sujet assez récurrent.

Les applications / site WEB ont très souvent besoin de générer de tels fichiers.

Il existe de nombreuses API qui permettent à partir d'une page PHP de générer un fichier PDF.

Celle qui nous intéresse dans cet article est FPDF.

L'intégration de cette API dans votre application est simple : copier le répertoire<FPDF> téléchargé dans votre projet.

En résumé :

  • Initialisation de notre document PDF dans votre page PHP

// nouveau document
$pdf = new FPDF();

// ajouter une page à votre document
$pdf->AddPage();

  • Ajoutons un entête à notre document

// insertion d'une image => attention uniquement des JPEG
$pdf->Image('images/mon_image.jpg',10,10);

// utilisation police Arial en Bold et 10 points de corps
$pdf->SetFont('Arial','B',10);

// on se positionne à partir du top de page : 5 en ordonnée Y => on travaille en ordonnées non en pixels !
$pdf->SetY(5);

// une ligne en format A4 fait 180 mm : on peut ainsi découper la ligne en "cellules" comme sous  EXCEL
// dans cet exemple le titre (corps 13 points) est centré à droite avec une bordure (Left, Top, right)
$pdf->Cell(180,13,"Mon titre","LTR",0,"C");

Nous partons du <Top> du document vers le <Bottom>.

  • Ajoutons le corps du document

...

// insertion d'un saut de ligne : dans notre exemple la taille du saut de ligne est de 4 en ordonnée
$pdf->Ln(4);

// dans cet exemple on affiche deux textes différents sur la même ligne
$pdf->SetFont('Arial','',10);
$pdf->Cell(90,10,"mon texte 1 ",0,0,"C");
$pdf->SetFont('Arial','B',10);
$pdf->Cell(90,10,"mon texte 2",0,0,"C");

$pdf->Ln(5);

....

A noter : nous pouvons soit nous positionner en ordonnée Y (fonction SetY), soit effectuer des sauts de ligne (les sauts de ligne sont toujours effectués à partir de la position Y courante).

Vous pouvez dans votre document ajouter un pied de page sur le même principe.

  • Générer le document PDF

$pdf->Output("mon_doc.pdf",'F');

Le fichier est généré sur votre serveur.

Cette API permet de couvrir la plupart des besoins, même de générer des documents assez complexes.

Le document est vierge, à vous de gérer l'entête, le corps et le pied de page.

jeudi 18 décembre 2014

Comment supprimer le contenu de iCloud sous XCode ?


Le menu <Debug> inclut désormais depuis XCode 5 un sous - menu "iCloud".

Il comporte deux options qui ont pour objectif de faciliter le développement sous iCloud.

La deuxième option nous intéresse dans cet article : "Delete Container Contents".

“Delete Container Contents” permet de supprimer tous les documents et données dans le containeur iCloud d'une application (et plus précisement de l'application courante).

Cette option peut être utile lorsque vous testez de votre application.

Par contre une fois supprimé, le contenu ne peut pas être restauré - soyez donc vigilant !

A noter : supprimer le contenu du containeur iCloud d'une application va "naturellement" affecter tous les Devices qui ont iCloud activé et qui sont associés à cette application. 

PHP / Logging : indispensable !


Tout développeur qui se respecte doit à un moment donné logger des informations que cela soit dans un but informatif ou de "debug".

Ces informations loggées sont redirigées vers la sortie standard par exemple ou vers un fichier (nous parlons dans ce cas de fichier LOG).

Dans un contexte WEB où tester un site / application est assez difficile, le fichier LOG prend alors une autre dimension.

Il devient un outil complémentaire très intéressant et surtout très utile pour tester vos applications.

Il existe de nombreuses API de type LOG : nous allons nous intéresser à l'une d'entre elles.

Son intégration dans une application est très simple : c'est une unique classe PHP (Logger.class.php).

A noter que cette classe fonctionne uniquement en PHP 5.

Vous trouverez ci-joint le source ainsi que de nombreux exemples d'utilisation de cette classe.

En résumé :

$logger = new Logger('./log');

Nous instancions la classe.

Au préalable, il faut créer un répertoire (par exemple /log) qui contiendra vos fichiers LOG.

$logger->log('mon_repertoire', "mon_fichier_log", $information, Logger::GRAN_MONTH);

<mon_repertoire> = répertoire "parent" qui va contenir votre fichier LOG

<mon_fichier_log> = votre fichier log formaté d'une certaine façon

Exemple de fichier LOG :

02/12/2014 10:21:38 mon information...

<$information> = String PHP qui contient l'information à logger

<GRAN_MONTH> = niveau de granularité que vous souhaitez - dans cet exemple regroupement par mois (création d'un sous - répertoire "mois" dans le répertoire "parent", lequel contiendra votre fichier LOG)

Nous avons donc une API simple, assez paramétrable qui vous rendre bien des services.

Publication sur Mac App Store : quelques conseils !


Avant de soumettre (et de publier) votre application sur le Mac App Store, il est nécessaire de prendre quelques précautions.

  • La première précaution (qui est peut être la plus importante) : vérifier que toutes les fonctionnalités de votre application fonctionnent correctement !

Cela peut sembler évident mais dans les faits, vous pouvez avoir quelques surprises.

Ayez à l'esprit que lors de la REVIEW de votre application par Apple, tout ce qui est "visible" dans votre application sera testé.

Ce qui est un peu normal car les équipes Apple ne sont pas censées connaître tous les métiers - ils vont donc favoriser les tests IHM.

Par exemple si vous avez des palettes d'outils, soyez certains que la personne en charge de tester votre application va "cliquer" sur chaque outil.

Le conseil qui peut être donné est d'effectuer votre propre REVIEW avant publication.


  • Développez, testez et packagez votre application sur la dernière version officielle de OS X et de XCode

Il est important d'être à jour avec les outils système et de développement officiels (sont exclus les outils en BETA version).

Les tests de votre application peuvent fonctionner sur une version précédente des outils et non sur la nouvelle version - nous sommes dans ce cas dans une phase de régression.

Partez du principe que les équipes Apple travaillent avec les dernières versions des outils et c'est sur ces versions que seront effectués les tests de la REVIEW.


  • Faites une pré - soumission de votre application

Il est possible de faire une pré - soumission sous XCode avant publication finale.

Cette pré - soumission permet de valider "techniquement" l'archive qui va être utilisée pour la publication.

C'est une étape importante qui ne doit pas être négligée.


  • Vérifier le délai de la REVIEW des applications

Même si le délai moyen d'une REVIEW s'est bien amélioré depuis quelques années, il n'en demeure pas moins que ce délai doit être pris en compte.

Cet outil vous donne un aperçu du délai moyen constaté.

Prenez en compte ce délai dans votre planning.

Pour rappel, une REVIEW de votre application ne signifie pas systèmatiquement qu'elle va être approuvée (et donc publiée).

Prévoyez aussi un délai pour d'éventuelles corrections et re-soumissions (avec REVIEW) de votre application.

mardi 16 décembre 2014

CSS : trucs et astuces partie 2


Comment customiser par exemple les composants <Radio Bouton> et <Check Box> en CSS ?

Dans un premier temps, prenons 2 fichiers <image> : le premier (fich1.png) pour les composants qui ne sont pas <DISABLED> et le deuxième (fich2.png) pour les composants qui sont <DISABLED> :



Pour une meilleure "visibilité" IHM nous vous conseillons d'affecter à chaque composant la même largeur et la même hauteur (dans notre exemple 19px * 19px).

Considérons maintenant la partie CSS

input[type="radio"] {
display: none;
}

input[type="radio"]+label {
color: black;
font-family: Tahoma;
font-size: 10px;
}

input[type="radio"]+label span {
display: inline-block;
width: 19px;
height: 19px;
margin: -1px 4px 0 0;
vertical-align: middle;
background: url(fich1.png) -38px top no-repeat;
cursor: pointer;
}

input[type="radio"]:checked+label span {
background: url(fich1.png) -57px top no-repeat;
}

input[type="radio"]:disabled:checked+label span {
background: url(fich2.png) -57px top no-repeat;
}

input[type="radio"]:disabled:not               (:checked               )
+label span {
background: url(fich2.png) -38px top no-repeat;
}

input[type="checkbox"] {
display: none;
}

input[type="checkbox"]+label {
color: black;
font-family: Tahoma;
font-size: 10px;
}

input[type="checkbox"]+label span {
display: inline-block;
width: 19px;
height: 19px;
margin: -1px 4px 0 0;
vertical-align: middle;
background: url(fich1.png) 0px top no-repeat;
cursor: pointer;
}

input[type="checkbox"]:checked+label span {
background: url(fich1.png) -19px top no-repeat;
}

input[type="checkbox"]:disabled:checked+label span {
background: url(fich2.png) -19px top no-repeat;
}

input[type="checkbox"]:disabled:not  (:checked ) +label span {
background: url(fich2.png) 0px top no-repeat;
}

Vous noterez comment nous nous positionnons sur chaque <image> (nous partons de la gauche vers la droite en utilisant un offset négatif ou à zéro).

Nous utilisons une balise <Label> pour gérer "proprement" le texte du composant.

Comment utiliser ces composants customisés ?

<Radio Bouton> :

<input id='rd1' name='rd' value='1' type='radio' checked='checked'><label for='rd1'><span>text de mon radio button 1</span></label>

<input id='rd2' name='rd' value='2' type='radio'><label for='rd2'><span>text de mon radio button 2</span></label>

<Check Box> :

<input id='ck1' value='100' type='checkbox' checked='checked' onclick='ma_fonction();'><label for='ck1' title='mon titre'><span>mon texte</span></label>