Un plugin jQuery pour redimensionner automatiquement vos textarea

Je vais aujourd'hui vous parler de Crusher, un petit destiné à faire en sorte que vos textarea se redimensionnent automatiquement. Léger (il repose en bonne partie sur l'application de styles CSS) et facile d'utilisation, il s'agit (à mon sens !) d'une bonne solution pour réaliser cet effet simplement.

Comme d'habitude, n'hésitez pas à participer au projet en vous rendant sur sa page GitHub !

Gérer des routes particulières sur PrestaShop

PrestaShop permet à ses utilisateurs disposant d'un serveur web supportant l'URL rewriting de gérer les URLs de leur boutique d'une manière assez complète : il suffit de modifier, directement dans le back-office, les masques correspondant à tel ou tel type d'URL pour voir toute la structure de son site se mettre à jour automatiquement, et tout cela est bien beau.

Mais qu'advient-il le jour où, pris de folie, vous vous rendez compte que vous avez besoin de gérer une URL spécifique pour une page ? Prenons l'exemple d'une catégorie : d'un point de vue technique, PrestaShop vous oblige à faire figurer l'id de ladite catégorie dans son URL. Comment faire pour s'en débarrasser sans casser tout le fonctionnement du routeur interne ?

La solution que je vous propose aujourd'hui consiste en une simple surcharge de la classe Dispatcher :

<?php

class Dispatcher extends DispatcherCore
{
// On définit des routes particulières, qui auront la priorité sur le processus de routage basique
// À gauche, l'URL actuelle ; à droite, l'URL souhaitée

public $special_routes = array(
'/3-my-category' => '/my-awesome-url'
);



public function dispatch()
{
// On démarre une session PHP classique pour la persistence des données POST,
// étant donné que PrestaShop lui-même n'en fait pas usage
session_start();

$this->getController();
$request_uri = explode('?', $this->request_uri);

// Si on a sauvegardé des données POST avant redirection, on les récupère
if (isset($_SESSION['_POST'])) {
$_POST = $_SESSION['_POST'];
unset($_SESSION['_POST']);
}

foreach ($this->special_routes as $old_url => $new_url) {
if ($request_uri[0] == $new_url) {
// Une "nouvelle" URL est demandée :
// on passe la requête à sa contrepartie originelle

$_GET['controller'] = false;
$this->controller = false;
$request_uri[0] = $old_url;
$this->request_uri = implode('?', $request_uri);
break;
} else if ($request_uri[0] == $old_url) {
// Une "ancienne" URL est demandée :
// on sauvegarde les données POST s'il y en a,
// et on redirige vers l'URL voulue

$_SESSION['_POST'] = $_POST;
$request_uri[0] = $new_url;
header('Status: 301 Moved Permanently', false, 301);
header('Location: '.implode('?', $request_uri));
die;
}
}

parent::dispatch();
}



// On fait maintenant en sorte que le générateur d'URLs utilise les nôtres
// Cela nous permet de gagner du temps et de nous assurer de la réussite des requêtes AJAX

public function createUrl($route_id, $id_lang = null, array $params = array(), $force_routes = false, $anchor = '', $id_shop = null) {
$url = '/'.parent::createUrl($route_id, $id_lang, $params, $force_routes, $anchor, $id_shop);
return ltrim((isset($this->special_routes[$url]) ? $this->special_routes[$url] : $url), '/');
}
}

Ainsi, dans cet exemple, naviguer vers /my-awesome-url fera apparaître la catégorie voulue ; et si on se rend directement à cette dernière via /3-my-category, on sera redirigé. Les éventuels paramètres GET et POST seront conservés.

Pour que ceci fonctionne, vous devez désactiver l'option de redirection canonique native dans le back-office de PrestaShop (dans Préférences > SEO & URLs). Soyez sûr·e d'avoir conscience des conséquences !

Un système de grille fluide basé sur LESS

Voici venir , une mixin LESS destinée à vous aider à générer dans votre CSS une grille fluide à tous points de vue : au sens propre du terme bien sûr, mais aussi bien dans son paramétrage que dans son emploi.

La mixin s'utilise de la manière suivante :

.greed(12, 10px); // nombre maximal de colonnes (défaut : 12), taille des gouttières (défaut : 0)

Et voici un exemple de grille en HTML :

<div class="greed">
<div class="row-4">
<div class="col-1"></div> <!-- 25% -->
<div class="col-3"></div> <!-- 75% -->
</div>
<div class="row-12">
<div class="col-1"></div> <!-- 8.3333333333 % -->
<div class="col-11"></div> <!-- 91.6666666667 % -->
</div>
</div>

Apprenez-en plus et contribuez au projet (si vous le voulez) sur la page GitHub de celui-ci !

Gérez vos environnements dans vos projets PHP 5.3+

J'ai le plaisir de vous présenter Environ, un petit pour PHP 5.3 ou supérieur, qui vous permettra de jongler facilement entre vos différents environnements (développement, tests, production...) tout en détectant automatiquement lequel est actif et quelles sont les actions à mener en conséquence (par exemple, l'ouverture d'une connexion à une base de données différente, ou encore l'activation de fonctionnalités de debug).

Celui-ci suit bien évidemment la norme PSR-2 et peut être installé facilement via Composer. Apprenez-en davantage en vous rendant sur la page GitHub du projet, sur laquelle vous aurez également l'occasion de collaborer si vous le souhaitez (sombres analogies mises à part) !

Utiliser Typeahead.js de Twitter dans une application AngularJS

Si vous avez tenté d'utiliser le plugin JavaScript d'autocomplétion de Twitter, baptisé Typeahead.js, au sein d'une directive dans votre application AngularJS, d'une façon similaire à celle-ci :

angular.module('myDirectives', [])
.directive('initTypeahead', function() {
return function(scope, element, attrs) {
element.typeahead({
// ...
});
};
});

...vous avez peut-être eu la désagréable surprise de constater que lors de la sélection d'une valeur par l'utilisateur, la variable du $scope Angular définie en tant que modèle de l'input sur lequel vous avez appliqué la directive précédente ne se mettait pas correctement à jour, conservant pour toute valeur les quelques lettres saisies au préalable.

Typeahead mettant à notre disposition des évènements JavaScript permettant de détecter ladite sélection, le réflexe primordial et naïf (c'est du vécu) sera d'appliquer manuellement un $scope.apply() dans le listener adéquat :

angular.module('myDirectives', [])
.directive('initTypeahead', function() {
return function(scope, element, attrs) {
element.typeahead({
// ...
}).on('typeahead:selected typeahead:autocompleted', function() {
scope.$apply();
});
};
});

Hélas, le souci étant bien localisé dans l'actualisation du $scope depuis la vue (et non l'inverse), ceci se révèlera insuffisant pour appliquer la bonne valeur depuis le DOM, avec lequel nous serons obligés d'interagir :

angular.module('myDirectives', [])
.directive('initTypeahead', function() {
return function(scope, element, attrs) {
element.typeahead({
// ...
}).on('typeahead:selected typeahead:autocompleted', function(data) {
scope[element.data('ng-model')] = data.target.value;
scope.$apply();
});
};
});

Cette astuce vous évitera une imbrication plus profonde (passant par exemple par l'écriture d'un service dédié au sein de votre application), ce qui se traduira par un précieux gain de temps si vous n'utilisez cette bibliothèque que pour répondre à un besoin ponctuel.