Logo_Aloha

Ecrire un plugin pour Aloha pour MCImageManager

Flattr this!

Comme dit l'autre jour, je vais vous reparler aujourd'hui de l'éditeur WYSIWYG Aloha. On va construire un plugin en se basant sur la doc officielle. L'idée étant d'intégrer le gestionnaire d'images MCImageManager. Il existe déjà un plugin officiel de gestion d'images pour Aloha mais il est encore incomplet par rapport à MCImageManager et on ne fait pas toujours ce qu'on veut.

Commençons par voir la structure de base d'un plugin :

define(
[ 'aloha/plugin' ],
function( plugin ) {
    "use strict";

    return plugin.create( 'helloworld', {
        init: function() {
            // Executed on plugin initialization
        }
    });
});

Ici, rien de bien compliqué. Le plugin s'appelle helloworld et dispose d'une seule et unique méthode init qui ne fait rien.

Le problème, c'est qu'avec ça, vous n'allez vraiment pas aller loin. Vous n'avez accès à rien. Donc déjà on va se donner plus de libertés. Pouvoir manipuler jQuery, accéder au "menu" (le bandeau de contrôles), accéder aux traductions et enfin au coeur d'Aloha :

define(
	['aloha', 'aloha/jquery', 'aloha/plugin', 'aloha/floatingmenu', 'i18n!imagemanager/nls/i18n', 'i18n!aloha/nls/i18n', 'aloha/engine'],
	function (Aloha, jQuery, Plugin, FloatingMenu, i18n, i18nCore, Engine) {
		"use strict";
		var GENTICS = window.GENTICS;

		return Plugin.create('imagemanager', {
			languages: ['en', 'fr'],

			init : function () {
			}
		});
	});

A par pour jQuery et i18n (pour la trad) où j'ai conservé la notation courante, on va préfixer d'une majuscule les composants majeurs auxquels on a accès.

Comme vous aurez pu le lire, j'ai renommé le plugin en "imagemanager", plus adapté à la situation. Et j'ai défini une série de langues dans lesquelles on aura des traductions pour le plugin. Disposer de traductions de votre plugin pour toutes les langues est indispensable si vous voulez vous imposer comme maître du monde un jour.

Vous aurez aussi pu remarquer qu'une fonction init traîne au milieu du code depuis le début. Assez logiquement, c'est la fonction qui est appelée pour initialiser le plugin. Il existe d'autres méthodes disponibles mais elles sont toutes déjà implémentées et n'auront que rarement besoin d'être surchargées. Si ça vous intéresse, jetez un oeil dans le fichier lib/aloha/plugin.js.

On passe à la suite et je vais être bœuf :

define(
	['aloha', 'aloha/jquery', 'aloha/plugin', 'aloha/floatingmenu', 'i18n!imagemanager/nls/i18n', 'i18n!aloha/nls/i18n', 'aloha/engine'],
	function (Aloha, jQuery, Plugin, FloatingMenu, i18n, i18nCore, Engine) {
		"use strict";
		var GENTICS = window.GENTICS;

		return Plugin.create('imagemanager', {
			languages : ['en', 'fr'],

			init : function () {
				FloatingMenu.createScope('Aloha.Image', 'Aloha.continuoustext');
				this.imgMgrButton = new Aloha.ui.Button({
					'name' : 'indent-list',
					'iconClass' : 'aloha-button aloha-button-indent-list',
					'size' : 'small',
					'tooltip' : i18n.t('button.image.tooltip'),
					'toggle' : false,
					'onclick' : function (element, event) {
						var file = null;
						mcImageManager.browse({
							oninsert : function (file) {
								var range = Aloha.Selection.getRangeObject();
								range.deleteContents();
								var newjQImage = jQuery('<img src="' + file.files[0].url + '" alt="' + file.files[0].name + '" title="' + file.files[0].name + '" />');
								GENTICS.Utils.Dom.insertIntoDOM(newjQImage, range, jQuery(Aloha.activeEditable.obj));
							}
						});
					}
				});
				FloatingMenu.addButton(
					'Aloha.continuoustext',
					this.imgMgrButton,
					i18n.t('floatingmenu.tab.image'),
					1
				);
			}
		});
	});

Comme vous pouvez le voir, là je vous ai balancé tout le source du plugin d'un coup. Sinon ça serait moins drôle. Pourtant, je n'ai fait qu'implémenter la méthode init.

Décomposons le code ci-dessus :

FloatingMenu.createScope('Aloha.Image', 'Aloha.continuoustext');

Code assez simple ici, nous ne faisons que définir un scope pour mieux séparer notre travail de l'existant. Vous allez me demander ce qu'est un scope, je vais donc de suite vous répondre. Aloha fonctionne sur un menu à onglets, qu'on appelle des scopes ici. Il en existe trois par défaut :

  • empty, qui est totalement vide et en soit ne nous servira pas, d'ailleurs même dans la doc, ils disent de ne pas y toucher ;
  • global, qui est la base de tous les autres scopes, voyez le comme un truc abstrait auquel on ne doit pas toucher non plus ;
  • continuoustext, qui est le seul scope présent par défaut et du même coup, celui qui est activé par défaut.

Pour faire simple et bénéficier de tout ce qui a été implémenté pour lui, nous allons créer un scope basé sur continuoustext et que nous appellerons Image. C'est ce que j'ai fait dans la ligne de code présentée ci-dessus. Pour plus de détails sur les scopes, je vous incite à lire la doc officielle sur le sujet.

Passons à la suite :

this.imgMgrButton = new Aloha.ui.Button({
	'name' : 'open-imagemanager',
	'iconClass' : 'aloha-button aloha-button-open-imagemanager',
	'size' : 'small',
	'tooltip' : i18n.t('button.image.tooltip'),
	'toggle' : false,
	'onclick' : function (element, event) {
		var file = null;
 		mcImageManager.browse({
	 		oninsert : function (file) {
	 			var range = Aloha.Selection.getRangeObject();
	 			range.deleteContents();
	 			var newjQImage = jQuery('<img src="' + file.files[0].url + '" alt="' + file.files[0].name + '" title="' + file.files[0].name + '" />');
				GENTICS.Utils.Dom.insertIntoDOM(newjQImage, range, jQuery(Aloha.activeEditable.obj));
 			}
	 	});
	}
});

Ici, nous créons un objet de type Aloha.UI.Button. Nous l'appelons open-imagemanager, on lui donne les classes CSS des boutons d'Aloha et du bouton d'ouverture de MCImageManager, cette dernière aura été réalisée séparément et nécessite de mettre en place une image de background de 16*16. Dans tooltip, je mets une référence vers une traduction (je reviendrai sur ce point plus tard).

Et pour finir, le plus important pour un bouton : réagir au clic. Nous y attachons donc une fonction qui fera le boulot. Et c'est donc là que nous appelons la méthode de parcours de bibliothèque de MCImageManager.

Evidemment pour gérer correctement l'insertion d'image, on va déléguer la suite des évènements à MCImageManager. Plus précisément en lui demandant de réagir à la sélection d'une image, évènement onInsert. Cet évènement nous fournit au passage un paramètre appelé ici file. Il contient le détail du/des fichier(s) sélectionné(s). On va donc se concentrer sur la portion de code suivante :

var range = Aloha.Selection.getRangeObject();
range.deleteContents();
var newjQImage = jQuery('<img src="' + file.files[0].url + '" alt="' + file.files[0].name + '" title="' + file.files[0].name + '" />');
GENTICS.Utils.Dom.insertIntoDOM(newjQImage, range, jQuery(Aloha.activeEditable.obj));

Pour insérer une image à l'endroit choisi, nous devons d'abord déterminer quel est l'endroit choisi. Aloha gère ça via la première ligne du code ci-dessus. La zone sélectionnée est un "range". Vu qu'on souhaite mettre une image comme contenu de ce range, on doit d'abord faire le ménage si il y a du monde dedans. Nous générons ensuite l'élément DOM de type image et l'encapsulons dans un objet jQuery (oui je l'ai fait salement là). Et nous demandons l'insertion dans le DOM via les méthodes fournies par Aloha.

Passons à la dernière portion de code :

FloatingMenu.addButton(
	'Aloha.continuoustext',
	this.imgMgrButton,
	i18n.t('floatingmenu.tab.image'),
	1
);

Nous avons créé un onglet et nous avons créé un bouton avec le comportement nécessaire pour faire ce qu'on veut. Ne reste plus qu'à mettre ce bouton au bon endroit.

Et voilà, nous avons écrit un plugin pour Aloha. Reste plus qu'à l'importer dans votre application pour qu'il soit géré. Voilà comment faire :

<script src="/js/aloha/lib/aloha.js" type="text/javascript"></script>
<script src="/js/imagemanager/js/mcimagemanager.js"></script>
<script src="/js/imagemanager/pages/im/js/jquery/jquery.dialog.js"></script>
<script src="/js/imagemanager/pages/im/js/jquery/jquery.domutils.js"></script>
<script src="/js/imagemanager/pages/im/js/jquery/jquery.dialog.status.js"></script>

Ne reste plus que de votre côté à configurer correctement MCImageManager. Honnêtement dans l'histoire, c'est le plus difficile et de très loin.

Flattr this!

A propos de Mathieu

Ingénieur développeur web dans la vente par correspondance B2B, adepte de nouvelles technologies et d'innovation. Vous pouvez aussi me retrouver sur Twitter @mathrobin
Cette entrée a été publiée dans JavaScript, avec comme mot(s)-clef(s) , , , , , , , , , . Vous pouvez la mettre en favoris avec ce permalien.

Articles liés