twitst4tz

twitter statistics web application
Log | Files | Refs | README | LICENSE

charset.js (3081B)


      1 /**
      2  * negotiator
      3  * Copyright(c) 2012 Isaac Z. Schlueter
      4  * Copyright(c) 2014 Federico Romero
      5  * Copyright(c) 2014-2015 Douglas Christopher Wilson
      6  * MIT Licensed
      7  */
      8 
      9 'use strict';
     10 
     11 /**
     12  * Module exports.
     13  * @public
     14  */
     15 
     16 module.exports = preferredCharsets;
     17 module.exports.preferredCharsets = preferredCharsets;
     18 
     19 /**
     20  * Module variables.
     21  * @private
     22  */
     23 
     24 var simpleCharsetRegExp = /^\s*([^\s;]+)\s*(?:;(.*))?$/;
     25 
     26 /**
     27  * Parse the Accept-Charset header.
     28  * @private
     29  */
     30 
     31 function parseAcceptCharset(accept) {
     32   var accepts = accept.split(',');
     33 
     34   for (var i = 0, j = 0; i < accepts.length; i++) {
     35     var charset = parseCharset(accepts[i].trim(), i);
     36 
     37     if (charset) {
     38       accepts[j++] = charset;
     39     }
     40   }
     41 
     42   // trim accepts
     43   accepts.length = j;
     44 
     45   return accepts;
     46 }
     47 
     48 /**
     49  * Parse a charset from the Accept-Charset header.
     50  * @private
     51  */
     52 
     53 function parseCharset(str, i) {
     54   var match = simpleCharsetRegExp.exec(str);
     55   if (!match) return null;
     56 
     57   var charset = match[1];
     58   var q = 1;
     59   if (match[2]) {
     60     var params = match[2].split(';')
     61     for (var j = 0; j < params.length; j++) {
     62       var p = params[j].trim().split('=');
     63       if (p[0] === 'q') {
     64         q = parseFloat(p[1]);
     65         break;
     66       }
     67     }
     68   }
     69 
     70   return {
     71     charset: charset,
     72     q: q,
     73     i: i
     74   };
     75 }
     76 
     77 /**
     78  * Get the priority of a charset.
     79  * @private
     80  */
     81 
     82 function getCharsetPriority(charset, accepted, index) {
     83   var priority = {o: -1, q: 0, s: 0};
     84 
     85   for (var i = 0; i < accepted.length; i++) {
     86     var spec = specify(charset, accepted[i], index);
     87 
     88     if (spec && (priority.s - spec.s || priority.q - spec.q || priority.o - spec.o) < 0) {
     89       priority = spec;
     90     }
     91   }
     92 
     93   return priority;
     94 }
     95 
     96 /**
     97  * Get the specificity of the charset.
     98  * @private
     99  */
    100 
    101 function specify(charset, spec, index) {
    102   var s = 0;
    103   if(spec.charset.toLowerCase() === charset.toLowerCase()){
    104     s |= 1;
    105   } else if (spec.charset !== '*' ) {
    106     return null
    107   }
    108 
    109   return {
    110     i: index,
    111     o: spec.i,
    112     q: spec.q,
    113     s: s
    114   }
    115 }
    116 
    117 /**
    118  * Get the preferred charsets from an Accept-Charset header.
    119  * @public
    120  */
    121 
    122 function preferredCharsets(accept, provided) {
    123   // RFC 2616 sec 14.2: no header = *
    124   var accepts = parseAcceptCharset(accept === undefined ? '*' : accept || '');
    125 
    126   if (!provided) {
    127     // sorted list of all charsets
    128     return accepts
    129       .filter(isQuality)
    130       .sort(compareSpecs)
    131       .map(getFullCharset);
    132   }
    133 
    134   var priorities = provided.map(function getPriority(type, index) {
    135     return getCharsetPriority(type, accepts, index);
    136   });
    137 
    138   // sorted list of accepted charsets
    139   return priorities.filter(isQuality).sort(compareSpecs).map(function getCharset(priority) {
    140     return provided[priorities.indexOf(priority)];
    141   });
    142 }
    143 
    144 /**
    145  * Compare two specs.
    146  * @private
    147  */
    148 
    149 function compareSpecs(a, b) {
    150   return (b.q - a.q) || (b.s - a.s) || (a.o - b.o) || (a.i - b.i) || 0;
    151 }
    152 
    153 /**
    154  * Get full charset string.
    155  * @private
    156  */
    157 
    158 function getFullCharset(spec) {
    159   return spec.charset;
    160 }
    161 
    162 /**
    163  * Check if a spec has any quality.
    164  * @private
    165  */
    166 
    167 function isQuality(spec) {
    168   return spec.q > 0;
    169 }