wiki:Creació de mòduls

Admin Center

L'adminCenter (Centre d'Administració Web) proporciona un punt d'administració únic dels servidors LliureX, facilitant des de qualsevol lloc, i a través d'un navegador web l'administració dels serveis N4d que el servidor ofereix.

Paquets

  • admin-center: paquet amb l'estructura de l'aplicació
  • admin-center-modules-transitional [Deprecated]: Conté els mòduls sobre els que s'està treballant actualment i que aporten la funcionalitat al centre d'administració web. La idea seria que cada servei n4d aportara els seus mòduls d'administració, però de moment els mòduls estan centralitzats en este paquet.
  • De moment, els serveis amb mòduls són:
  • I en vistes de ser portats pròximament:
    • LliureX Mirror
    • [...]

Estructura

Es tracta d'una aplicació modular i realitzada en PHP. Cada funcionalitat que es proporcione per N4d pot tindre mòduls associats a l'adminCenter que accedisquen a ells.

La instal·lació es realitza a /usr/share/admin-center, i es crea un enllaç simbòlic en /var/www/admin-center.

Accés

L'accés inicial es realitza a través de l'adreça:

http://server/admin-center/login.php

O bé a través de la pàgina principal del servidor, mitjançant l'enllaç "Centre d'Administració".

Principals canvis en quant a l'estructura basada en aplicacions centrades en el client

L'accés a n4d des d'aplicacions client d'escriptori es realitza a través de crides xmlrpc al servidor, ignorant els certificats que aquest li envía.

http://i.imgur.com/62FZvFs.png

Donat que un navegador web ha d'acceptar necessàriament els certificats, i per tal d'evitar confusions en l'usuari (que faça clic en acceptar els certificats), l'admin-center es comunica amb els serveis n4d a través d'una espècie de wrapper d'n4d a través del servidor web.

El client, des del navegador web, fa una crida AJAX al servidor, indicant el mètode i els arguments que es necessiten, i és el propi servidor php qui fa les peticions per nosaltres al servei n4d a través d'xmlrpc, oferint-nos la resposta en la petició ajax.

Açò tindrà una sèrie d'implicacions en algunes funcions, com per exemple totes aquelles que necessiten saber l'adreça ip del client, que en aquest cas sempre serà el propi server des del punt de vista de php.

http://i.imgur.com/f81iAYg.png

Estructura d'un mòdul

Anem a veure com estructurar un mòdul per al centre d'administració web, i quines són les utilitats que este ens presenta.

Els mòduls pengen de la carpeta DOCUMENTROOT/admin-center/modules, i tenen la següent estructura:

	module-name/
	├── module.json
	└── src
	    ├── component1.html
	    ├── component2.html
	    ├── css
	    │   ├── estils1.css
	    │   └── estils2.css
	    ├── i18n
	    │   ├── ca-ES@valencia
	    │   │   └── messages.json
	    │   ├── es-ES
	    │   │   └── messages.json
	    │   ├── en-US
	    │   │   └── messages.json
	    │   └── ...
	    ├── icons
	    │   ├── icon1.png
	    │   └── icon2.png
	    ├── js
	    │   ├── scipt1.js
	    │   └── script2.js
	    └── main.html

Vegem el contingut dels fitxers més importants.

Fitxer module.json

Fitxer en format JSON amb la descripció del mòdul i els components:

		{
		  "id": "module-name",
		  "version": "0.1",
		  "name": "Example Module",
		  "description": "Module description",
		  "main":"main.html",
		  "icon":"icon1.png",
		  "components":
		    [
		      {
		        "menuEntry":"Desc Menu Entry",
		        "id":"component id",
		        "main":"component1.html",
		        "icon":"icon2.png"
		      },
		      {
		        "menuEntry":"Desc Menu Entry 2",
		        "id":"component id 2",
		        "main":"component2.html",
		        "icon":"icon2.png"
		
		      }
		    ]
		}

Sent:

  • id: Identificador del mòdul, que haurà de coincidir amb el nom de la carpeta que el conté.
  • version: versió del mòdul.
  • name: Nom del mòdul, tai com apareixerà al menú.
  • Description: Descripció del mpòdul.
  • main: Document principal del mòdul (pàgina d'inici, sense incloure referències a fulls d'estil ni llibreries).
  • icon: Icona que representa el mòdul (acompanya a l'entrada de menú).
  • components: Llista dels components del mòdul (subpàgines/ítems del submenú). De cada component caldrà indicar:
    • menuEntry: Text de l'entrada del menú.
    • id: identificador del component.
    • main: Pàgina html del component, sense incloure referències a fulls d'estil ni llibreries.
    • icon: Icona corresponent al mòdul per a l'entrada del menú.

Notes:

  • Als identificadors, cal evitar l'ús dels caràcters ".", "#", i qualsevol altre que puga portar a confusió amb selectors CSS.
  • No cal indicar els scripts i els fulls d'estils associats, ja que es carreguen tots dinàmicament en carregar el mòdul.

La carpeta src

Conté el codi principal del mòdul, i dins d'ella trobem:

  • Un document html per a cada comoponent especificat al module.json indicat per "main".
  • Carpeta css amb els diferents fulls d'estil utilitzats pel mòdul.
  • Carpeta i18n, amb un directori per a cada idioma suportat, i el fitxer messages.json amb les traduccions a eixe idioma.
  • Carpeta icons, on s'ubiquen les icones utilitzades pel mòdul per als menus.
  • Carpeta js, amb els scripts associats a cada mòdul.

Càrrega dinàamica de mòduls

Quan es punxa sobre l'opció principal d'un mòdul per primera vegada, es procedix a la càrrega dinàmica i síncrona d'aquest, de la següent manera:

  • Carrega tots els documents css de la carpeta corresponents
  • Carrega els documents html especificats al module.json
  • Carrega els scripts de la carpeta js de forma dinàmica
  • Carrega els fitxers de traducció
  • Quan està tot carregat, llença l'event "moduleLoaded", amb el paràmetre {"moduleName":target}.
  • Quan s'accedix a un component d'un mòdul, el que es llança és l'event "componentClicked" o "componentShown" sobre el component, segons siga la primera vegada que es fa clic en el component (i per tant es llança componentClicked), o si és en vegades successives (componentShown). Caldrà capturar l'event "componentShown" associat a l'etiqueta corresponent al mòdul si volem realitzar algunes funcionalitats a l'hora de mostrar un component d'un mòdul.
  • De la mateixa manera, en accedir a un component d'un mòdul, es llança a la resta l'event "componentHidden", de manera que puguen aturar o pausar processos que estaven realitzant de per mostrar resultats a l'usuari. Per exemple, en actualitzar el mirror, periòdicament s'haurà d'actualitzar la barra de progrés. El que es fa és utilitzar un temporitzador quan es mostre el mòdul que vaja refrescant la barra, i que deixe d'existir en el moment en què l'usuari accedisca a altre mòdul.

És preferible que els mòduls utilitzen aquests events en lloc del document.load o document.ready, ja que amb ell ens assegurem que tots els components del mòdul estan carregats i per tant, s'està en predisposició de que siguen executat sense problemes de sincronisme.

Vegem un exemple de fitxer js de control principal d'un mòdul:

	function ModuleX(){}
	
	ModuleX.prototype.init=function init(){
	  console.log("Module started");
	}
	
	ModuleX.prototype.bindEvents=function bindEvents(){
	
	  // Module Loaded: Triggered when a module is fully loaded (html and scripts)
	
	  $(document).on("moduleLoaded", function(e, args){
	    var moduleName="ModuleX";
	    if(args["moduleName"]===moduleName)
	      ModuleX.init();
	  });

	  // ComponentClicked: Triggered when a module component is clicked for first time
	  $("#ModuleX-ComponentY").on("componentClicked", function(e, args){
	    console.log("Showing Component Y from module X);
	  });
	
	  // componentShown: Triggered when a module component is clicked (for second or other times)
	  $("#ModuleX-ComponentY").on("componentShown", function(e, args){
	    console.log("Showing Component Y from module X);
           // set some timing events

	  });


	  // componentHidden: Triggered when a module component is hidden
	  $("#ModuleX-ComponentY").on("componentHidden", function(e, args){
	    console.log("Hiding Component Y from module X);
            // Release timing events
	  });

	
	}
	
	var myModuleX=new ModuleX();
	ModuleX.bindEvents();
	

Traduccions

  • En pàgines html: afegim el tag "i18n" a l'element que es puga traduir.
  • En js: fem ús de l'objecte i18n que proporciona la funció gettext("domini", "cadena"), on "domini" serà un domini associat al mòdul.
  • Les cadenes corresponents a les subentrades de menú es tradueixen automàticament del JSON.
  • Tot i que en principi la funció gettext de l'objecte i18n aplica les traduccions per mòduls, és convenient utilitzar un prefix associat al mòdul en les cadenes de traducció, per tal d'evitar possibles conflictes.

Utilitats

L'admin Center ja carrega de base les llibreries i estils corresponents a:

  • JQuery,
  • Bootstrap
  • Material / Ripples
  • Snackbar
  • Bootbox
  • Suport a traduccions (i18n i jed)
  • XMLRPC [deprecated?]
  • La llibreria d'utilitsts Utils

Dins les utilitats que l'objecte Utils proporciona tenim:

  • Funció msg(text, type): Mostra el missatge "text" en un snackbar. És útil per mostrar xicotets missastges a l'usuari. El tipus pot ser:
  • MSG_INFO, (missatge informatiu, en blau)
  • MSG_ERROR i (missatge d'error, en roig)
  • MSG_SUCCESS (missatge d'èxit, en verd

Accés a funcionalitats n4d

A partir de la versió 0.2, s'ha inclòs la utilitat Utils.n4d per realitzar crides a mètodes n4d a través d'Ajax sobre el wrapper en php per a n4d. La manera d'utilitzar aquesta funcionalitat és la següent:

Utils.n4d(credentials, n4dclass, n4dmethod, arglist, callback);

Sent:

  • credentials: Una cadena buida o un vector amb les credencials de l'usuari si són necessàries.
  • n4dclass: La classe on es troba el mètode
  • n4dmethod: El mètode a executar
  • arglist: Un vector amb la llista d'arguments
  • callback: La funció de callback que s'executarà quan amb el resultat que s'obtinga de la crida.

Vegem algun exemple:

  // Prepare Ajax call
  var credentials=""; // Si necessita autenticació credentials=["user", "pass"]
  var n4dclass="LliurexGuard";
  var n4dmethod="getCustomList";
  var arglist=[targetListFile];

  try{
    Utils.n4d(credentials, n4dclass, n4dmethod, arglist, function(response){
      $("body").css("cursor", "auto");
      contentList=response["response"];
      callback(contentList);
    })
  } catch (err){
    $("body").css("cursor", "auto");
    message=self._("N4d.Error.Connection");
    Utils.msg(message, MSG_ERROR);
  }
Last modified 14 months ago Last modified on May 3, 2016, 4:03:49 PM