Visualizzazione post con etichetta jquery. Mostra tutti i post
Visualizzazione post con etichetta jquery. Mostra tutti i post

sabato 10 gennaio 2015

Summernote - un editor WYSIWYG per Bootstrap

Oggi presento Summernote, un editor WYSIWYG per Bootstrap molto ben fatto. Tra le caratteristiche che lo rendono un ottimo prodotto (a mio parere) sono la facilità di installazione, la gestione del menù personalizzata e la possibilità di mostrare il sorgente del testo immesso.

Installazione

Si può installare direttamente dai sorgenti oppure tramite bower:
bower install summernote

Dipendenze

Utilizza ovviamente Bootstrap (e jQuery), assieme a font-awesome. Questo significa che è necessario includere i seguenti file (se non sono già inclusi nella pagina html):
<link href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.min.css" rel="stylesheet"></link>

<!-- include summernote css/js-->
<link href="summernote.css" rel="stylesheet"></link>
<script src="summernote.min.js"></script>

Inserimento del codice html e javascript

Un semplice <div> verrà trasformato in un editor Summernote con poche righe di codice javascript:
<div id="summernote">Hello Summernote</div>
<script>
$(document).ready(function() {
  $('#summernote').summernote();
});
</script>

Risultato


:-)

lunedì 7 aprile 2014

Includere un file html esterno con jQuery

Un semplice snippet per includere dinamicamente il contenuto html di un file esterno con jQuery:

 $('body').append($('<div></div>').load('file_esterno.html', function() {
   //Qui operazioni opzionali sull'html appena caricato
 });
:-)

giovedì 3 aprile 2014

jVectorMap - Mappe geografiche vettoriali in Javascript

jVectoMap è una utile libreria che permette di mostrare ed interagire con mappe geografiche vettoriali in Javascript. Il vantaggio di questo progetto, oltre a quello di essere open source, è che utilizza tecnologie native dei browser, quindi html, javascript, svg o vml, css, senza bisogno di plugin aggiuntivi. La sezione tutorial è molto ben fatta, ne consiglio una attenta lettura.
Qualche tempo fa ho avuto bisogno di sfruttare questa libreria per mostrare una mappa geografica della provenienza dei preventivi richiesti dagli utenti su un determinato sito web. Per ottimizzare tutto però ho voluto caricare i dati relativi al numero dei preventivi dei singoli stati in ajax con il formato JSON, vediamo come.
<div id="mappamondo-richieste" style="height:350px;width:100%;"></div>

$.ajax({
   type: "GET",
   url: 'http://api.example.com/stats/world/',
   dataType: "json",
   }).done(function( json_response ) { 
                            
     $('#mappamondo-richieste').vectorMap({
      map: 'world_mill_en',
      series: {
        regions: [{
          values: json_response.worldData,
          scale: ['#C8EEFF', '#0071A4'],
          normalizeFunction: 'polynomial'
        }]
      },
      onRegionLabelShow: function(e, el, code){
        if(!json_response.worldData[code]) json_response.worldData[code] = 0;
          el.html(el.html()+' ('+json_response.worldData[code]+')');
        }
      });
                            
    }).fail(function(jqXHR, textStatus) {
       console.log( "Request failed: " + textStatus + " " + jqXHR.status );
    });

La mappa utilizzata è la world_mill_en, ossia rappresenta l'intero globo terrestre. Le sigle delle nazioni seguono il formato a due lettere (ad esempio IT per Italia, FR per Francia, DE per Germania, ecc.).
L'url richiamata è una API (nel mio progetto scritta in Php) che risponde in formato JSON con una particolare struttura, ad esempio:
{
  "worldData":
  {
    "IT":"97",
    "US":"357"
  }
}
Il risultato finale non delude le mie aspettative :-)

lunedì 20 gennaio 2014

Crono, un Time Tracker open source in php codeigniter

Dopo qualche settimana di lavoro vi presento Crono, una web application per il time tracking open source (quindi è gratuito) scritta in Php.
Specifico che il software è formato da un sistema di APIs sviluppato in Codeigniter e un frontend che si basa su Twitter Bootstrap e jQuery. Il DBMS utilizzato è MySql.
Per utilizzarlo potete clonare il repository (sempre aggiornato) oppure scaricare la versione 1.0.
Dopo averlo copiato nella cartella wwwroot di un webserver che supporti il php è necessario visitare da un browser la cartella install per installarlo correttamente.

Crono ha le seguenti caratteristiche:
  • registrazione e gestione di attività (task) sia live che manuali, collegate a progetti
  • gestione progetti
  • gestione clienti
  • gestione utenti
  • sistema di installazione

Qualche screenshot di Crono:









martedì 17 gennaio 2012

Programmazione Android: Costruire una web application (seconda parte) - jQuery Mobile

In questa seconda parte incontriamo jQuery Mobile, una versione del famoso framework appositamente creata per gestire e mostrare contenuti per dispositivi quali smartphone e tablet. E' possibile analizzarne il comportamento accedendo alla demo disponibile, che mostra tutti i componenti utili per realizzare una splendida web application. Ovviamente la cosa più semplice è scaricare l'intero framework, caricarlo sul sito che farà da base per l'applicazione web, studiarsi il sorgente html + javascript della demo e modificarlo a piacimento; vediamo però a grandi linee quale sia la struttura:
Header
<!DOCTYPE html> 
<html> 
 <head> 
 <title>My Page</title> 
 <meta name="viewport" content="width=device-width, initial-scale=1"> 
 <link rel="stylesheet" href="http://code.jquery.com/mobile/1.0/jquery.mobile-1.0.min.css" />
 <script src="http://code.jquery.com/jquery-1.6.4.min.js"></script>
 <script src="http://code.jquery.com/mobile/1.0/jquery.mobile-1.0.min.js"></script>
</head> 
Fino a qui niente di particolare: in sostanza il caricamento delle librerie necessarie al funzionamento di jQuery Mobile. Da notare però la parola chiave "viewport" all'interno di un meta tag, fondamentale per l'impostazione delle dimensioni dello schermo per il risultato finale html.

Body
<body> 

<div data-role="page">

 <div data-role="header">
  <h1>My Title</h1>
 </div><!-- /header -->

 <div data-role="content"> 
  <p>Hello world</p>  
 </div><!-- /content -->

</div><!-- /page -->

</body>
</html>
Da questa parte di codice si comprende come una pagina sia indicata come una div con attributo "data-role" impostato su "page". La barra di navigazione in alto a sua volta avrà ruolo "header", mentre il contenuto vero e proprio della pagina avrà ruolo "content".

L'idea di base è quella di mostrare un sito (o una sezione di sito) appositamente sviluppato con jQuery Mobile all'interno dell'applicazione Android; all'utente sarà quindi invisibile se questa parte sia sviluppata con il framework Android o con il più immediato e graficamente appagante html, css e javascript. Ovviamente, riprendendo il codice del post precedente, è sufficiente modificare la pagina alla quale l'oggetto webView si deve connettere:
webView1.loadUrl("http://code.jquery.com/mobile/latest/demos/");
Ho chiaramente usato l'url del demo per semplicità; andrà sostituito con la parte del sito mobile che avrete destinato ad Android (ad esempio, www.example.com/android).
Per terminare questa parte, mostro un piccolo accorgimento grafico: se si prova ad eseguire l'applicazione android creata in precedenza si nota una fastidiosa barra in alto, con il nome dell'applicazione. Questa barra può essere migliorata graficamente (e lo mostrerò nei post successivi) oppure, più facilmente, può essere nascosta. Per fare quest'ultima operazione è sufficiente aprire il file manifest AndroidManifest.xml e creare, all'interno del tag activity principale, l'attributo "android:theme", impostandolo ad un determinato valore. Vediamo il risultato:
<?xml version="1.0" encoding="utf-8"?>  
<manifest xmlns:android="http://schemas.android.com/apk/res/android"  
    package="net.stefanobianchini.webapp"  
    android:versionCode="1"  
    android:versionName="1.0" >  
  
    <uses-sdk android:minSdkVersion="10" />  
    <uses-permission android:name="android.permission.INTERNET"/>  
    <application  
        android:icon="@drawable/ic_webapp"  
        android:label="@string/app_name" >  
        <activity  
            android:name=".webappActivity"  
            android:label="@string/app_name" 
            android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen">  
            <intent-filter>  
                <action android:name="android.intent.action.MAIN" />  
  
                <category android:name="android.intent.category.LAUNCHER" />  
            </intent-filter>  
        </activity>  
    </application>  
  
</manifest>
Questa direttiva chiederà ad Android di mostrare l'applicazione a tutto schermo, senza la fastidiosa TitleBar. In figura il risultato finale, visualizzato dentro l'emulatore:

martedì 13 dicembre 2011

FullCalendar - un calendario jQuery con agenda e drag & drop

Per un piccolo gestionale medico ultimamente mi è capitato sotto mano FullCalendar, un ottimo calendario jQuery "full-size" altamente configurabile. Già dalla home page di questo progetto emergono i punti forti del plugin: eventi di tutto il giorno o schedulati, drag & drop degli eventi, viste per mese, per settimana e vista giornaliera. Il progetto è molto ben documentato, quindi per un utilizzo base rimando ogni spiegazione al sito.
Voglio pubblicare però la configurazione che ho utilizzato, cercando di mostrarne le potenzialità:
$('#calendar_strutture').fullCalendar({
   header: {
    left: 'prev,next today',
    center: 'title',
    right: 'month' //,agendaWeek,agendaDay
   },
   firstHour: 6,
   firstDay: 1,
   allDaySlot : false,
   timeFormat: 'HH:mm',
   monthNames:['Gennaio','Febbraio','Marzo','Aprile','Maggio','Giugno','Luglio','Agosto','Settembre','Ottobre','Novembre','Dicembre'],
   monthNamesShort: ['Gen', 'Feb', 'Mar', 'Apr', 'Mag', 'Giu', 'Lug', 'Ago', 'Set', 'Ott', 'Nov', 'Dic'],
   dayNames: ['Domenica', 'Lunedì', 'Martedì', 'Mercoledì', 'Giovedì', 'Venerdì', 'Sabato'],
   dayNamesShort: ['Dom', 'Lun', 'Mar', 'Mer', 'Gio', 'Ven', 'Sab'],
   buttonText: {
    prev:     ' &#9668 ',  // left triangle
    next:     ' &#9658 ',  // right triangle
    prevYear: ' &lt;&lt; ', // <<
    nextYear: ' &lt;&lt; ', // >>
    today:    'Oggi',
    month:    'Mese',
    week:     'Settimana',
    day:      'Giorno'
   },
   columnFormat: {
    month: 'ddd',    // Mon
    week: 'd/M ddd', // Mon 9/7
    day: 'dddd d/M'  // Monday 9/7
   },
   editable: true,
   
   events: {
    url: 'lista_calendario_strutture.php',
    cache: true,
    //color: 'purple',   // a non-ajax option
          textColor: 'white' // a non-ajax option
   },
   lazyFetching: false,
     
   eventClick: function(calEvent) {
    if(confirm("Elimino dal calendario la disponibilita' della struttura per il giorno selezionato?")) {
     $.ajax({
       url: "interventi.php?section=calendario_strutture&action=delete",
       type: 'POST',
       data: {
      struttura: calEvent.title,
      data: calEvent.start.getTime()
       },
       success: function(msg){
      //alert(msg); //debug
      $('#calendar_strutture').fullCalendar('removeEvents',calEvent.id); 
       },
       error: function() {
      revertFunc();
       }
     });
    }
   },
   
   eventMouseover: function(calEvent) {
    $(this).find('.fc-event-title').html('<img src="template/default/admin/assets/images/delete.png" /> '+calEvent.title);
   },
   
   eventMouseout: function(calEvent) {
    $(this).find('.fc-event-title').html(calEvent.title);  
   },
   
   eventDrop: function(calEvent,dayDelta,minuteDelta,allDay,revertFunc) {
    //Qui ajax per spostamento evento
    $.ajax({
      url: "interventi.php?section=calendario_strutture&action=move",
      type: 'POST',
      data: {
     struttura: calEvent.title,
     movimento: dayDelta,
     nuova_data: calEvent.start.getTime()
               },
      success: function(msg){
     //alert(msg);
      },
      error: function() {
     revertFunc();
      }
    });
   },
   droppable: true,
   drop: function(date, allDay) { // this function is called when something is dropped
   
    // retrieve the dropped element's stored Event Object
    var originalEventObject = $(this).data('eventObject');
    
    // we need to copy it, so that multiple events don't have a reference to the same object
    var copiedEventObject = $.extend({}, originalEventObject);
    
    var today = new Date();
    
    // assign it the date that was reported
    copiedEventObject.id = today.getTime();
    copiedEventObject.start = date;
    copiedEventObject.allDay = allDay;
    
    //alert(copiedEventObject.title + ' ' + copiedEventObject.start.getTime());
    
    //Qui ajax per inserimento disponibilita in calendario struttura
    $.ajax({
      url: "interventi.php?section=calendario_strutture&action=insert",
      type: 'POST',
      data: {
     struttura: copiedEventObject.title,
     data: copiedEventObject.start.getTime()
               },
      success: function(msg){
     //alert(msg); //debug
     // render the event on the calendar
     $('#calendar_strutture').fullCalendar('renderEvent', copiedEventObject, false);
      }
    });
    
   }
   
  });

$('#external-events div.external-event').each(function() {

 // create an Event Object (http://arshaw.com/fullcalendar/docs/event_data/Event_Object/)
 // it doesn't need to have a start or end
 var eventObject = {
  title: $.trim($(this).text()), // use the element's text as the event title
  backgroundColor: $(this).css('background-color')
 };
 
 // store the Event Object in the DOM element so we can get to it later
 $(this).data('eventObject', eventObject);
 
 // make the event draggable using jQuery UI
 $(this).draggable({
  zIndex: 999,
  revert: true,      // will cause the event to go back to its
  revertDuration: 0  //  original position after the drag
 });
 
});

Questa prima parte, che deve essere contenuta nella parte relativa a $(document).ready(...), specifica il comportamento del calendario, in particolare:
  1. deve poter gestire, tramite chiamate ajax, lo spostamento degli eventi (eventDrop), che in questo caso particolare, sono "disponibilità" delle sale operatorie in determinate strutture ospedaliere
  2. deve gestire l'eliminazione delle disponibilità, mediante click del mouse (eventClick) sull'evento stesso (notare che quando il mouse si trova sopra l'evento viene mostrata una icona "cestino")
  3. deve gestire la creazione delle disponibilità mediante il trascinamento dall'elenco strutture sulla sinistra al calendario (drop), date una occhiata allo screenshot per capire di cosa sto parlando
  4. La parte finale del codice jQuery è relativa al punto 3, fa capire al motore javascript che i
    sulla sinistra deve gestirli come "draggable" e creare un oggetto evento (Event Object) in modo da poterlo poi gestire in FullCalendar.
Di seguito il codice html utilizzato (elenco strutture + calendario):
<div id='wrap' style="width:100%;margin: 0 auto;"> 
                 <div id='external-events' style="float: left;width: 150px;padding: 0 10px;border: 1px solid #ccc;background: #eee;text-align: left;margin-right:20px;">
                  <h4>Elenco Strutture</h4>
                                    <div class='external-event' style="background-color:#0099FF">Struttura Ospedaliera 1</div>
                                    <div class='external-event' style="background-color:#996699">Struttura Ospedaliera 2</div>

                                    </div>
                 <div id='calendar_strutture' style="width: 900px;float:left;"></div>
                 <div style='clear:both'></div>
              </div>
            </div>
Il risultato finale!

mercoledì 27 luglio 2011

jQuery: semplice e veloce slideshow (base)

Girovagando per la rete, mi sono imbattuto in questo codice per creare una veloce slideshow con il framework jQuery.
Ovviamente fare il copia e incolla non è nel mio stile quindi ho apportato qualche piccola modifica nel codice (niente di speciale, tempistiche e stile degli elementi).
Questo perché, se utilizzate direttamente il codice originale, verrà mostrato un effetto non voluto: durante la transizione delle immagini, se ne vedono due in una volta che sembra che facciano a botte tra di loro per mostrarsi (ok, fate prima a provare di persona per capire cosa intendo). 
Per la cronaca, l'autore del codice originale lascia all'utilizzatore finale il compito di aggiungere tutto lo stile CSS. E così ho fatto :-)

Qui di seguito il listato della slideshow personalizzata. Iniziamo con la testata del file html (standard), dove andremo ad inglobare jQuery:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Prova Slideshow</title>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js"></script>
Proseguiamo con il cuore del codice:
<script>
$(function(){
    $('.slideshow img:gt(0)').hide();
    setInterval(function(){$('.slideshow :first-child').fadeOut(1500).next('img').fadeIn(1500).end().appendTo('.slideshow');}, 2400);
});
</script>
Io ho aggiunto la tempistica del fadeOut e del fadeIn (1 secondo e mezzo).
Applichiamo uno stile css adeguato ai nostri scopi: slideshow centrato, sovrapposizione delle immagini per evitare effetto "litigio", eccetera:
<style type="text/css">
body {
 margin:0;
 padding:0;
 text-align:center;
}
.slideshow {
 margin:0 auto;
 padding:0;
 width:618px;
 height:246px;
 border:1px solid #eeeeee;
}
.slideshow img { 
 display:block;
 position:absolute;
}
</style>
E finiamo in bellezza con il codice html dello slideshow (e del resto della pagina)
</head>
<body>
 <div class="slideshow">
  <img src="1.jpg"/>
  <img src="2.jpg"/>
  <img src="3.jpg"/>
 </div>
</body>
</html>

martedì 26 luglio 2011

jQuery: eliminare una riga di una tabella (con richiesta ajax)

Poco tempo fa ho avuto la necessità di sviluppare un piccolo programma di protocollo. Caratteristica base era che ogni documento protocollato poteva avere più mittenti e più destinatari: la cancellazione degli stessi, così come la modifica, doveva avvenire in modo trasparente e veloce, ossia... tramite ajax :-)
Ricercando nel web, mi sono imbattuto in questa soluzione, facilmente adattata alle mie esigenze:
function cancellaMittente(id,num_progressivo,anno_progressivo){
 if (confirm('Sicuro di voler eliminare questo mittente?')) {
  jQuery.post('cancella_mittente.php', {id: +id, num_progressivo: + num_progressivo, anno_progressivo: +anno_progressivo },
  function(){
   jQuery("#mittente_"+id).fadeOut("slow");
  });
 }
}
Questa funzione verrà richiamata ogni volta che si vorrà eliminare un determinato mittente ed eseguirà le operazioni:
  1. esecuzione di una richiesta ajax di tipo post al file cancella_mittente.php con parametro id (dell'anagrafica), num_progressivo e anno_progressivo (questi ultimi identificano il documento protocollato);
  2. fadeOut, e quindi dissolvenza e cancellazione, della riga selezionata (la discriminazione è per id del tag, ad esempio mittente_1
Lato html invece la questione è semplice:
<tr id="destinatario_1">
   <td width="50">
      <a href="#" onclick="cancellaDestinatario(1,12,2011)">
      <img src="img/remove.png" /></a>
   </td>
   <td align="center">Pinco Pallino</td>
</tr>
Il file richiamato via post ajax avrà il compito di eliminare dal database la entry relativa all'id passato per parametro. Di seguito l'implementazione vera, con due parametri (num_progressivo e anno_progressivo) che per semplicità sono stati omessi nei listati precedenti:
<?php

require('engine/config.php');

if(is_numeric($_REQUEST['num_progressivo']) && is_numeric($_REQUEST['anno_progressivo']) && is_numeric($_REQUEST['id'])) {

$ris=$db->query("DELETE FROM ". $__TABLE_PREFIX."protocollo_mittente WHERE mittente_documento_num_progressivo='".$_REQUEST['num_progressivo']."' AND mittente_documento_anno_progressivo='".$_REQUEST['anno_progressivo']."' AND mittente_id_anagrafica='".$_REQUEST['id']."'");

}

?>