bytes.cat

La wiki d'FP d'informàtica

Eines de l'usuari

Eines del lloc


cordova

Diferències

Ací es mostren les diferències entre la revisió seleccionada i la versió actual de la pàgina.

Enllaç a la visualització de la comparació

Ambdós costats versió prèvia Revisió prèvia
Següent revisió
Revisió prèvia
cordova [2023/12/11 20:33]
enric_mieza_sanchez [Exercici Tasklist v0.1] jquery mobile dialog
cordova [2025/12/04 17:52] (actual)
enric_mieza_sanchez [AJAX amb jQuery]
Línia 52: Línia 52:
  
 ===== Afegint jQuery ===== ===== Afegint jQuery =====
-jQuery ens pot ajudar molt a agilitzar el desenvolupament.+jQuery és una biblioteca de codi que opera sobre el DOM de JavaScript i facilita moltes operacions.
  
 <WRAP info> <WRAP info>
 Podeu aprendre més sobre [[jQuery]] <- en aquesta wiki. Podeu aprendre més sobre [[jQuery]] <- en aquesta wiki.
-</WRAP> 
- 
-Com afegir jQuery a la meva pàgina HTML: 
-  - **Instal·lació "a mà"**. Cal incloure els arxius de jQuery al nostre projecte. Ho pots fer de diverses maneres: 
-    - Descarregar els arxius de la web oficial http://jquery.com 
-    - Utilitzar els repositoris online (CDN). Pots veure com fer-ho en aquest tutorial: 
-    - https://www.w3schools.com/jquery/jquery_get_started.asp 
-  - Instal·lació amb el **//package// ''cordova-jquery'' de NodeJS** que, a més, ens facilita plantilles bàsiques típiques de apps mòbils. 
-    - Està força obsolet, però té alguns //templates// que permeten començar ràpid. 
-    - https://www.npmjs.com/package/cordova-jquery 
-    - Instal·la-ho a l'arrel del teu projecte Cordova:<code>$ npm install cordova-jquery</code> 
-    - Configura el template. 
-      * En Linux executa:<code>$ node_modules/cordova-jquery/cordova-jquery</code> 
-      * En Windows fes des del CMD:<code>node node_modules/cordova-jquery/cordova-jquery</code> 
-  - Mira com queda la plantilla fent de nou:<code>$ cordova run browser</code>  
-  - Prova diversos //templates// (per exemple: multipage, accordion, listview). Observa el codi que ens genera per cadascun d'ells, en particular el ''index.html''. 
-  - Ens quedarem amb el ''listview'' ja que ens anirà bé com a base per a fer un exercici de //tasklist//. 
-    * La [[https://api.jquerymobile.com/listview/|documentació oficial de jQuery mobile listview]] ens serà útil per a saber com utilitzar-la. 
- 
-<WRAP important> 
-Hi ha un petit error a les plantilles. Quan arrenquis l'aplicació mira la consola (CTRL+SHIFT+K) i veuràs un error a la línia 28 del ''index.js''. Elimina aquesta línia ja que no ens cal i ens atura l'execució de la nostra aplicació. 
 </WRAP> </WRAP>
  
 \\ \\
  
-===== Cordova no vol inlines ===== 
-Típicament podríem fer una aplicació en JavaScript en una pàgina HTML i podríem posar botons que cridin a funcions del nostre codi amb un //onclick// (el què coneixem per crida //inline//). Doncs bé, Cordova no ens deixa fer //inlines//. 
- 
-Forma de solventar-ho: fer els botons més senzills, sense //onclick// (però amb //id//): 
-<code javascript index.html> 
-  <button id="boto1">Prem per afegir</button> 
-</code> 
-   
-I després, en el nostre ''index.js'', ja li afegim el //onclick// (jQuery version): 
-<code javascript index.js> 
-  $('#boto1').click(addElem); 
-</code> 
- 
-En aquest exemple, cridaríem a la funció ''addElem()''. 
- 
-I un darrer apunt, la crida a aquesta funció no pot anar al principi del document, pq en el //head// encara no existeix el nostre //button//. Tenim 2 solucions: 
-  - Posar el tag ''<script src=...'' al final del doc (just després del //button//). 
-  - Posar el codi d'inicialització dins la funció onclick del document, perquè s'executi al acabar de carregar (exemple segueix):<sxh javascript> 
-$(document).ready( function ()  { 
- // initialize 
- $('#addButton').click(addElem); 
- $('#apiButton').click(callAPI); 
-}); 
-</sxh> 
- 
- 
-\\ 
  
 ==== Exercici Tasklist v0.1 ==== ==== Exercici Tasklist v0.1 ====
Línia 115: Línia 67:
 Tasklist: Tasklist:
   - Inicia un projecte Cordova.   - Inicia un projecte Cordova.
-  - Implementa una plantilla amb el [[https://www.npmjs.com/package/cordova-jquery|package NPM cordova-jquery]], tal i com es descriu mes amunt (secció [[#afegint_jquery]]). +  - Crea una llista de tasques d'exemple amb un senzill OL o UL.
-    * Es recomana utilitzar la plantilla ''listView''.+
   - Implementa el **botó d'afegir tasca**.   - Implementa el **botó d'afegir tasca**.
-    * Necessitaràs conèixer [[jQuery|com utilitzar el DOM amb jQuery]]:+    * Necessitaràs conèixer [[jQuery|com utilitzar el DOM amb jQuery]].
     * Afegir elements. El text el podem agafar amb:     * Afegir elements. El text el podem agafar amb:
-      [[https://developer.mozilla.org/es/docs/Web/API/Window/prompt|prompt del navegador]] (és el més senzill). +      - El [[https://developer.mozilla.org/es/docs/Web/API/Window/prompt|prompt del navegador]] (és el més senzill). 
-      * ''input form'' a part. +      - Un [[https://jqueryui.com/dialog/#modal-form|modal form de jQuery UI]], que quedarà més vistós :) 
-      * Posar el ''input form'' dins un [[https://demos.jquerymobile.com/1.4.5/pages-dialog/|Dialog de jQuery Mobile]]. +    * Tingues en compte la documentació oficial de la jQuery UICal fer-ho correctament per tal que ens apliqui els estils CSS adequats quan insertem un nou element.
-    * Tingues en compte la [[https://api.jquerymobile.com/listview/|documentació oficial de la jQuery mobile listview]]En particular mira el mètode ''refresh()'' que ens aplicarà els estils perquè quan insertem un nou element a la listview quedi amb els estils CSS adequats.+
 </WRAP> </WRAP>
  
 \\ \\
 +
  
 ==== Exercici Tasklist v0.2 ==== ==== Exercici Tasklist v0.2 ====
 +
 +{{tasklist2.png?200}} {{tasklist1.png?200}}
  
 <WRAP todo> <WRAP todo>
 Continua de l'anterior exercici Tasklist v0.1: Continua de l'anterior exercici Tasklist v0.1:
   - Implementa un **botó Elimina** dins de cada element de la llista que esborri aquell element. Convé fer-ho en la pròpia creació de l'element ''jQuery''.   - Implementa un **botó Elimina** dins de cada element de la llista que esborri aquell element. Convé fer-ho en la pròpia creació de l'element ''jQuery''.
-    * Per saber més [[https://demos.jquerymobile.com/1.4.3/listview/|sobre jQuery UI listview]]+    * Enlloc d'assignar la //callback// en el ''onclick="elimina()"'' del botó, assigneu-la d'aquesta manera, que és la bona pràctica recomanada en general:<code javascript>$(".boto_eliminar").click(elimina);</code>On ''elimina'' és la funció que cridarem per esborrar l'element
-    * Per eliminar un element del DOM caldrà saber //quin// element està cridant (caller). [[https://stackoverflow.com/questions/945201/how-to-get-the-caller-event-and-dom-element-id|Aquest post explica com obtenir el caller]]:<code javascript>function Hello(e){ +    * Per eliminar un element del DOM caldrà saber **//quin// element està cridant (caller)**. [[https://stackoverflow.com/questions/945201/how-to-get-the-caller-event-and-dom-element-id|Aquest post explica com obtenir el caller]]:<code javascript>function elimina(event){ 
-    var caller = e.target || e.srcElement;+    var caller = event.target || event.srcElement;
     console.log( caller );     console.log( caller );
 }</code> }</code>
     * Busca la funció jQuery per a eliminar un element.     * Busca la funció jQuery per a eliminar un element.
     * Busca la funció jQuery per a accedir al pare d'un element per poder esborrar el ''<li>'' (si no, esborraràs el botó i prou).     * Busca la funció jQuery per a accedir al pare d'un element per poder esborrar el ''<li>'' (si no, esborraràs el botó i prou).
-  - Implementa un **botó Edita** dins de cada element de la llista que ens porti a una altra pàgina que ens permeti editar la tasca+  - Implementa un **botó Edita** dins de cada element de la llista
-    * Mireu l'exemple inicial on cada element de la llista ens porta una pàgina. En tenim prou amb tenir dues pàgines: la //home// (on hi ha la ''listview'' i la pàgina //edita//. +  - La funció d'edició la podem realitzar de diverses formes: 
-    És probable (depenent de la implementació que hagis fet) que quan vulguis editar el text de la tasca (està dintre d'un <a>) et trobis que et posa també el text dels elements fills (botons d'esborrar i/o editar). [[https://stackoverflow.com/questions/3442394/using-text-to-retrieve-only-text-not-nested-in-child-tags|En aquest post s'explica una solució molt eleganṭ]] per eliminar el text dels botons i deixar el de la task sola.+    - La més elegant: utilitzar el ''Dialog'' de jQuery UI per demanar l'usuari que entri el nou text
 +    - Buidant l'element ''<li>'' que volem editar i creant dins un ''<input>''botó de OK com a la imatge. Després caldrà agafar el text i ficar-ho dins l'element de la tasca. 
 +    - Demanant amb el //prompt//, que de fet és la opció més senzilla (però també la menys vistosa)
 +   - És probable (depenent de la implementació que hagis fet) que quan vulguis editar el text de la tasca (està dintre d'un <a>) et trobis que et posa també el text dels elements fills (botons d'esborrar i/o editar). [[https://stackoverflow.com/questions/3442394/using-text-to-retrieve-only-text-not-nested-in-child-tags|En aquest post s'explica una solució molt eleganṭ]] per eliminar el text dels botons i deixar el de la task sola.
 </WRAP> </WRAP>
  
Línia 175: Línia 131:
 <WRAP todo> <WRAP todo>
 Fes la //tasklist// persistent utilitzant el ''localStorage'', tal i com s'explica més amunt. Fes la //tasklist// persistent utilitzant el ''localStorage'', tal i com s'explica més amunt.
 +</WRAP>
 +
 +\\
 +
 +===== Seguretat en Cordova =====
 +<WRAP important>
 +Cordova ens deixa crear qualsevol pàgina HTML amb el codi que ens sembli bé. Però si ens fixem en la plantilla al crear de zero un projecte, ens trobem algunes particularitats que cal parar atenció, sobretot el **tag META amb el Content-Security-Policy**:
 +<WRAP prewrap>
 +<code html>
 +<meta http-equiv="Content-Security-Policy" content="default-src 'self' data: https://ssl.gstatic.com 'unsafe-eval'; style-src 'self' 'unsafe-inline'; media-src *; img-src 'self' data: content:;">
 +</code>
 +</WRAP>
 +
 +Aquest tag META bàsicament ens limita certes accions de l'HTML que podrien fer vulnerable el nostre codi. Entre d'altres, no ens deixa connectar a webs externes si no les validem dins del tag. I tampoc ens permet posar codi //inline//.
 +</WRAP>
 +
 +Típicament podríem fer una aplicació en JavaScript en una pàgina HTML i podríem posar botons que cridin a funcions del nostre codi amb un //onclick// (el què coneixem per crida //inline//). Doncs bé, Cordova no ens deixa fer //inlines// com aquest:
 +
 +<WRAP alert>
 +Aquesta solució funcionaria en una web normal, però **no funciona si posem el tag META de Content-Security-Policy**:
 +
 +<code html><button id="boto_esborrar" onclick="esborra()">Esborra</button></code>
 +
 +</WRAP>
 +
 +Forma de solventar-ho: fer els botons més senzills, sense //onclick// (però amb //id//):
 +<code html index.html>
 +  <button id="boto1">Prem per afegir</button>
 +
 +  <!-- al final del body carreguem les llibreries de Cordova i la de la nostra app -->
 +  <script src="cordova.js"></script>
 +  <script src="js/index.js"></script>
 +</code>
 +  
 +I després, en el nostre ''index.js'', ja li afegim el //onclick// per cridar la funció ''addElem'':
 +
 +<tabbox JavaScript>
 +<code javascript index.js>document.getElementyById('boto1').onclick(addElem);</code>
 +<tabbox jQuery>
 +<code javascript index.js>$('#boto1').click(addElem);</code>
 +</tabbox>
 +
 +\\
 +
 +===== Inicialitzacions =====
 +
 +==== Inicialitzacions HTML ====
 +
 +Abans d'executar codi JavaScript sol convenir esperar a que estigui carregat tot el document. Tenim 2 estratègies bàsiques:
 +  - Posar el tag ''<script src=...'' al final del document HTML.
 +  - Posar el codi d'inicialització dins la funció onclick del document, perquè s'executi al acabar de carregar (exemple segueix):<tabbox jQuery>
 +Estil jQuery amb la funció ''ready'':
 +<code javascript>
 +$(document).ready( function ()  {
 +    // inicialitzar: assignar events
 +    $('#addButton').click(addElem);
 +    $('#apiButton').click(callAPI);
 +});
 +</code>
 +<tabbox JavaScript>
 +<code javascript>
 +function inicialitza() {
 +    // inicialitzar: assignar events
 +    document.getElementById("addButton").onclick = addElem;
 +    document.getElementById("apiButton").onclick = callAPI;
 +}
 +
 +// associem l'event "onload" del document a la funció inicialitza
 +window.addEventListener("load", inicialitza, false);
 +</code>
 +</tabbox>
 +
 +==== Inicialitzacions Cordova ====
 +Cordova necessita inicialitzar el //hardware// del dispositiu. Per això és important que al nostre codi carreguem les llibreries. Si és una aplicació com la //tasklist// que només dibuix per pantalla segurament no li caldria. Però si volem accedir a la càmera o al sistema d'arxius del dispositiu serà imprescindible carregar aquestes llibreries:
 +
 +<code html index.html>
 +<body>
 +
 +  ...
 +
 +  <!-- carreguem les llibreries de Cordova i la de la nostra app -->
 +  <script src="cordova.js"></script> <!-- dispara event ondeviceready -->
 +  <script src="js/index.js"></script>
 +</body>
 +</code>
 +
 +La línia del HTML que carrega ''cordova.js'' dispararà un event "ondeviceready" propi de Cordova. Al nostre codi podem començar a realitzar accions quan es rebi aquest event:
 +
 +<code javascript index.js>
 +document.addEventListener('deviceready', onDeviceReady, false);
 +
 +function onDeviceReady() {
 +    // aquí ja podem fer accions amb la càmera, arxius, etc.
 +}
 +</code>
 +
 +<WRAP todo>
 +Fes una **versió v0.4 de la Tasklist** aplicant el tag META de seguretat i les inicialitzacions pertinents.
 </WRAP> </WRAP>
  
Línia 224: Línia 278:
 </WRAP> </WRAP>
  
-==== AJAX amb jQuery ====+==== Exemple AJAX amb API Musicbrainz.org ====
 Aquestes mateixes les podem demanar des d'un document/aplicació HTML+JS amb crides asíncrones, el que solem conèixer per AJAX. Utilitzarem [[http://api.jquery.com/jquery.ajax/|AJAX amb jQuery]] que ens ajudarà a simplificar el codi. Els exemples estan a la mateixa documentació, però us poso aquí un d'essencial per fer la crida i que ens retorni un objecte JSON de la API de musicbrainz.org : Aquestes mateixes les podem demanar des d'un document/aplicació HTML+JS amb crides asíncrones, el que solem conèixer per AJAX. Utilitzarem [[http://api.jquery.com/jquery.ajax/|AJAX amb jQuery]] que ens ajudarà a simplificar el codi. Els exemples estan a la mateixa documentació, però us poso aquí un d'essencial per fer la crida i que ens retorni un objecte JSON de la API de musicbrainz.org :
  
 +<tabbox JavaScript>
 +<code javascript>
 +fetch('https://musicbrainz.org/ws/2/artist?query=queen&fmt=json')
 +  .then(response => {
 +      if (!response.ok) {
 +          throw new Error('Error de xarxa.');
 +      }
 +      return response.json();
 +  })
 +  .then(data => {
 +    // iterem pels diversos elements de l'array artists
 +    for( const artist of data.artists ) {
 +      console.log(`${artist.name} (${artist.disambiguation}`)
 +      // pintar l'HTML necessari...
 +    }
 +  })
 +  .catch(error => {
 +    console.error('Error en obtenir les notícies:', error);
 +  });
 +</code>
 +<tabbox jQuery>
 <code javascript> <code javascript>
 $.ajax({ $.ajax({
Línia 232: Línia 307:
   url: "https://musicbrainz.org/ws/2/artist?query=queen",   url: "https://musicbrainz.org/ws/2/artist?query=queen",
   dataType: "json",   // necessitem això pq ens retorni un objecte JSON   dataType: "json",   // necessitem això pq ens retorni un objecte JSON
-}).done(function (msg) { +}).done(function (data) { 
-  for(let item in msg.artists) { +  for(let item in data.artists) { 
-    console.log(msg.artists[item])+    var artista = data.aritsts[item].name; 
-    // aquí caldría fer mes coses, of course...+    var descripcio = data.aritsts[item].disambiguation; 
 +    console.log(`${artista} (${descripcio}`) 
 +    // aquí caldria pintar l'HTML necessari
     // ...     // ...
   };   };
Línia 242: Línia 319:
 }); });
 </code> </code>
 +</tabbox>
  
 Cal tenir en compte que les URLs a les que cridis amb AJAX han de tenir habilitada la capçalera de CORS (Cross-Origin Resource Sharing). Les APIs solen tenir-ho habilitat. Totes les APIs públiques ho tenen activat. Cal tenir en compte que les URLs a les que cridis amb AJAX han de tenir habilitada la capçalera de CORS (Cross-Origin Resource Sharing). Les APIs solen tenir-ho habilitat. Totes les APIs públiques ho tenen activat.
Línia 282: Línia 360:
 </WRAP> </WRAP>
  
-==== Public APIs lists ====+==== Public API lists ====
 <WRAP tip> <WRAP tip>
 [[https://github.com/public-apis/public-apis|En aquest repositori hi ha un llistat de public APIs]] per poder fer aplicacions amb les seves dades. [[https://github.com/public-apis/public-apis|En aquest repositori hi ha un llistat de public APIs]] per poder fer aplicacions amb les seves dades.
  
-[[https://api.spaceflightnewsapi.net/v3/documentation#/|Mira't la documentació d'aquesta de space news]] ja que és força clara per començar.+[[https://api.spaceflightnewsapi.net/v4/docs/|Mira't la documentació d'aquesta de space news]] ja que és força clara per començar.
  
 Fes-li un cop d'ull i troba el teu //hobby// en una API! Fes-li un cop d'ull i troba el teu //hobby// en una API!
Línia 298: Línia 376:
 Aprofitant el codi que hem fet amb l'API de musicbrainz.com , fes una nova app que utilitzi la [[https://api.spaceflightnewsapi.net/v3/documentation|API de spaceflight news]]: Aprofitant el codi que hem fet amb l'API de musicbrainz.com , fes una nova app que utilitzi la [[https://api.spaceflightnewsapi.net/v3/documentation|API de spaceflight news]]:
   * Al **tab1** posa un botó que carregui una llista de notícies (mostrant només el títol).   * Al **tab1** posa un botó que carregui una llista de notícies (mostrant només el títol).
-    * Utilitza les [[https://materializecss.com/collections.html|Collections de MaterializeCSS]] per donar-li una formatació adequada. Cada ítem de la llista ha de tenir un //link// que carregui les dades complertes al tab2 i hi salti al clicar. +    * Utilitza les [[https://materializeweb.com/collections.html|Collections de MaterializeCSS]] per donar-li una formatació adequada. Cada ítem de la llista ha de tenir un //link// que carregui les dades complertes al tab2 i hi salti al clicar. 
-    * Per saltar al //tab2// necessitaràs consultar la [[https://materializecss.com/tabs.html|doc dels tabs de Materialize i anar a la secció "Methods"]] i cridar el mètode "select"La versió jQuery seria així:<WRAP prewrap><code javascript> +    * Per saltar al //tab2// necessitaràs consultar la [[https://materializeweb.com/tabs.html|doc dels tabs de Materialize i anar a la secció "Methods"]] i cridar el mètode "select"Segons la doc es faria així:<WRAP prewrap><code javascript> 
-$('.tabs').tabs("select","test-swipe-2");+var elems = document.getElementsByClassName('tabs')
 +var instance = M.Tabs.getInstance(elems[0]); 
 +instance.select('test-swipe-2');
 </code></WRAP> </code></WRAP>
   * Al **tab2** posa la notícia complerta amb la imatge. Formata-la adequadament. Probablement hauràs de fer una altra crida a la API per carregar els detalls de l'article concret, cercant-lo per ID.   * Al **tab2** posa la notícia complerta amb la imatge. Formata-la adequadament. Probablement hauràs de fer una altra crida a la API per carregar els detalls de l'article concret, cercant-lo per ID.
     * Poseu //links// a les notícies originals. El problema és que salta dins de la pròpia app. En realitat el què voldrem és que l'obri al navegador del mòbil, això ho podem aconseguir així:<WRAP prewrap><code html>     * Poseu //links// a les notícies originals. El problema és que salta dins de la pròpia app. En realitat el què voldrem és que l'obri al navegador del mòbil, això ho podem aconseguir així:<WRAP prewrap><code html>
 <a href="#" onclick="window.open('http://www.nasa.com/abc.html', '_system'); return false;">Notícia original.</a></code></WRAP> <a href="#" onclick="window.open('http://www.nasa.com/abc.html', '_system'); return false;">Notícia original.</a></code></WRAP>
-  * Al **tab3** carregarem la llista de notícies amb [[https://materializecss.com/cards.html|Materialize Cards]] o bé utilitzant la [[https://materializecss.com/grid.html|Grid de Materialize amb containers, row i col]], l'exemple "Example Promotion Table" ens anirà molt bé.+  * Al **tab3** carregarem la llista de notícies amb [[https://materializeweb.com/cards.html|Materialize Cards]] o bé utilitzant la [[https://materializeweb.com/grid.html|Grid de Materialize amb containers, row i col]], l'exemple "Example Promotion Table" ens anirà molt bé.
  
 </WRAP> </WRAP>
Línia 313: Línia 393:
 ===== Plugins ===== ===== Plugins =====
  
-  * [[https://cordova.apache.org/docs/en/latest/reference/cordova-plugin-camera/|cordova-camera-plugin]] permet capturar fotos amb la càmera del dispositiu mòbil.+  * **cordova-plugin-camera**: permet capturar fotos amb la càmera del dispositiu mòbil (o del //browser//). 
 +    * [[https://github.com/apache/cordova-plugin-camera|cordova-camera-plugin doc a Github.com]] 
 +    * [[https://www.npmjs.com/package/cordova-plugin-camera|cordova-camera-plugin doc a NPM]] 
 +    * [[https://cordova.apache.org/docs/en/latest/reference/cordova-plugin-camera/|cordova-camera-plugin doc a cordova.org]] DEPRECATED
     * [[https://github.com/apache/cordova-plugin-camera/issues/761|Solució a l'error "Not allowed to load..."]]. Necessitaràs també el [[https://cordova.apache.org/docs/en/latest/reference/cordova-plugin-file/index.html|file plugin]].     * [[https://github.com/apache/cordova-plugin-camera/issues/761|Solució a l'error "Not allowed to load..."]]. Necessitaràs també el [[https://cordova.apache.org/docs/en/latest/reference/cordova-plugin-file/index.html|file plugin]].
-  * [[https://github.com/bitpay/cordova-plugin-qrscanner|cordova-plugin-qrscanner]]+  * **cordova-plugin-qrscanner**: per capturar codis QR 
 +    * [[https://github.com/bitpay/cordova-plugin-qrscanner|doc oficial de cordova-plugin-qrscanner]]
     * Necessitaràs [[https://github.com/bitpay/cordova-plugin-qrscanner/issues/356|parxejar el codi del plugin]] pq funcioni amb Cordova >= v10.0     * Necessitaràs [[https://github.com/bitpay/cordova-plugin-qrscanner/issues/356|parxejar el codi del plugin]] pq funcioni amb Cordova >= v10.0
  
cordova.1702326792.txt.gz · Darrera modificació: 2023/12/11 20:33 per enric_mieza_sanchez