Esta página está traduciéndose a partir del artículo How_to implement a custom XUL query processor component, razón por la cual puede haber algunos errores sintácticos o partes sin traducir. Puedes colaborar continuando con la traducción
El servicio XUL apoya el uso de plantillas para crear un bloque de contenidos a partir de una consulta a una fuente de datos. La Guia de Plantillas XUL presenta una gran fuente de información detallada acerca del uso de las plantillas XUL. El servicio XUL proporciona procesadores de consulta de plantillas para RDF, XML y SQL (mozStorage). Este sistema de plantillas también da soporte a la creación de procesadores de consultas personalizadas. Los procesadores de consultas personalizadas son componentes XPCOM que deben implementar la interfaz nsIXULTemplateQueryProcessor y seguir algunos de los criterios que indican cuándo se deben registrar los mismos.
En este ejemplo, crearemos un sencillo componente XPCOM en JavaScript. Dicho componente mantendrá una pequeña selección de objetos de JavaScript en su fuente de datos. En la práctica, se usaría una fuente propia de datos personalizada.
A continuación presentamos un ejemplo del posible aspecto que podría tener nuestro servicio de XUL al utilizar un procesador de consultas personalizado:
<?xml version="1.0"?> <?xml-stylesheet href="chrome://global/skin/" type="text/css"?> <window xmlns="https://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> <grid> <columns> <column flex="1"/> <column flex="3"/> <column flex="2"/> <column flex="1"/> </columns> <rows datasources="dummy" ref="." querytype="simpledata"> <template> <row uri="?"> <label value="?name"/> <label value="?age"/> <label value="?hair"/> <label value="?eye"/> </row> </template> </rows> </grid> </window>
Algunas cosas a tener en cuenta. En realidad no estamos utilizando las fuentes de datos
en nuestro componente de ejemplo, por lo que lo configuraremos con un valor no válido. Un hilo vacío también valdría. El tipo de consulta
es importante. Se usa para crear un caso de nuestro objeto XPCOM. La contracción de la identidad de nuestro componente XPCOM debería tener la forma de "@mozilla.org/xul/xul-query-processor;1?name=xxx"
, donde las xxx representan el tipo de consulta
utilizado en el bloque de plantillas XUL. A continuación mostramos nuestro ejemplo de procesador de consultas XPCOM de JavaScript:
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); // basic wrapper for nsIXULTemplateResult function TemplateResult(aData) { this._data = aData; // just make a random number for the id this._id = Math.random(100000).toString(); } TemplateResult.prototype = { QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsIXULTemplateResult]), // private storage _data: null, // right now our results are flat lists, so no containing/recursion take place isContainer: false, isEmpty: true, mayProcessChildren: false, resource: null, type: "simple-item", get id() { return this._id; }, // return the value of that bound variable such as ?name getBindingFor: function(aVar) { // strip off the ? from the beginning of the name var name = aVar.toString().slice(1); return this._data[name]; }, // return an object instead of a string for convenient comparison purposes // or null to say just use string value getBindingObjectFor: function(aVar) { return null; }, // called when a rule matches this item. ruleMatched: function(aQuery, aRuleNode) { }, // the output for a result has been removed and the result is no longer being used by the builder hasBeenRemoved: function() { } }; // basic wrapper for nsISimpleEnumerator function TemplateResultSet(aArrayOfData) { this._index = 0; this._array = aArrayOfData; } TemplateResultSet.prototype = { QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsISimpleEnumerator]), hasMoreElements: function() { return this._index < this._array.length; }, getNext: function() { return new TemplateResult(this._array[this._index++]); } }; // The query processor class - implements nsIXULTemplateQueryProcessor function TemplateQueryProcessor() { // our basic list of data this._data = [ {name: "mark", age: 36, hair: "brown", eye: "brown"}, {name: "bill", age: 25, hair: "red", eye: "black"}, {name: "joe", age: 15, hair: "blond", eye: "blue"}, {name: "jimmy", age: 65, hair: "gray", eye: "dull"} ]; } TemplateQueryProcessor.prototype = { QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsIXULTemplateQueryProcessor]), classDescription: "Sample XUL Template Query Processor", classID: Components.ID("{282cc4ea-a49c-44fc-81f4-1f03cbb7825f}"), contractID: "@mozilla.org/xul/xul-query-processor;1?name=simpledata", getDatasource: function(aDataSources, aRootNode, aIsTrusted, aBuilder, aShouldDelayBuilding) { // TODO: parse the aDataSources variable // for now, ignore everything and let's just signal that we have data return this._data; }, initializeForBuilding: function(aDatasource, aBuilder, aRootNode) { // perform any initialization that can be delayed until the content builder // is ready for us to start }, done: function() { // called when the builder is destroyed to clean up state }, compileQuery: function(aBuilder, aQuery, aRefVariable, aMemberVariable) { // outputs a query object. // eventually we should read the <query> to create filters return this._data; }, generateResults: function(aDatasource, aRef, aQuery) { // preform any query and pass the data to the result set return new TemplateResultSet(this._data); }, addBinding: function(aRuleNode, aVar, aRef, aExpr) { // add a variable binding for a particular rule, which we aren't using yet }, translateRef: function(aDatasource, aRefstring) { // if we return null, everything stops return new TemplateResult(null); }, compareResults: function(aLeft, aRight, aVar) { // -1 less, 0 ==, +1 greater if (aLeft < aRight) { return -1; } else if (aLeft > aRight) { return 1; } else { return 0; } } }; var components = [TemplateQueryProcessor]; function NSGetModule(compMgr, fileSpec) { return XPCOMUtils.generateModule(components); }
Nuestro ejemplo de procesador de consultas es muy fácil. Notas aclaratorias:
- Estamos usando el
getBindingFor
en vez delgetBindingObjectFor
para simplificar así el código. La variable introducida en elgetBindingFor
todavía conserva las “?” por lo que debéis aseguraros de introducirla de forma correcta. - No se usarán cualquiera de los elementos
<query/>
o<rule/>
en el bloque de plantillas de XUL. Se podrá hacer uso de éstas para apoyar el filtrado de fuentes de datos. - No estamos manejando
fuentes de datos
, sino que en su lugar, estamos introduciendo a mano el componente. Se podría ampliar fácilmente este ejemplo para manejar variasfuentes de datos
a través de la comprobación del valor de las mismas en elgetDatasource
y en elinitializeForBuilding
. - No se usarán cualquiera de los elementos
<query/>
o<rule/>
en el bloque de plantillas de XUL. Se podrá hacer uso de éstas para apoyar el filtrado de fuentes de datos.