Para añadir una aplicación en SaltOS, hay que hacer los siguientes pasos:
El fichero XML que define una aplicación, puede contener los siguientes nodos:
Aunque no es necesario que los contenga todos. Por ejemplo, si se observa la aplicación de xml/documentos.xml, esta no incluye los nodos <pdf> ni <excel>, sin embargo, la aplicación xml/partes.xml si que incluye todas estas opciones.
Este nodo define como es el listado de la aplicación. A continuación se muestra un fragmento (modificado) con las opciones que puede contener:
<list> <title lang="true">list</title> <actions include="xml/common/actions.xml" replace="true"/> <width>100%</width> <fields> <field> <name>id</name> <label lang="true">id</label> <tip>My tip message</tip> <width>100px</width> <sort>true</sort> <order>id</order> <orderasc>id</orderasc> <orderdesc>id</orderdesc> <size>20</size> <class>mycssclass</class> </field> <field> . . . </field> . . . </fields> <javascript> . . . </javascript> <styles> . . . </styles> <quick> <row> <field> <type>button</type> <value lang="true">create</value> <tip lang="true">create</tip> <onclick>create()</onclick> <icon>create</icon> <class>nowrap contextmenu</class> <class2>shortcut_ctrl_insert</class2> <disabled global="page" eval="true">check_user($page,"create")?"false":"true"</disabled> </field> <field> <type>separator</type> <width>100%</width> </field> <field ifeval="!ismobile() && check_filter(array('campo1'=>'','comentarios'=>''))"> <type>label</type> <label lang="true">usedfilter</label> <class>nowrap</class> <class2>info</class2> </field> <field> <name>buscar</name> <label lang="true">buscar</label> <type>text</type> <width>240px</width> <value global="comentarios" eval="true">$comentarios=getParam("comentarios")</value> <onchange>copy_value("comentarios","buscar");</onchange> <onkey>if(is_enterkey(event)) { copy_value("comentarios","buscar");buscar(); }</onkey> <focus>true</focus> <speech>true</speech> <class3>shortcut_ctrl_f</class3> </field> <field> <type>button</type> <value lang="true">buscar</value> <tip lang="true">buscartip</tip> <onclick>buscar()</onclick> <icon>find</icon> <class>nowrap</class> </field> <field> <type>button</type> <value lang="true">limpiar</value> <tip lang="true">limpiartip</tip> <onclick>limpiar()</onclick> <icon>refresh</icon> <class>nowrap contextmenu</class> </field> </row> </quick> <form> <name>list</name> <action></action> <method>get</method> <fields> <title lang="true">filter</title> <buttons>true</buttons> <row> <field include="xml/common/hiddenslist.xml" replace="true" /> <field> <name>id_usuario</name> <label lang="true">username</label> <type>text</type> <width>240px</width> <value global="id_usuario" eval="true">$id_usuario=getParam("id_usuario")</value> <colspan>3</colspan> </field> <field> <type>separator</type> <width>10px</width> </field> <field> <name>id_cliente</name> <label lang="true">cliente</label> <type>text</type> <width>240px</width> <value global="id_cliente" eval="true">$id_cliente=getParam("id_cliente")</value> <colspan>4</colspan> <onchange>myjsfunction()</onchange> </field> </row> <row> . . . </row> . . . </fields> <buttons include="xml/common/buttonslist.xml" /> </form> <pager include="xml/common/pagerlist.xml"/> <query global="page,comentarios" eval="true">" SELECT id, campo1, campo2, campo3, campo4, campo5, FROM (SELECT a.* FROM tbl_example a LEFT JOIN tbl_registros_i e ON e.id_aplicacion='".page2id($page)."' AND e.id_registro=a.id LEFT JOIN tbl_usuarios b ON e.id_usuario=b.id WHERE a.id IN (SELECT id_registro FROM tbl_indexing WHERE id_aplicacion='".page2id($page)."' AND ".make_fulltext_query("search",$comentarios,"tbl_indexing")." ) ) d WHERE ".check_sql($page,"list")</query> <order global="order" eval="true">$order</order> <limit global="limit" eval="true">$limit</limit> <offset global="offset" eval="true">$offset</offset> </list>
Este nodo define como es el formulario de la aplicación. Dependiendo de si es un formulario para hacer una consulta, para crear un nuevo registro o para actualizar a un registro existente, se deberán configurar las diferentes vistas en los nodos <view>, <insert> y <update>. A continuación se muestra un fragmento (modificado) con las opciones que puede contener:
<form> <views> <view> <title lang="true">formview</title> <query> <query include="xml/common/qpermview.xml" replace="true" /> <query include="xml/common/qdefaultview.xml" replace="true" /> <comments_old include="xml/common/qcommentsold.xml" /> <files_old include="xml/common/qfilesold.xml" /> <control include="xml/common/qcontrol.xml"/> <folders include="xml/common/qfolders.xml" /> </query> </view> <insert> <title lang="true">forminsert</title> <query> <query include="xml/common/qpermcreate.xml" replace="true" /> <default>SELECT '0' id,'0' id_cliente,'0' id_proyecto</default> <files_new include="xml/common/qfilesnew.xml" replace="true"/> <folders include="xml/common/qfolders.xml" /> </query> </insert> <update> <title lang="true">formupdate</title> <query> <query include="xml/common/qpermupdate.xml" replace="true" /> <query include="xml/common/qdefaultview.xml" replace="true" /> <comments_old include="xml/common/qcommentsold.xml" /> <files_old include="xml/common/qfilesold.xml" /> <comments_new include="xml/common/qcommentnew.xml" replace="true"/> <files_new include="xml/common/qfilesnew.xml" replace="true"/> <control include="xml/common/qcontrol.xml"/> <folders include="xml/common/qfolders.xml" /> </query> </update> </views> <name>form</name> <action></action> <method>post</method> <hiddens include="xml/common/hiddensform.xml" /> <fields> <default> <fieldset> <title lang="true">defaultdata</title> <quick global="id" eval="true">$id>=0?"false":"true"</quick> <buttons>true</buttons> <row> <field> <name>id</name> <type>hidden</type> </field> <field> <name>id_cliente</name> <label lang="true">cliente</label> <type>select</type> <width>240px</width> <query eval="true">make_extra_query_with_perms("clientes","tbl_clientes","nombre")." UNION ..."</query> <focus global="id" eval="true">$id>=0?"true":"false"</focus> <readonly global="id" eval="true">$id>=0?"false":"true"</readonly> <onchange>update_proyectos()</onchange> <link>openapp('clientes',-abs(ID))</link> <icon>view</icon> </field> </row> <row> <field> <name>id_proyecto</name> <label lang="true">proyecto</label> <type>select</type> <width>240px</width> <query eval="true">"SELECT '' value,'".LANG_ESCAPE("sinproyecto")."' label"</query> <readonly global="id" eval="true">$id>=0?"false":"true"</readonly> <colspan>3</colspan> <link>openapp('proyectos',-abs(ID))</link> <icon>view</icon> </field> </row> <row> <field> <name>nombre</name> <label lang="true">nombre</label> <type>text</type> <width>240px</width> <readonly global="id" eval="true">$id>=0?"false":"true"</readonly> <required>true</required> <speech>true</speech> </field> </row> <row> <field> <type>separator</type> </field> </row> <row> <field> <name>descripcion</name> <label lang="true">descripcion</label> <type>textarea</type> <width>600px</width> <height>120px</height> <colspan>6</colspan> <readonly global="id" eval="true">$id>=0?"false":"true"</readonly> <required>true</required> </field> </row> </fieldset> </default> <comments_old include="xml/common/commentsold.xml"/> <files_old include="xml/common/filesold.xml" /> <comments_new include="xml/common/commentnew.xml"/> <files_new include="xml/common/filesnew.xml"/> <control include="xml/common/control.xml" /> <folders include="xml/common/folders.xml" /> </fields> <quick include="xml/common/quickform.xml" /> <buttons include="xml/common/buttonsform.xml" /> <javascript> <javascript include="xml/common/jsform.xml" replace="true"/> <cache> <include>js/updateproyectos.js</include> </cache> </javascript> </form>
Este nodo define la lista de consultas necesarias para hacer un insert, es decir, para crear un registro. A continuación se muestra un fragmento (modificado) con las opciones que puede contener:
<insert> <query include="xml/common/qpermcreate.xml" replace="true"/> <query include="xml/common/autonombre.xml" replace="true"/> <query match="default" prefix="true" global="page" preeval="true" eval="true">preeval_insert_query(page2table($page))</query> <query include="xml/common/qcontrolinsert.xml" replace="true"/> <query include="xml/common/qfilesinsert.xml" replace="true"/> <query include="xml/common/qfoldersinsert.xml" replace="true"/> </insert>
Este nodo define la lista de consultas necesarias para hacer un update, es decir, para modificar un registro. A continuación se muestra un fragmento (modificado) con las opciones que puede contener:
<update> <query include="xml/common/qpermupdate.xml" replace="true"/> <query match="default" prefix="true" global="page" preeval="true" eval="true">preeval_update_query(page2table($page))</query> <query include="xml/common/qcontrolupdate.xml" replace="true"/> <query include="xml/common/qfilesdelete.xml" replace="true" /> <query include="xml/common/qfilesupdate.xml" replace="true"/> <query include="xml/common/qcommentsdelete.xml" replace="true" /> <query include="xml/common/qcommentsinsert.xml" replace="true" /> <query include="xml/common/qfoldersupdate.xml" replace="true"/> </update>
Este nodo define la lista de consultas necesarias para hacer un delete, es decir, para borrar un registro. A continuación se muestra un fragmento (modificado) con las opciones que puede contener:
<delete> <query include="xml/common/qpermdelete.xml" replace="true"/> <query include="xml/common/qdelete.xml" replace="true" /> <query include="xml/common/qdeletecomments.xml" replace="true" /> <query include="xml/common/qdeletefiles.xml" replace="true" /> <query include="xml/common/qcontroldelete.xml" replace="true"/> <query include="xml/common/qfoldersdelete.xml" replace="true"/> </delete>
Este nodo define la consulta y el diseño gráfico necesario para generar un PDF. A continuación se muestra un fragmento (modificado) con las opciones que puede contener:
<pdf> <constructor>"P","mm","A4"</constructor> <margins>50,30,30,30</margins> <query>"SELECT CASE id_cliente ... FROM (SELECT a.*, ".make_extra_query_with_login("b.")." usuario, ... FROM tbl_partes a LEFT JOIN tbl_registros_i e ON e.id_aplicacion='".page2id(getParam("page"))."' AND e.id_registro=a.id LEFT JOIN tbl_usuarios b ON e.id_usuario=b.id LEFT JOIN tbl_clientes c ON a.id_cliente=c.id LEFT JOIN tbl_proyectos p ON a.id_proyecto=p.id) d WHERE ROUND(id) IN (".check_ids(getParam("id")).")"</query> <foreach> <!-- TEMPLATE --> <header> <!-- LOGO --> <margins>0,0,0,0</margins> <image>CONFIG("logo_left"),CONFIG("logo_top"), ...)</image> <!-- PONER MARCA DE AGUA --> <font>"normal","B",CONFIG("water_partes_size"),"#eeeeee"</font> <text>CONFIG("water_partes_posx"),CONFIG("water_partes_posy"), ...</text> <margins>50,30,30,30</margins> <setxy>30,50</setxy> </header> <footer> <margins>0,0,0,0</margins> <!-- PONER PIE DE PAGINA --> <font>"normal","",6,CONFIG("color_text2")</font> <pageno>30,279,150,0,"R",LANG("paginaspc"),LANG("spcdespc")</pageno> <margins>50,30,30,30</margins> </footer> <!-- BEGIN --> <newpage></newpage> <color>CONFIG("color_line"),"#000000"</color> <!-- VOLCAR DATOS --> <setxy>30,50</setxy> <getxy>"x","y"</getxy> <font>"normal","B",8,CONFIG("color_text1")</font> <textarea>30,$row["y"],25,4,"R",LANG("parte")</textarea> <font>"normal","",8,CONFIG("color_text2")</font> <textarea>55,$row["y"],75,4,"L",$row["id"]</textarea> <font>"normal","B",8,CONFIG("color_text1")</font> <textarea>105,$row["y"],25,4,"R",LANG("userinsert")</textarea> <font>"normal","",8,CONFIG("color_text2")</font> <textarea>130,$row["y"],75,4,"L",$row["usuario"]</textarea> . . . </foreach> <output>encode_bad_chars(str_replace(".","",strpos(check_ids(getParam("id")),",")===false?execute_query(" SELECT CONCAT('".LANG_ESCAPE("parte")."',' ',LPAD(id,".intval(CONFIG("zero_padding_digits")).",0),' ',tarea) subject FROM tbl_partes WHERE id IN (".check_ids(getParam("id")).")"):LANG("partes"))).getDefault("exts/pdfext",".pdf")</output> </pdf>
Este nodo define la consulta necesaria para generar un fichero en formato Excel. A continuación se muestra un fragmento (modificado) con las opciones que puede contener:
<excel> <query require="php/listsim.php" global="page" eval="true">" SELECT CONCAT(''',LPAD(a.id,".intval(CONFIG("zero_padding_digits")).",0)) '".LANG_ESCAPE("codigo")."', CASE a.id_cliente WHEN '0' THEN '".LANG_ESCAPE("sincliente")."' ELSE c.nombre END '".LANG_ESCAPE("cliente")."', CASE a.id_proyecto WHEN '0' THEN '".LANG_ESCAPE("sinproyecto")."' ELSE p.nombre END '".LANG_ESCAPE("proyecto")."', tarea '".LANG_ESCAPE("tarea")."', fecha '".LANG_ESCAPE("date")."', horas '".LANG_ESCAPE("horas")."', precio '".LANG_ESCAPE("precio")."', total '".LANG_ESCAPE("total")."', CASE liquidado WHEN 1 THEN '".LANG_ESCAPE("yes")."' ELSE '".LANG_ESCAPE("no")."' END '".LANG_ESCAPE("liquidado")."', fecha2 '".LANG_ESCAPE("dateliq")."' FROM tbl_partes a LEFT JOIN tbl_clientes c ON a.id_cliente=c.id LEFT JOIN tbl_proyectos p ON a.id_proyecto=p.id WHERE a.id IN (".list_simulator($page).")"</query> </excel>
Este nodo, aparece en los nodos <list> y <form> y permite definir que códigos JavaScript se desea ejecutar para esa pantalla. A continuación se muestra un fragmento (modificado) con las opciones que puede contener:
<javascript> <javascript include="xml/common/jslist.xml" replace="true" /> <function>myfunction(args) { alert(args); }</function> <inline>alert('myfunction executed now');</inline> <include>js/myjsfile.js</include> </javascript>
Este nodo, aparece en los nodos <list> y <form> y permite definir que códigos CSS se desea incluir para esa pantalla. A continuación se muestra un fragmento (modificado) con las opciones que puede contener:
<styles> <inline>.mystyle { color:#336699; };</inline> <include>css/mycssfile.css</include> </styles>
Este fichero define el esquema de la base de datos que usará SaltOS. Cuando se modifica este fichero, SaltOS busca que diferencias hay entre el esquema especificado en este fichero y el esquema que hay en la base de datos. Cuando encuentra cambios, hace las consultas SQL necesarias para modificar el esquema sin perder datos. A continuación se muestra un fragmento (modificado) con las opciones que puede contener:
<tables> . . . <table> <name>tbl_documentos</name> <fields> <field> <name>id</name> <type>/*MYSQL INT(11) *//*SQLITE INTEGER */</type> <pkey>true</pkey> </field> <field> <name>id_cliente</name> <type>INT(11)</type> <fkey>tbl_clientes</fkey> </field> <field> <name>nombre</name> <type>VARCHAR(255)</type> </field> <field> <name>descripcion</name> <type>TEXT</type> </field> <field> <name>id_proyecto</name> <type>INT(11)</type> <fkey>tbl_proyectos</fkey> </field> </fields> </table> . . . </tables>
Este fichero define los datos de las tablas maestras de SaltOS. Cuando se modifica este fichero, SaltOS actualiza las tablas maestras con los nuevos datos. En este caso, se explica como añadir una aplicación a la tabla maestra tbl_aplicaciones. A continuación se muestra un fragmento (modificado) con las opciones que puede contener:
<tbl_aplicaciones> . . . <row> <id>100</id> <codigo>examples</codigo> <nombre>Ejemplos</nombre> <tabla>tbl_example</tabla> <campo>nombre</campo> </row> . . . </tbl_aplicaciones>
Este fichero define los datos de las tablas maestras de SaltOS. Cuando se modifica este fichero, SaltOS actualiza las tablas maestras con los nuevos datos. En este caso, se explica como añadir una aplicación a la tabla maestra tbl_aplicaciones_p que permite a SaltOS relacionar que permisos puede tener cada aplicación, tal como se muestra en la pestaña de permisos de las aplicaciones de usuarios y grupos. A continuación se muestra un fragmento (modificado) con las opciones que puede contener:
<tbl_aplicaciones_p> <row> <id_aplicacion>6</id_aplicacion> <id_permiso>10</id_permiso> </row> <row> <id_aplicacion>6</id_aplicacion> <id_permiso>3</id_permiso> </row> <row> <id_aplicacion>6</id_aplicacion> <id_permiso>1</id_permiso> </row> <row> <id_aplicacion>6</id_aplicacion> <id_permiso>8</id_permiso> </row> <row> <id_aplicacion>6</id_aplicacion> <id_permiso>4</id_permiso> </row> <row> <id_aplicacion>6</id_aplicacion> <id_permiso>5</id_permiso> </row> <row> <id_aplicacion>6</id_aplicacion> <id_permiso>11</id_permiso> </row> <row> <id_aplicacion>6</id_aplicacion> <id_permiso>12</id_permiso> </row> <row> <id_aplicacion>6</id_aplicacion> <id_permiso>13</id_permiso> </row> <row> <id_aplicacion>6</id_aplicacion> <id_permiso>14</id_permiso> </row> <row> <id_aplicacion>6</id_aplicacion> <id_permiso>2</id_permiso> </row> <row> <id_aplicacion>6</id_aplicacion> <id_permiso>9</id_permiso> </row> <row> <id_aplicacion>6</id_aplicacion> <id_permiso>6</id_permiso> </row> <row> <id_aplicacion>6</id_aplicacion> <id_permiso>7</id_permiso> </row> </tbl_aplicaciones_p>
La lista de permisos esta definida en la tabla tbl_permisos que se encuentra también en el fichero xml/dbstatic.xml. Si se desea añadir mas permisos, bastará con añadir el permiso en la tbl_permisos y crear en la tabla tbl_aplicaciones_p la relación entre el nuevo permiso y la nueva aplicación.
Este fichero define el menú de SaltOS. Contiene la especificación de como debe ser la cabecera de SaltOS y la especificación de como debe ser el menú de la izquierda de SaltOS. A continuación se muestra un fragmento (modificado) con las opciones que puede contener:
<group> <label lang="true">gestiongeneral</label> <name>gestiongeneral</name> <class>menu</class> . . . <temp global="temp" eval="true">$temp="example"</temp> <option include="xml/common/menuoptionslist.xml" replace="true"/> <option include="xml/common/menuoptionsquery.xml" replace="true"/> <option include="xml/common/menuoptionscreate.xml" replace="true"/> <option include="xml/common/menuoptionsfilter.xml" replace="true"/> <option include="xml/common/menuoptionsreset.xml" replace="true"/> . . . <temp global="temp" eval="true">$temp="about"</temp> <option include="xml/common/menuoptionslist.xml" replace="true"/> <temp global="temp" eval="true">$temp="logout"</temp> <option include="xml/common/menuoptionslist.xml" replace="true"/> </group>
En este ejemplo, se ha añadido la aplicación Example en el grupo de aplicaciones General. Si se desea añadir o incluso crear otro grupo, bastará con seguir el mismo formato que el ejemplo anterior.
Este fichero define los iconos de SaltOS. Actualmente, contiene 3 grupos para cada uno de los estilos de iconos que SaltOS dispone. A continuación se muestra un fragmento (modificado) con las opciones que puede contener:
<highcontrast> . . . <example>lib/highcontrast/actions/document-open.png</example> . . . </highcontrast> <crystal> . . . <example>lib/crystal/apps/mydocuments.png</example> . . . </crystal> <silk> . . . <example>lib/silk/icons/table_multiple.png</example> . . . </silk>
Este fichero define los textos que usará SaltOS en los nodos que se especifique el atributo lang="true". A continuación se muestra un fragmento (modificado) con las opciones que puede contener:
<dir>ltr</dir> <default>common</default> <common> . . . </common> <login> . . . </login> <menu> . . . <documentos>Documentos</documentos> . . . </menu> . . . <documentos> <list>Listado de documentos</list> <create>Nuevo documento</create> <formview>Detalle del documento</formview> <forminsert>Alta de un nuevo documento</forminsert> <formupdate>Modificación del documento</formupdate> <defaultdata>Datos del documento</defaultdata> </documentos> . . .
Este fichero, también esta explicado en la FAQ sobre como traducir textos en SaltOS.