2009-12-15 6 views
16

Est-il possible de détecter si le client prend en charge un caractère Unicode particulier ou s'il sera rendu comme une boîte de glyphes manquante?Détection de la prise en charge des caractères Unicode individuels avec JavaScript

Important: Support en autant de navigateurs que possible

Non importante: l'efficacité, la vitesse ou l'élégance

La seule méthode que je peux penser à essayer est d'utiliser une toile, alors je pensais que je demanderais avant que je commence à descendre cette route.

Merci!

Éditer: Ceci n'est pas destiné à être utilisé sur un site Web public; J'essaie juste de compiler une liste de caractères supportés par chaque navigateur.

+2

Pourquoi cette question wiki communautaire? –

+0

Je ne me suis pas rendu compte qu'il y avait un inconvénient à marquer une question wiki communautaire. Mon erreur. –

+1

L'ensemble des caractères qui seront affichés par un navigateur dépend plus des polices que l'utilisateur a installées que de son navigateur. Presque tous les navigateurs prennent en charge Unicode, et la plupart des personnages n'ont pas besoin de manipulation particulière. –

Répondre

-3

Si vous souhaitez optimiser la prise en charge du navigateur, vous ne souhaitez probablement pas utiliser le javascript. De nombreux navigateurs mobiles ne le prennent même pas en charge.

Si le navigateur ne supporte pas un ensemble de char, quelle est la solution de repli? Afficher le contenu dans une autre langue? Peut-être un lien entre le site qui change de langue à la demande serait plus robuste.

+1

J'essaie de compiler une liste de caractères supportés par chaque navigateur, pas de maximiser le support pour une page publique. –

8

Ceci est plus d'une idée folle qu'une vraie réponse:

Si vous pouviez trouver un personnage que vous saviez serait toujours rendu comme une boîte de glyphe manquant, vous pouvez utiliser la même technique que ce javascript font detector --render le personnage et la boîte de glyphes manquante hors écran et comparer leurs largeurs. Si elles sont différentes, alors vous savez que le personnage n'est pas rendu comme une boîte de glyphes manquante. Bien sûr, cela ne fonctionnera pas du tout pour les polices à largeur fixe, et il pourrait y avoir beaucoup de négatifs fixes pour d'autres polices où beaucoup de caractères ont la même largeur.

+0

Merci! Cela aide beaucoup. Bien sûr, cela ne fonctionnera pas pour les caractères qui ont la même largeur et la même hauteur qu'une boîte de glyphes manquante, mais c'est un pas dans la bonne direction. –

+1

cela ne fonctionnera pas pour tous les caractères, mais si vous augmentez la taille de la police, vous devriez obtenir de bons résultats. J'aime toujours cette réponse ... une sorte de wierd mais pourrait-elle fonctionner :-) – TheHippo

+0

@Hippo - c'est un bon point: puisque les polices sont rendues hors écran, vous pouvez les rendre vraiment vraiment énormes. – Annie

-2

Vous pouvez toujours évaluer chaque caractère à l'aide de la méthode charCodeAt(). Cela renverra la valeur du caractère Unicode. En fonction de ce que vous faites, vous pouvez restreindre la plage que vous voulez accepter comme caractères "valides" ... Si vous copiez le caractère qui est dans la "boîte", vous pouvez utiliser un traducteur de caractères sur le web pour voir ce que la valeur unicode correspondante est.

Voici un que je googlé et trouvé: enter link description here

2

Je ne sais pas si elle peut compter sur l'avenir (les navigateurs pourraient changer ce qui est montré pour les caractères non pris en charge), je ne suis pas sûr que cela est optimisé (comme je ne comprennent pas bien les limites idéales à mesurer ici), mais l'approche suivante (dessiner un texte sur toile et inspecter le résultat sous forme d'image) peut, si elle est examinée, fournir une vérification plus fiable et plus précise que largeur. Tout le code au début est juste une détection de navigateur que nous devons utiliser puisque la détection de fonction n'est pas possible.

(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); 

MISE À JOUR 1

J'ai essayé de mettre à jour pour Firefox moderne (pour essayer de vérifier les chiffres hexadécimaux attendus dans la toile), et en vérifiant que, contrairement à mon code ci-dessus, la toile (et le motif pour le faire correspondre) était juste assez grand pour accueillir le plus grand caractère par context.measureText() (U + 0BCC de mes tests, bien que probablement dépend de la police, dans mon cas "Arial Unicode MS"). Par https://bugzilla.mozilla.org/show_bug.cgi?id=442133#c9, cependant, measureText répond actuellement par erreur au zoom pour seulement les caractères inconnus. Maintenant, si seulement un pouvait simuler le zoom dans le canevas JavaScript afin d'affecter ces mesures (et seulement ces mesures) ...

code disponible pour référence à https://gist.github.com/brettz9/1f061bb2ce06368db3e5

+0

La solution de Brett ne fonctionne plus dans Firefox puisqu'elle affiche maintenant le codepoint Unicode hexadécimal dans une boîte quand il ne peut pas trouver de personnage. –

+0

@AnonymousCoward: mise à jour avec un autre obstacle pour Firefox en ce moment ... –

Questions connexes