Get window/viewport/document height and width [JavaScript]

Via andylangton and james.padolsey we can find the viewport and document height/width in JavaScript:

function getPageSize() {
  var vw = {width:0, height:0};
  var doc = {width:0, height:0};
  var w=window, d=document, dde=d.documentElement, db=d.getElementsByTagName('body')[0];
  
  // viewport size
  vw.width  = w.innerWidth||dde.clientWidth||db.clientWidth;
  vw.height = w.innerHeight||dde.clientHeight||db.clientHeight;

  // document size
  doc.width  = Math.max(db.scrollWidth, dde.scrollWidth, db.offsetWidth, dde.offsetWidth, db.clientWidth, dde.clientWidth);
  doc.height = Math.max(db.scrollHeight, dde.scrollHeight, db.offsetHeight, dde.offsetHeight, db.clientHeight, dde.clientHeight);
  
  // if IE8 there is a bug with 4px
  if (!!(document.all && document.querySelector && !document.addEventListener) && (vw.width+4 == doc.width) && (vw.height+4 == doc.height)) {
    vw.width=doc.width;
    vw.height=doc.height;
  }
  
   return {vw:vw, doc:doc};
}

getPageSize(); // -> {vw: { width:xxx, height:xxx }, doc: { width:xxx, height:xxx } }

It should work for IE8-IE10 and all modern browsers.

Autosize a text to fit into a div in pure/native JavaScript

I was looking for a very tiny and light solution to fit a text inside a box. The box’ height and width are fixed. I only found some great solutions like BigText but I didn’t want to have jQuery loaded.

Finally I found some code on StackOverflow and also at Coderwall. I created my own solution that could only work with my own HTML code… but I share it here, maybe that could help someone else.

The HTML code:

  
This is my text !

The related CSS code:

.ribbon-front { overflow:hidden }

And the JavaScript code:

var autoSizeText = function(selector) {
  "use strict";
  var el, elements, i, len, style, fontSize, IEoffsetHeight;
  elements = document.querySelectorAll(selector);
  if (elements.length <= 0) return;
  
  for (i=0, len = elements.length; i < len; i++) {
    el = elements[i];

    // we start from 0px and we grow by 0.5 until the content is too large
    fontSize=0;
    el.style.fontSize = "0px";
    // fix for all IE : I cache the offsetHeight, and if it becomes really bigger than the previous value, then we stop!
    IEoffsetHeight = el.offsetHeight;
    // check if our content is out its box
    while (el.scrollHeight===0 || el.scrollHeight >= el.offsetHeight) {
      fontSize += 0.5;
      el.style.fontSize = fontSize + 'px';

      if (el.offsetHeight - IEoffsetHeight > 10) break;
      IEoffsetHeight = el.offsetHeight;
    }
    el.style.fontSize = (fontSize - 0.5) + 'px';
  }
};
autoSizeText('.ribbon-front > span');

It works for IE8-IE10 and with all modern browsers.

You can see a demo at codepen.

Ajouter « nocaptcha reCaptcha » de Google à Guiform sous WordPress [Astuce]

J’utilise GuiForm pour faire des formulaires dans un WordPress, et je voulais y ajouter le captcha de Google sans pour autant devoir payer la licence chère de GuiForm juste pour ça…

Pour réussir ce que je décris ci-dessous, il vous faudra connaitre votre clé privée et publique de Google Captcha.

Il faut commencer par faire son formulaire (de contact dans mon cas) avec tous les champs voulus via GuiForm, puis on ajoute un champ de type « Heading » avec comme contenu « captcha ». On sauvegarde le formulaire.

Maintenant dans le fichier functions.php de votre thème il faut rajouter :

// on veut rajouter un captcha dans le formulaire de contact
// pour ça on surcharge 'guiform_render_form' qui est appelé par le plugin
function addCaptchaToGuiForm($content) {
  // on va remplacer "<h1>captcha</h1>" par ce qu'il faut
  $content = str_replace("<h1>captcha</h1>", "<div class='g-recaptcha' style='float:right' data-sitekey='VOTRE_CLE_PUBLIQUE' data-theme='light'></div><script src='https://www.google.com/recaptcha/api.js'></script>",$content);
  // on rajoute aussi du JavaScript
  $content .= '<script>'."\r\n".
              "function waitForjQuery() {"."\r\n".
              "  if (typeof jQuery === 'undefined') { setTimeout(waitForjQuery, 50); return }"."\r\n".
              "  var submit = jQuery('.f_submit');"."\r\n".
              "  var html = '<div class=\"'+submit[0].className+'\">'+submit.html()+'</div>';"."\r\n".
              "  submit.before(html).find('button').hide().prop('disabled', true);"."\r\n".
              "  var cloneSubmit = jQuery('.f_submit:first');"."\r\n".
              "  cloneSubmit.on('click', function(event) {"."\r\n".
              "    event.preventDefault();"."\r\n".
              "    jQuery.ajax({"."\r\n".
              "      type: 'GET',"."\r\n".
              "      url: '/wp-content/themes/VOTRE_THEME/checkCaptcha?response='+grecaptcha.getResponse(),"."\r\n".
              "      success: function(data) {"."\r\n".
              "        if (data['success'] === true) {"."\r\n".
              "          jQuery('.f_submit:first').remove()"."\r\n".
              "          jQuery('.f_submit').find('button').prop('disabled',false).show().last().trigger('click');"."\r\n".
              "        }"."\r\n".
              "        else if (data['error-codes']) {"."\r\n".
              "          switch (data['error-codes'][0]) {"."\r\n".
              "            case 'missing-input-secret': "."\r\n".
              "            case 'invalid-input-secret': alert('Erreur : impossible de vérifier le système anti-spam.'); break;"."\r\n".
              "            case 'missing-input-response': "."\r\n".
              "            case 'invalid-input-response': "."\r\n".
              "            default: alert('Erreur : vous devez répondre à l\'anti-spam.');"."\r\n".
              "          }"."\r\n".
              "        }"."\r\n".
              "      },"."\r\n".
              "      dataType: 'json'"."\r\n".
              "    });"."\r\n".
              "  })"."\r\n".
              "}"."\r\n".
              "waitForjQuery();"."\r\n".
              "</script>";
  return $content;
}
add_action('guiform_render_form', 'addCaptchaToGuiForm');

Grâce à cette astuce on modifie notre <h1>captcha</h1> par le code de Google. On ajoute un soupçon de JavaScript qui va permettre de cacher le vrai bouton « Submit ». Lorsqu’on va cliquer sur le faux bouton, le catpcha va être vérifié. Une fois fait le formulaire classique peut-être utilisé.

Attention : dans le code ci-dessus il faut remplacer VOTRE_CLE_PUBLIQUE et VOTRE_THEME par les valeurs correspondantes.

Enfin on a besoin de créer un fichier PHP à la racine de notre thème, qui va s’appeler checkCaptcha.php et qui aura comme contenu :

<?php
$url = "https://www.google.com/recaptcha/api/siteverify?secret=VOTRE_CLE_PRIVEE&response=".$_GET["response"];
$curl = curl_init($url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
$output = curl_exec($curl);
curl_close($curl);
echo $output;
?>

Attention : dans le code ci-dessus il faut remplacer VOTRE_CLE_PRIVEE par la valeur correspondante.

Activer la compression gzip / deflate sur 1and1 [Astuce]

Ayant un WordPress chez 1and1 j’ai voulu activer la compression de mes pages. Après avoir longuement cherché de partout, j’ai trouvé comment procéder, et ce n’est vraiment pas simple…. En effet, il va falloir faire passer tous nos fichiers (js, css, html, …) par PHP afin qu’ils soient compressés à la volée.

Chemin d’accès complet

Il nous faut le chemin d’accès complet chez 1and1. Pour cela on va mettre un fichier temporaire à la racine de notre site qui se nomme info.php dans lequel on inscrit :

<?php
phpinfo();
?>

On accède à cette page via un navigateur pour avoir toutes les informations liées à PHP. On y cherche la ligne qui correspond à DOCUMENT_ROOT afin de trouver le chemin d’accès complet de notre site ; par exemple /kunden/homepages/25/d3506178849/htdocs/clickandbuilds/WordPress/.

Supprimer le fichier info.php.

Création du prepend file

Maintenant on crée un nouveau fichier à la racine de notre site qui se nomme headers.php dans lequel on met :

<?php
$pathinfo=pathinfo($_ENV['SCRIPT_FILENAME']); 
$extension=$pathinfo['extension']; 
switch ($extension) {
  case 'css':
    $contentType = 'text/css';
    break;
  case 'js':
    $contentType = 'application/x-javascript';
    break;
  case 'xml':
    $contentType = 'text/xml';
    break;
  default:
    $contentType = 'text/html';
    break;
}
header("Content-type: ".$contentType);
// pour vérifier que notre script est bien exécuté
header("X-Homemade-Compression: OK");
?>

Ce fichier va être appelé pour chaque page et va permettre d’envoyer le bon Content-Type.

Fichiers .htaccess et php.ini

Maintenant, cela se complique car il va falloir repérer où se situent toutes les ressources que l’on souhaite compresser. Dans le cas de WordPress, il devrait y avoir :

  • /wp-includes/js/jquery/*
  • /wp-content/themes/votretheme/*

On peut aussi inclure les éventuels répertoires des plugins, et toutes autres ressources.

On se crée un fichier php.ini :

; Server side compression
zlib.output_compression=on
zlib.output_compression_level=9
; tous les fichiers seront parsés par le script headers.php afin d'envoyer le bon Content-Type
auto_prepend_file=/kunden/homepages/25/d3506178849/htdocs/clickandbuilds/WordPress/headers.php

On se crée aussi un fichier .htaccess en y mettant :

AddType x-mapp-php5 .html .htm .css .js .php

Pour que la compression fonctionne sans créer de problème, il va falloir envoyer ces deux fichiers dans chaque répertoire des ressources que l’on souhaite compresser. Par exemple dans /wp-content/themes/votretheme/js/ pour que les fichiers JS du thème soient impactés.

Vous pouvez aussi mettre php.ini à la racine de votre site web, mais sans utiliser le .htaccess de ci-dessus afin d’éviter des problèmes avec l’admin.

On teste

Enfin vous pouvez tester si tout est correct grâce à curl sous Linux :
curl -I -H 'Accept-Encoding: gzip,deflate' --head http://votresite/votreressource.js

Vous devriez voir apparaitre :

X-Homemade-Compression: OK
Content-Encoding: gzip

Gérer les évènements touch sur mobile [JavaScript]

J’ai un projet sur lequel j’ai deux évènements « mouseenter » et « mouseleave » gérés par jQuery (pour faire le « hover »), et je voulais un comportement similaire sur mobile. Pour ce faire, je voulais qu’un « tap » affiche ce que le « hover » affiche avec la souris, puis qu’un second « tap » permette d’accéder au contenu (comme un « clic »). La solution était assez simple, mais j’ai été ensuite confronté au problème du « scroll »…. en effet il confondait le « scroll » avec un « tap ».

Pour empêcher ce comportement, il faut tester si on effectue un « scroll » en s’aidant de $(window).scrollTop():

var scrollPos=0;
$('#elem').on('mouseenter', function() {
  // affiche quelque chose quand la souris est sur la zone
  $(this).addClass('hover');
}).on('mouseleave', function() {
  // cache le contenu lorsque la souris n'est plus dans la zone
  $(this).removeClass('hover');
}).on('touchstart', function(event) {
  // lorsqu'on tape avec son doigt on doit récupérer la position dans la page
  scrollPos=$(window).scrollTop();
}).on('touchend', function(event) {
  event.preventDefault();
  // puis ici on vérifie que ce n'est pas un scroll
  if(Math.abs(scrollPos - $(window).scrollTop()) < 3){
    // si on entre là dedans c'est qu'on a bien effectué un simple "tap"
    var $this=$(this);
    if ($this.hasClass('hover')) {
      // effectue l'action de clic liée à ce bloc ... c'est donc le second "tap"
    } else {
      // effectue la même opération que lorsque la souris est dans la zone
      $this.addClass('hover');
    }
  }
});

Permettre à aux utilisateurs phpBB de prévisualiser les styles du forum

Afin d’offrir une version mobile d’un forum phpbb aux utilisateurs, j’ai cherché comment ils pourraient basculer vers le style/thème mobile du forum juste en ajoutant « ?style=X » dans l’URL.

Normalement cette option n’est offerte qu’à l’administrateur du forum, mais pour l’ouvrir à tous il suffit de modifier le fichier includes/session.php en remplaçant :

if (!empty($_GET['style']) && $auth->acl_get('a_styles') && !defined('ADMIN_START'))

Par :

if (!empty($_GET['style']) && !defined('ADMIN_START'))

Et le tour est joué.

Extraire une image d’un PDF [Astuce]

Pour extraire une image d’un PDF vous pouvez utiliser Photoshop…. ou Gimp ! Ce logiciel gratuit permet également d’extraire une image d’un PDF. Il suffit d’ouvrir le document PDF avec Gimp et il va vous proposer de choisir l’image à extraire.

Simple et efficace.

How to expand Sharepoint 2010 calendar by default [JavaScript]

This code has been tested for Sharepoint 2010 only. It permits to expand by default (so as soon as the page is loaded) the events in the Month calendar view.

See here a solution for Sharepoint 2013.

Tested with IE8 and Firefox 34. You’ll have to add the below JavaScript code into your calendar page:

// the below function simulate a click on a link
function fireEventClick(elem){
    if(document.createEvent){                                                 
      var e = document.createEvent('MouseEvents');
      e.initMouseEvent('click', /* Event type */
      true, /* Can bubble */
      true, /* Cancelable */
      document.defaultView, /* View */
      1, /* Mouse clicks */
      0, /* Screen x */
      0, /* Screen y */
      0, /* Client x */
      0, /* Client y */
      false, /* Ctrl */
      false, /* Alt */
      false, /* Shift */
      false, /* Meta */
      0, /* Button */
      null); /* Related target */
      elem.dispatchEvent(e);                     
    } else { // pour IE
      elem.click();
    }
}

// wait for all the events to be loaded
_spBodyOnLoadFunctionNames.push('changeCalendarEventLinkIntercept');
function changeCalendarEventLinkIntercept() {
  var OldCalendarNotify4a = SP.UI.ApplicationPages.CalendarNotify.$4b;
  SP.UI.ApplicationPages.CalendarNotify.$4b = function () {
    OldCalendarNotify4a();
    // here all the events are loaded so we can expand them
    setTimeout(function() {
      ExpandEvents(0)
    }, 250)
  }
}

// Expand the events
// because Sharepoint redraw ALL the events when we click on Expand, then we need a special recurrent function
function ExpandEvents(idx) {
  var a = document.querySelectorAll('a[evtid="expand_collapse"]');
  if (idx < a.length) {
    if (a[idx].parentNode.getAttribute("_expand") !== "collapse") fireEventClick(a[idx]);
    ExpandEvents(++idx);
  }
}
ExpandEvents(0)

Breadcrumb / steps in CSS that works from IE8 [CSS]

I was looking for a simple code for a step by step process indicator. I found a few things, but everyone seems to have forgotten about IE8… I need to support this old browser at work. So I did my own that I’m sharing here:

  • File Uploaded
  • File Reviewed
  • File Approved

And the code:

<ul class="steps">
  <li class="step complete">File Uploaded</li>
  <li class="arrow">→</li>
  <li class="step current">File Reviewed</li>
  <li class="arrow">→</li>
  <li class="step">File Approved</li>
</ul>
<style>
body {
  counter-reset:steps
}
ul.steps {
  margin:0;
  padding:0;
}
ul.steps li.step {
  background: none repeat scroll 0 0 lightgray;
  border-radius: 1em;
  color: white;
  display: inline-block;
  font-size: 14px;
  height: 4em;
  line-height: 4em;
  margin: 0 1em;
  position: relative;
  text-align: center;
  width: 9em;
}
ul.steps li.step:before {
  content: counter(steps, decimal) ". ";
  counter-increment: steps;
}
ul.steps li.step.complete:before {
  content: "✔ ";
}
ul.steps li.step.complete {
  background-color: green;
}
ul.steps li.step.current {
  background-color:dodgerblue
}
ul.steps li.arrow {
  background: none repeat scroll 0 0 rgba(0, 0, 0, 0);
  color: black;
  display: inline-block;
  font-size: 28px;
  height: 46px;
  line-height: normal;
  margin: 0;
  width: auto;
}
</style>