2009-12-15 16 views
16

È possibile rilevare se il client supporta un particolare carattere Unicode o se verrà reso come una finestra di glifo mancante?Rilevamento del supporto di caratteri Unicode con JavaScript

Importante: sostegno nel maggior numero possibile di browser

indifferente: Efficienza, velocità, o l'eleganza

L'unico metodo che posso pensare di provare sta usando una tela, quindi ho pensato di chiedere prima di iniziare a percorrere quella strada.

Grazie!

Modifica: non deve essere utilizzato su un sito Web pubblico; Sto solo cercando di compilare un elenco di caratteri supportati da ciascun browser.

+2

Perché questa domanda è wiki della comunità? –

+0

Non mi rendevo conto che c'era un inconveniente nel contrassegnare una wiki della comunità di domande. Errore mio. –

+1

Il set di caratteri che verrà visualizzato da un browser dipende più dai font installati dall'utente che dal browser. Praticamente tutti i browser supportano Unicode e la maggior parte dei personaggi non ha bisogno di alcun tipo di gestione speciale. –

risposta

-3

Se si desidera massimizzare il supporto del browser, probabilmente non si vuole fare affidamento su javascript per nulla. Molti browser mobili non lo supportano nemmeno.

Se il browser non supporta un set di caratteri, che cos'è il fall back? Visualizzazione del contenuto in un'altra lingua? Forse collega un sito che cambia lingua su richiesta sarebbe più robusto.

+1

Sto cercando di compilare un elenco di caratteri supportati da ciascun browser, non massimizzare il supporto per una pagina pubblica. –

8

Questo è più di un'idea selvaggia di una vera risposta:

Se si potesse trovare un carattere che si sapeva sarebbe sempre il rendering come una scatola glifo mancante, è possibile utilizzare la stessa tecnica di questo javascript font detector --render il personaggio e la finestra degli glifo mancanti fuori dallo schermo e confrontano le loro larghezze. Se sono diversi, allora sai che il personaggio non viene mostrato come un glifo mancante. Ovviamente, questo non funzionerà affatto con i font a larghezza fissa, e potrebbe avere molti negativi fissi per altri font dove molti caratteri hanno la stessa larghezza.

+0

Grazie! Questo aiuta molto. Ovviamente, non funzionerà con nessun carattere che abbia la stessa larghezza e altezza di un glifo mancante, ma è un passo nella giusta direzione. –

+1

non funzionerà per ogni carattere, ma se aumenti la dimensione del font dovresti ottenere buoni risultati. Mi piace ancora questa risposta ... una specie di strano, ma potrebbe funzionare :-) – TheHippo

+0

@Hippo - questo è un buon punto: dato che i font sono resi fuori dallo schermo, potresti renderli davvero enormi. – Annie

-2

È sempre possibile valutare ciascun carattere utilizzando il metodo charCodeAt(). Ciò restituirà il valore del carattere Unicode. A seconda di ciò che stai facendo, puoi restringere la gamma di cui vuoi accettare come caratteri "validi" ... Se copi il personaggio che si trova nella "scatola", puoi usare un traduttore di caratteri sul web per vedere cosa il corrispondente valore unicode è.

Ecco quello che ho cercato su google e ho trovato: enter link description here

2

Non so se può essere fatto valere per il futuro (i browser potrebbe cambiare ciò che viene mostrato per i caratteri non supportati), né sono sicuro che questo è ottimizzata (come ho non ho una buona comprensione dei confini ideali da misurare qui), ma il seguente approccio (di disegnare il testo su tela e ispezionare il risultato come un'immagine) può, se revisionato, fornire un controllo più affidabile e accurato di quello che potrebbe controllare il larghezza. Tutto il codice all'inizio è solo il rilevamento del browser che dobbiamo utilizzare poiché il rilevamento delle funzioni non è possibile.

(function() { 

// http://www.quirksmode.org/js/detect.html 
var BrowserDetect = { 
    init: function() { 
     this.browser = this.searchString(this.dataBrowser) || "An unknown browser"; 
     this.version = this.searchVersion(navigator.userAgent) 
      || this.searchVersion(navigator.appVersion) 
      || "an unknown version"; 
     this.OS = this.searchString(this.dataOS) || "an unknown OS"; 
    }, 
    searchString: function (data) { 
     for (var i=0;i<data.length;i++) { 
      var dataString = data[i].string; 
      var dataProp = data[i].prop; 
      this.versionSearchString = data[i].versionSearch || data[i].identity; 
      if (dataString) { 
       if (dataString.indexOf(data[i].subString) != -1) 
        return data[i].identity; 
      } 
      else if (dataProp) 
       return data[i].identity; 
     } 
    }, 
    searchVersion: function (dataString) { 
     var index = dataString.indexOf(this.versionSearchString); 
     if (index == -1) return; 
     return parseFloat(dataString.substring(index+this.versionSearchString.length+1)); 
    }, 
    dataBrowser: [ 
     { 
      string: navigator.userAgent, 
      subString: "Chrome", 
      identity: "Chrome" 
     }, 
     { string: navigator.userAgent, 
      subString: "OmniWeb", 
      versionSearch: "OmniWeb/", 
      identity: "OmniWeb" 
     }, 
     { 
      string: navigator.vendor, 
      subString: "Apple", 
      identity: "Safari", 
      versionSearch: "Version" 
     }, 
     { 
      prop: window.opera, 
      identity: "Opera", 
      versionSearch: "Version" 
     }, 
     { 
      string: navigator.vendor, 
      subString: "iCab", 
      identity: "iCab" 
     }, 
     { 
      string: navigator.vendor, 
      subString: "KDE", 
      identity: "Konqueror" 
     }, 
     { 
      string: navigator.userAgent, 
      subString: "Firefox", 
      identity: "Firefox" 
     }, 
     { 
      string: navigator.vendor, 
      subString: "Camino", 
      identity: "Camino" 
     }, 
     {  // for newer Netscapes (6+) 
      string: navigator.userAgent, 
      subString: "Netscape", 
      identity: "Netscape" 
     }, 
     { 
      string: navigator.userAgent, 
      subString: "MSIE", 
      identity: "Explorer", 
      versionSearch: "MSIE" 
     }, 
     { 
      string: navigator.userAgent, 
      subString: "Gecko", 
      identity: "Mozilla", 
      versionSearch: "rv" 
     }, 
     {  // for older Netscapes (4-) 
      string: navigator.userAgent, 
      subString: "Mozilla", 
      identity: "Netscape", 
      versionSearch: "Mozilla" 
     } 
    ], 
    dataOS : [ 
     { 
      string: navigator.platform, 
      subString: "Win", 
      identity: "Windows" 
     }, 
     { 
      string: navigator.platform, 
      subString: "Mac", 
      identity: "Mac" 
     }, 
     { 
       string: navigator.userAgent, 
       subString: "iPhone", 
       identity: "iPhone/iPod" 
     }, 
     { 
      string: navigator.platform, 
      subString: "Linux", 
      identity: "Linux" 
     } 
    ] 

}; 
BrowserDetect.init(); 


/** 
* Checks whether a given character is supported in the specified font. If the 
* font argument is not provided, it will default to sans-serif, the default 
* of the canvas element 
* @param {String} chr Character to check for support 
* @param {String} [font] Font Defaults to sans-serif 
* @returns {Boolean} Whether or not the character is visually distinct from characters that are not supported 
*/ 
function characterInFont (chr, font) { 
    var data, 
     size = 10, // We use 10 to confine results (could do further?) and minimum required for 10px 
     x = 0, 
     y = size, 
     canvas = document.createElement('canvas'), 
     ctx = canvas.getContext('2d'); 
    // Necessary? 
    canvas.width = size; 
    canvas.height = size; 

    if (font) { // Default of canvas is 10px sans-serif 
     font = size + 'px ' + font; // Fix size so we can test consistently 
     /** 
     // Is there use to confining by this height? 
     var d = document.createElement("span"); 
     d.font = font; 
     d.textContent = chr; 
     document.body.appendChild(d); 
     var emHeight = d.offsetHeight; 
     document.body.removeChild(d); 
     alert(emHeight); // 19 after page load on Firefox and Chrome regardless of canvas height 
     //*/ 
    } 

    ctx.fillText(chr, x, y); 
    data = ctx.getImageData(0, 0, ctx.measureText(chr).width, canvas.height).data; // canvas.width 
    data = Array.prototype.slice.apply(data); 

    function compareDataToBox (data, box, filter) { 
     if (filter) { // We can stop making this conditional if we confirm the exact arrays will continue to work, or otherwise remove and rely on safer full arrays 
      data = data.filter(function (item) { 
       return item != 0; 
      }); 
     } 
     return data.toString() !== box; 
    } 

    var missingCharBox; 
    switch (BrowserDetect.browser) { 
     case 'Firefox': // Draws nothing 
      missingCharBox = ''; 
      break; 
     case 'Opera': 
      //missingCharBox = '0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,197,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,73,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,0,0,0,0,197,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,73,0,0,0,0'; 
      missingCharBox = '197,255,255,255,255,73,36,36,36,36,36,36,36,36,197,255,255,255,255,73'; 
      break; 
     case 'Chrome': 
      missingCharBox = '2,151,255,255,255,255,67,2,26,2,26,2,26,2,26,2,26,2,26,2,26,2,26,2,151,255,255,255,255,67'; 
      break; 
     case 'Safari': 
      missingCharBox = '17,23,23,23,23,5,52,21,21,21,21,41,39,39,39,39,39,39,39,39,63,40,40,40,40,43'; 
      break; 
     default: 
      throw 'characterInFont() not tested successfully for this browser'; 
    } 
    return compareDataToBox(data, missingCharBox, true); 
} 

// EXPORTS 
((typeof exports !== 'undefined') ? exports : this).characterInFont = characterInFont; 

}()); 

var r1 = characterInFont('a', 'Arial'); // true 
var r2 = characterInFont('\uFAAA', 'Arial'); // false 
alert(r1); 
alert(r2); 

UPDATE 1

ho provato ad aggiornare per Firefox moderna (per cercare di verificare la presenza delle cifre esadecimali attesi entro la tela), e controllando che, a differenza del mio codice di cui sopra, la tela (e il modello per abbinarlo) era abbastanza grande da contenere il carattere più ampio per context.measureText() (U + 0BCC dai miei test, anche se presumibilmente dipende dal tipo di carattere, nel mio caso "Arial Unicode MS"). Per https://bugzilla.mozilla.org/show_bug.cgi?id=442133#c9, tuttavia, measureText attualmente risponde erroneamente allo zoom solo per i caratteri sconosciuti. Ora, se solo uno potesse simulare lo zoom nella tela JavaScript in modo da influenzare queste misurazioni (e solo quelle misurazioni) ...

Codice disponibile per riferimento a https://gist.github.com/brettz9/1f061bb2ce06368db3e5

+0

La soluzione di Brett non funziona più in Firefox poiché al giorno d'oggi mostra il codice esadecimale Unicode in una scatola quando non riesce a trovare un personaggio. –

+0

@AnonymousCoward: aggiornato con un altro ostacolo per Firefox al momento ... –