[249] | 1 | (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
|
---|
| 2 | /* MIT license */
|
---|
| 3 | var convert = require("color-convert"),
|
---|
| 4 | string = require("color-string");
|
---|
| 5 |
|
---|
| 6 | var Color = function(obj) {
|
---|
| 7 | if (obj instanceof Color) return obj;
|
---|
| 8 | if (! (this instanceof Color)) return new Color(obj);
|
---|
| 9 |
|
---|
| 10 | this.values = {
|
---|
| 11 | rgb: [0, 0, 0],
|
---|
| 12 | hsl: [0, 0, 0],
|
---|
| 13 | hsv: [0, 0, 0],
|
---|
| 14 | hwb: [0, 0, 0],
|
---|
| 15 | cmyk: [0, 0, 0, 0],
|
---|
| 16 | alpha: 1
|
---|
| 17 | }
|
---|
| 18 |
|
---|
| 19 | // parse Color() argument
|
---|
| 20 | if (typeof obj == "string") {
|
---|
| 21 | var vals = string.getRgba(obj);
|
---|
| 22 | if (vals) {
|
---|
| 23 | this.setValues("rgb", vals);
|
---|
| 24 | }
|
---|
| 25 | else if(vals = string.getHsla(obj)) {
|
---|
| 26 | this.setValues("hsl", vals);
|
---|
| 27 | }
|
---|
| 28 | else if(vals = string.getHwb(obj)) {
|
---|
| 29 | this.setValues("hwb", vals);
|
---|
| 30 | }
|
---|
| 31 | else {
|
---|
| 32 | throw new Error("Unable to parse color from string \"" + obj + "\"");
|
---|
| 33 | }
|
---|
| 34 | }
|
---|
| 35 | else if (typeof obj == "object") {
|
---|
| 36 | var vals = obj;
|
---|
| 37 | if(vals["r"] !== undefined || vals["red"] !== undefined) {
|
---|
| 38 | this.setValues("rgb", vals)
|
---|
| 39 | }
|
---|
| 40 | else if(vals["l"] !== undefined || vals["lightness"] !== undefined) {
|
---|
| 41 | this.setValues("hsl", vals)
|
---|
| 42 | }
|
---|
| 43 | else if(vals["v"] !== undefined || vals["value"] !== undefined) {
|
---|
| 44 | this.setValues("hsv", vals)
|
---|
| 45 | }
|
---|
| 46 | else if(vals["w"] !== undefined || vals["whiteness"] !== undefined) {
|
---|
| 47 | this.setValues("hwb", vals)
|
---|
| 48 | }
|
---|
| 49 | else if(vals["c"] !== undefined || vals["cyan"] !== undefined) {
|
---|
| 50 | this.setValues("cmyk", vals)
|
---|
| 51 | }
|
---|
| 52 | else {
|
---|
| 53 | throw new Error("Unable to parse color from object " + JSON.stringify(obj));
|
---|
| 54 | }
|
---|
| 55 | }
|
---|
| 56 | }
|
---|
| 57 |
|
---|
| 58 | Color.prototype = {
|
---|
| 59 | rgb: function (vals) {
|
---|
| 60 | return this.setSpace("rgb", arguments);
|
---|
| 61 | },
|
---|
| 62 | hsl: function(vals) {
|
---|
| 63 | return this.setSpace("hsl", arguments);
|
---|
| 64 | },
|
---|
| 65 | hsv: function(vals) {
|
---|
| 66 | return this.setSpace("hsv", arguments);
|
---|
| 67 | },
|
---|
| 68 | hwb: function(vals) {
|
---|
| 69 | return this.setSpace("hwb", arguments);
|
---|
| 70 | },
|
---|
| 71 | cmyk: function(vals) {
|
---|
| 72 | return this.setSpace("cmyk", arguments);
|
---|
| 73 | },
|
---|
| 74 |
|
---|
| 75 | rgbArray: function() {
|
---|
| 76 | return this.values.rgb;
|
---|
| 77 | },
|
---|
| 78 | hslArray: function() {
|
---|
| 79 | return this.values.hsl;
|
---|
| 80 | },
|
---|
| 81 | hsvArray: function() {
|
---|
| 82 | return this.values.hsv;
|
---|
| 83 | },
|
---|
| 84 | hwbArray: function() {
|
---|
| 85 | if (this.values.alpha !== 1) {
|
---|
| 86 | return this.values.hwb.concat([this.values.alpha])
|
---|
| 87 | }
|
---|
| 88 | return this.values.hwb;
|
---|
| 89 | },
|
---|
| 90 | cmykArray: function() {
|
---|
| 91 | return this.values.cmyk;
|
---|
| 92 | },
|
---|
| 93 | rgbaArray: function() {
|
---|
| 94 | var rgb = this.values.rgb;
|
---|
| 95 | return rgb.concat([this.values.alpha]);
|
---|
| 96 | },
|
---|
| 97 | hslaArray: function() {
|
---|
| 98 | var hsl = this.values.hsl;
|
---|
| 99 | return hsl.concat([this.values.alpha]);
|
---|
| 100 | },
|
---|
| 101 | alpha: function(val) {
|
---|
| 102 | if (val === undefined) {
|
---|
| 103 | return this.values.alpha;
|
---|
| 104 | }
|
---|
| 105 | this.setValues("alpha", val);
|
---|
| 106 | return this;
|
---|
| 107 | },
|
---|
| 108 |
|
---|
| 109 | red: function(val) {
|
---|
| 110 | return this.setChannel("rgb", 0, val);
|
---|
| 111 | },
|
---|
| 112 | green: function(val) {
|
---|
| 113 | return this.setChannel("rgb", 1, val);
|
---|
| 114 | },
|
---|
| 115 | blue: function(val) {
|
---|
| 116 | return this.setChannel("rgb", 2, val);
|
---|
| 117 | },
|
---|
| 118 | hue: function(val) {
|
---|
| 119 | return this.setChannel("hsl", 0, val);
|
---|
| 120 | },
|
---|
| 121 | saturation: function(val) {
|
---|
| 122 | return this.setChannel("hsl", 1, val);
|
---|
| 123 | },
|
---|
| 124 | lightness: function(val) {
|
---|
| 125 | return this.setChannel("hsl", 2, val);
|
---|
| 126 | },
|
---|
| 127 | saturationv: function(val) {
|
---|
| 128 | return this.setChannel("hsv", 1, val);
|
---|
| 129 | },
|
---|
| 130 | whiteness: function(val) {
|
---|
| 131 | return this.setChannel("hwb", 1, val);
|
---|
| 132 | },
|
---|
| 133 | blackness: function(val) {
|
---|
| 134 | return this.setChannel("hwb", 2, val);
|
---|
| 135 | },
|
---|
| 136 | value: function(val) {
|
---|
| 137 | return this.setChannel("hsv", 2, val);
|
---|
| 138 | },
|
---|
| 139 | cyan: function(val) {
|
---|
| 140 | return this.setChannel("cmyk", 0, val);
|
---|
| 141 | },
|
---|
| 142 | magenta: function(val) {
|
---|
| 143 | return this.setChannel("cmyk", 1, val);
|
---|
| 144 | },
|
---|
| 145 | yellow: function(val) {
|
---|
| 146 | return this.setChannel("cmyk", 2, val);
|
---|
| 147 | },
|
---|
| 148 | black: function(val) {
|
---|
| 149 | return this.setChannel("cmyk", 3, val);
|
---|
| 150 | },
|
---|
| 151 |
|
---|
| 152 | hexString: function() {
|
---|
| 153 | return string.hexString(this.values.rgb);
|
---|
| 154 | },
|
---|
| 155 | rgbString: function() {
|
---|
| 156 | return string.rgbString(this.values.rgb, this.values.alpha);
|
---|
| 157 | },
|
---|
| 158 | rgbaString: function() {
|
---|
| 159 | return string.rgbaString(this.values.rgb, this.values.alpha);
|
---|
| 160 | },
|
---|
| 161 | percentString: function() {
|
---|
| 162 | return string.percentString(this.values.rgb, this.values.alpha);
|
---|
| 163 | },
|
---|
| 164 | hslString: function() {
|
---|
| 165 | return string.hslString(this.values.hsl, this.values.alpha);
|
---|
| 166 | },
|
---|
| 167 | hslaString: function() {
|
---|
| 168 | return string.hslaString(this.values.hsl, this.values.alpha);
|
---|
| 169 | },
|
---|
| 170 | hwbString: function() {
|
---|
| 171 | return string.hwbString(this.values.hwb, this.values.alpha);
|
---|
| 172 | },
|
---|
| 173 | keyword: function() {
|
---|
| 174 | return string.keyword(this.values.rgb, this.values.alpha);
|
---|
| 175 | },
|
---|
| 176 |
|
---|
| 177 | rgbNumber: function() {
|
---|
| 178 | return (this.values.rgb[0] << 16) | (this.values.rgb[1] << 8) | this.values.rgb[2];
|
---|
| 179 | },
|
---|
| 180 |
|
---|
| 181 | luminosity: function() {
|
---|
| 182 | // http://www.w3.org/TR/WCAG20/#relativeluminancedef
|
---|
| 183 | var rgb = this.values.rgb;
|
---|
| 184 | var lum = [];
|
---|
| 185 | for (var i = 0; i < rgb.length; i++) {
|
---|
| 186 | var chan = rgb[i] / 255;
|
---|
| 187 | lum[i] = (chan <= 0.03928) ? chan / 12.92
|
---|
| 188 | : Math.pow(((chan + 0.055) / 1.055), 2.4)
|
---|
| 189 | }
|
---|
| 190 | return 0.2126 * lum[0] + 0.7152 * lum[1] + 0.0722 * lum[2];
|
---|
| 191 | },
|
---|
| 192 |
|
---|
| 193 | contrast: function(color2) {
|
---|
| 194 | // http://www.w3.org/TR/WCAG20/#contrast-ratiodef
|
---|
| 195 | var lum1 = this.luminosity();
|
---|
| 196 | var lum2 = color2.luminosity();
|
---|
| 197 | if (lum1 > lum2) {
|
---|
| 198 | return (lum1 + 0.05) / (lum2 + 0.05)
|
---|
| 199 | };
|
---|
| 200 | return (lum2 + 0.05) / (lum1 + 0.05);
|
---|
| 201 | },
|
---|
| 202 |
|
---|
| 203 | level: function(color2) {
|
---|
| 204 | var contrastRatio = this.contrast(color2);
|
---|
| 205 | return (contrastRatio >= 7.1)
|
---|
| 206 | ? 'AAA'
|
---|
| 207 | : (contrastRatio >= 4.5)
|
---|
| 208 | ? 'AA'
|
---|
| 209 | : '';
|
---|
| 210 | },
|
---|
| 211 |
|
---|
| 212 | dark: function() {
|
---|
| 213 | // YIQ equation from http://24ways.org/2010/calculating-color-contrast
|
---|
| 214 | var rgb = this.values.rgb,
|
---|
| 215 | yiq = (rgb[0] * 299 + rgb[1] * 587 + rgb[2] * 114) / 1000;
|
---|
| 216 | return yiq < 128;
|
---|
| 217 | },
|
---|
| 218 |
|
---|
| 219 | light: function() {
|
---|
| 220 | return !this.dark();
|
---|
| 221 | },
|
---|
| 222 |
|
---|
| 223 | negate: function() {
|
---|
| 224 | var rgb = []
|
---|
| 225 | for (var i = 0; i < 3; i++) {
|
---|
| 226 | rgb[i] = 255 - this.values.rgb[i];
|
---|
| 227 | }
|
---|
| 228 | this.setValues("rgb", rgb);
|
---|
| 229 | return this;
|
---|
| 230 | },
|
---|
| 231 |
|
---|
| 232 | lighten: function(ratio) {
|
---|
| 233 | this.values.hsl[2] += this.values.hsl[2] * ratio;
|
---|
| 234 | this.setValues("hsl", this.values.hsl);
|
---|
| 235 | return this;
|
---|
| 236 | },
|
---|
| 237 |
|
---|
| 238 | darken: function(ratio) {
|
---|
| 239 | this.values.hsl[2] -= this.values.hsl[2] * ratio;
|
---|
| 240 | this.setValues("hsl", this.values.hsl);
|
---|
| 241 | return this;
|
---|
| 242 | },
|
---|
| 243 |
|
---|
| 244 | saturate: function(ratio) {
|
---|
| 245 | this.values.hsl[1] += this.values.hsl[1] * ratio;
|
---|
| 246 | this.setValues("hsl", this.values.hsl);
|
---|
| 247 | return this;
|
---|
| 248 | },
|
---|
| 249 |
|
---|
| 250 | desaturate: function(ratio) {
|
---|
| 251 | this.values.hsl[1] -= this.values.hsl[1] * ratio;
|
---|
| 252 | this.setValues("hsl", this.values.hsl);
|
---|
| 253 | return this;
|
---|
| 254 | },
|
---|
| 255 |
|
---|
| 256 | whiten: function(ratio) {
|
---|
| 257 | this.values.hwb[1] += this.values.hwb[1] * ratio;
|
---|
| 258 | this.setValues("hwb", this.values.hwb);
|
---|
| 259 | return this;
|
---|
| 260 | },
|
---|
| 261 |
|
---|
| 262 | blacken: function(ratio) {
|
---|
| 263 | this.values.hwb[2] += this.values.hwb[2] * ratio;
|
---|
| 264 | this.setValues("hwb", this.values.hwb);
|
---|
| 265 | return this;
|
---|
| 266 | },
|
---|
| 267 |
|
---|
| 268 | greyscale: function() {
|
---|
| 269 | var rgb = this.values.rgb;
|
---|
| 270 | // http://en.wikipedia.org/wiki/Grayscale#Converting_color_to_grayscale
|
---|
| 271 | var val = rgb[0] * 0.3 + rgb[1] * 0.59 + rgb[2] * 0.11;
|
---|
| 272 | this.setValues("rgb", [val, val, val]);
|
---|
| 273 | return this;
|
---|
| 274 | },
|
---|
| 275 |
|
---|
| 276 | clearer: function(ratio) {
|
---|
| 277 | this.setValues("alpha", this.values.alpha - (this.values.alpha * ratio));
|
---|
| 278 | return this;
|
---|
| 279 | },
|
---|
| 280 |
|
---|
| 281 | opaquer: function(ratio) {
|
---|
| 282 | this.setValues("alpha", this.values.alpha + (this.values.alpha * ratio));
|
---|
| 283 | return this;
|
---|
| 284 | },
|
---|
| 285 |
|
---|
| 286 | rotate: function(degrees) {
|
---|
| 287 | var hue = this.values.hsl[0];
|
---|
| 288 | hue = (hue + degrees) % 360;
|
---|
| 289 | hue = hue < 0 ? 360 + hue : hue;
|
---|
| 290 | this.values.hsl[0] = hue;
|
---|
| 291 | this.setValues("hsl", this.values.hsl);
|
---|
| 292 | return this;
|
---|
| 293 | },
|
---|
| 294 |
|
---|
| 295 | mix: function(color2, weight) {
|
---|
| 296 | weight = 1 - (weight == null ? 0.5 : weight);
|
---|
| 297 |
|
---|
| 298 | // algorithm from Sass's mix(). Ratio of first color in mix is
|
---|
| 299 | // determined by the alphas of both colors and the weight
|
---|
| 300 | var t1 = weight * 2 - 1,
|
---|
| 301 | d = this.alpha() - color2.alpha();
|
---|
| 302 |
|
---|
| 303 | var weight1 = (((t1 * d == -1) ? t1 : (t1 + d) / (1 + t1 * d)) + 1) / 2;
|
---|
| 304 | var weight2 = 1 - weight1;
|
---|
| 305 |
|
---|
| 306 | var rgb = this.rgbArray();
|
---|
| 307 | var rgb2 = color2.rgbArray();
|
---|
| 308 |
|
---|
| 309 | for (var i = 0; i < rgb.length; i++) {
|
---|
| 310 | rgb[i] = rgb[i] * weight1 + rgb2[i] * weight2;
|
---|
| 311 | }
|
---|
| 312 | this.setValues("rgb", rgb);
|
---|
| 313 |
|
---|
| 314 | var alpha = this.alpha() * weight + color2.alpha() * (1 - weight);
|
---|
| 315 | this.setValues("alpha", alpha);
|
---|
| 316 |
|
---|
| 317 | return this;
|
---|
| 318 | },
|
---|
| 319 |
|
---|
| 320 | toJSON: function() {
|
---|
| 321 | return this.rgb();
|
---|
| 322 | },
|
---|
| 323 |
|
---|
| 324 | clone: function() {
|
---|
| 325 | return new Color(this.rgb());
|
---|
| 326 | }
|
---|
| 327 | }
|
---|
| 328 |
|
---|
| 329 |
|
---|
| 330 | Color.prototype.getValues = function(space) {
|
---|
| 331 | var vals = {};
|
---|
| 332 | for (var i = 0; i < space.length; i++) {
|
---|
| 333 | vals[space.charAt(i)] = this.values[space][i];
|
---|
| 334 | }
|
---|
| 335 | if (this.values.alpha != 1) {
|
---|
| 336 | vals["a"] = this.values.alpha;
|
---|
| 337 | }
|
---|
| 338 | // {r: 255, g: 255, b: 255, a: 0.4}
|
---|
| 339 | return vals;
|
---|
| 340 | }
|
---|
| 341 |
|
---|
| 342 | Color.prototype.setValues = function(space, vals) {
|
---|
| 343 | var spaces = {
|
---|
| 344 | "rgb": ["red", "green", "blue"],
|
---|
| 345 | "hsl": ["hue", "saturation", "lightness"],
|
---|
| 346 | "hsv": ["hue", "saturation", "value"],
|
---|
| 347 | "hwb": ["hue", "whiteness", "blackness"],
|
---|
| 348 | "cmyk": ["cyan", "magenta", "yellow", "black"]
|
---|
| 349 | };
|
---|
| 350 |
|
---|
| 351 | var maxes = {
|
---|
| 352 | "rgb": [255, 255, 255],
|
---|
| 353 | "hsl": [360, 100, 100],
|
---|
| 354 | "hsv": [360, 100, 100],
|
---|
| 355 | "hwb": [360, 100, 100],
|
---|
| 356 | "cmyk": [100, 100, 100, 100]
|
---|
| 357 | };
|
---|
| 358 |
|
---|
| 359 | var alpha = 1;
|
---|
| 360 | if (space == "alpha") {
|
---|
| 361 | alpha = vals;
|
---|
| 362 | }
|
---|
| 363 | else if (vals.length) {
|
---|
| 364 | // [10, 10, 10]
|
---|
| 365 | this.values[space] = vals.slice(0, space.length);
|
---|
| 366 | alpha = vals[space.length];
|
---|
| 367 | }
|
---|
| 368 | else if (vals[space.charAt(0)] !== undefined) {
|
---|
| 369 | // {r: 10, g: 10, b: 10}
|
---|
| 370 | for (var i = 0; i < space.length; i++) {
|
---|
| 371 | this.values[space][i] = vals[space.charAt(i)];
|
---|
| 372 | }
|
---|
| 373 | alpha = vals.a;
|
---|
| 374 | }
|
---|
| 375 | else if (vals[spaces[space][0]] !== undefined) {
|
---|
| 376 | // {red: 10, green: 10, blue: 10}
|
---|
| 377 | var chans = spaces[space];
|
---|
| 378 | for (var i = 0; i < space.length; i++) {
|
---|
| 379 | this.values[space][i] = vals[chans[i]];
|
---|
| 380 | }
|
---|
| 381 | alpha = vals.alpha;
|
---|
| 382 | }
|
---|
| 383 | this.values.alpha = Math.max(0, Math.min(1, (alpha !== undefined ? alpha : this.values.alpha) ));
|
---|
| 384 | if (space == "alpha") {
|
---|
| 385 | return;
|
---|
| 386 | }
|
---|
| 387 |
|
---|
| 388 | // cap values of the space prior converting all values
|
---|
| 389 | for (var i = 0; i < space.length; i++) {
|
---|
| 390 | var capped = Math.max(0, Math.min(maxes[space][i], this.values[space][i]));
|
---|
| 391 | this.values[space][i] = Math.round(capped);
|
---|
| 392 | }
|
---|
| 393 |
|
---|
| 394 | // convert to all the other color spaces
|
---|
| 395 | for (var sname in spaces) {
|
---|
| 396 | if (sname != space) {
|
---|
| 397 | this.values[sname] = convert[space][sname](this.values[space])
|
---|
| 398 | }
|
---|
| 399 |
|
---|
| 400 | // cap values
|
---|
| 401 | for (var i = 0; i < sname.length; i++) {
|
---|
| 402 | var capped = Math.max(0, Math.min(maxes[sname][i], this.values[sname][i]));
|
---|
| 403 | this.values[sname][i] = Math.round(capped);
|
---|
| 404 | }
|
---|
| 405 | }
|
---|
| 406 | return true;
|
---|
| 407 | }
|
---|
| 408 |
|
---|
| 409 | Color.prototype.setSpace = function(space, args) {
|
---|
| 410 | var vals = args[0];
|
---|
| 411 | if (vals === undefined) {
|
---|
| 412 | // color.rgb()
|
---|
| 413 | return this.getValues(space);
|
---|
| 414 | }
|
---|
| 415 | // color.rgb(10, 10, 10)
|
---|
| 416 | if (typeof vals == "number") {
|
---|
| 417 | vals = Array.prototype.slice.call(args);
|
---|
| 418 | }
|
---|
| 419 | this.setValues(space, vals);
|
---|
| 420 | return this;
|
---|
| 421 | }
|
---|
| 422 |
|
---|
| 423 | Color.prototype.setChannel = function(space, index, val) {
|
---|
| 424 | if (val === undefined) {
|
---|
| 425 | // color.red()
|
---|
| 426 | return this.values[space][index];
|
---|
| 427 | }
|
---|
| 428 | // color.red(100)
|
---|
| 429 | this.values[space][index] = val;
|
---|
| 430 | this.setValues(space, this.values[space]);
|
---|
| 431 | return this;
|
---|
| 432 | }
|
---|
| 433 |
|
---|
| 434 | module.exports = Color;
|
---|
| 435 |
|
---|
| 436 | },{"color-convert":3,"color-string":4}],2:[function(require,module,exports){
|
---|
| 437 | /* MIT license */
|
---|
| 438 |
|
---|
| 439 | module.exports = {
|
---|
| 440 | rgb2hsl: rgb2hsl,
|
---|
| 441 | rgb2hsv: rgb2hsv,
|
---|
| 442 | rgb2hwb: rgb2hwb,
|
---|
| 443 | rgb2cmyk: rgb2cmyk,
|
---|
| 444 | rgb2keyword: rgb2keyword,
|
---|
| 445 | rgb2xyz: rgb2xyz,
|
---|
| 446 | rgb2lab: rgb2lab,
|
---|
| 447 | rgb2lch: rgb2lch,
|
---|
| 448 |
|
---|
| 449 | hsl2rgb: hsl2rgb,
|
---|
| 450 | hsl2hsv: hsl2hsv,
|
---|
| 451 | hsl2hwb: hsl2hwb,
|
---|
| 452 | hsl2cmyk: hsl2cmyk,
|
---|
| 453 | hsl2keyword: hsl2keyword,
|
---|
| 454 |
|
---|
| 455 | hsv2rgb: hsv2rgb,
|
---|
| 456 | hsv2hsl: hsv2hsl,
|
---|
| 457 | hsv2hwb: hsv2hwb,
|
---|
| 458 | hsv2cmyk: hsv2cmyk,
|
---|
| 459 | hsv2keyword: hsv2keyword,
|
---|
| 460 |
|
---|
| 461 | hwb2rgb: hwb2rgb,
|
---|
| 462 | hwb2hsl: hwb2hsl,
|
---|
| 463 | hwb2hsv: hwb2hsv,
|
---|
| 464 | hwb2cmyk: hwb2cmyk,
|
---|
| 465 | hwb2keyword: hwb2keyword,
|
---|
| 466 |
|
---|
| 467 | cmyk2rgb: cmyk2rgb,
|
---|
| 468 | cmyk2hsl: cmyk2hsl,
|
---|
| 469 | cmyk2hsv: cmyk2hsv,
|
---|
| 470 | cmyk2hwb: cmyk2hwb,
|
---|
| 471 | cmyk2keyword: cmyk2keyword,
|
---|
| 472 |
|
---|
| 473 | keyword2rgb: keyword2rgb,
|
---|
| 474 | keyword2hsl: keyword2hsl,
|
---|
| 475 | keyword2hsv: keyword2hsv,
|
---|
| 476 | keyword2hwb: keyword2hwb,
|
---|
| 477 | keyword2cmyk: keyword2cmyk,
|
---|
| 478 | keyword2lab: keyword2lab,
|
---|
| 479 | keyword2xyz: keyword2xyz,
|
---|
| 480 |
|
---|
| 481 | xyz2rgb: xyz2rgb,
|
---|
| 482 | xyz2lab: xyz2lab,
|
---|
| 483 | xyz2lch: xyz2lch,
|
---|
| 484 |
|
---|
| 485 | lab2xyz: lab2xyz,
|
---|
| 486 | lab2rgb: lab2rgb,
|
---|
| 487 | lab2lch: lab2lch,
|
---|
| 488 |
|
---|
| 489 | lch2lab: lch2lab,
|
---|
| 490 | lch2xyz: lch2xyz,
|
---|
| 491 | lch2rgb: lch2rgb
|
---|
| 492 | }
|
---|
| 493 |
|
---|
| 494 |
|
---|
| 495 | function rgb2hsl(rgb) {
|
---|
| 496 | var r = rgb[0]/255,
|
---|
| 497 | g = rgb[1]/255,
|
---|
| 498 | b = rgb[2]/255,
|
---|
| 499 | min = Math.min(r, g, b),
|
---|
| 500 | max = Math.max(r, g, b),
|
---|
| 501 | delta = max - min,
|
---|
| 502 | h, s, l;
|
---|
| 503 |
|
---|
| 504 | if (max == min)
|
---|
| 505 | h = 0;
|
---|
| 506 | else if (r == max)
|
---|
| 507 | h = (g - b) / delta;
|
---|
| 508 | else if (g == max)
|
---|
| 509 | h = 2 + (b - r) / delta;
|
---|
| 510 | else if (b == max)
|
---|
| 511 | h = 4 + (r - g)/ delta;
|
---|
| 512 |
|
---|
| 513 | h = Math.min(h * 60, 360);
|
---|
| 514 |
|
---|
| 515 | if (h < 0)
|
---|
| 516 | h += 360;
|
---|
| 517 |
|
---|
| 518 | l = (min + max) / 2;
|
---|
| 519 |
|
---|
| 520 | if (max == min)
|
---|
| 521 | s = 0;
|
---|
| 522 | else if (l <= 0.5)
|
---|
| 523 | s = delta / (max + min);
|
---|
| 524 | else
|
---|
| 525 | s = delta / (2 - max - min);
|
---|
| 526 |
|
---|
| 527 | return [h, s * 100, l * 100];
|
---|
| 528 | }
|
---|
| 529 |
|
---|
| 530 | function rgb2hsv(rgb) {
|
---|
| 531 | var r = rgb[0],
|
---|
| 532 | g = rgb[1],
|
---|
| 533 | b = rgb[2],
|
---|
| 534 | min = Math.min(r, g, b),
|
---|
| 535 | max = Math.max(r, g, b),
|
---|
| 536 | delta = max - min,
|
---|
| 537 | h, s, v;
|
---|
| 538 |
|
---|
| 539 | if (max == 0)
|
---|
| 540 | s = 0;
|
---|
| 541 | else
|
---|
| 542 | s = (delta/max * 1000)/10;
|
---|
| 543 |
|
---|
| 544 | if (max == min)
|
---|
| 545 | h = 0;
|
---|
| 546 | else if (r == max)
|
---|
| 547 | h = (g - b) / delta;
|
---|
| 548 | else if (g == max)
|
---|
| 549 | h = 2 + (b - r) / delta;
|
---|
| 550 | else if (b == max)
|
---|
| 551 | h = 4 + (r - g) / delta;
|
---|
| 552 |
|
---|
| 553 | h = Math.min(h * 60, 360);
|
---|
| 554 |
|
---|
| 555 | if (h < 0)
|
---|
| 556 | h += 360;
|
---|
| 557 |
|
---|
| 558 | v = ((max / 255) * 1000) / 10;
|
---|
| 559 |
|
---|
| 560 | return [h, s, v];
|
---|
| 561 | }
|
---|
| 562 |
|
---|
| 563 | function rgb2hwb(rgb) {
|
---|
| 564 | var r = rgb[0],
|
---|
| 565 | g = rgb[1],
|
---|
| 566 | b = rgb[2],
|
---|
| 567 | h = rgb2hsl(rgb)[0],
|
---|
| 568 | w = 1/255 * Math.min(r, Math.min(g, b)),
|
---|
| 569 | b = 1 - 1/255 * Math.max(r, Math.max(g, b));
|
---|
| 570 |
|
---|
| 571 | return [h, w * 100, b * 100];
|
---|
| 572 | }
|
---|
| 573 |
|
---|
| 574 | function rgb2cmyk(rgb) {
|
---|
| 575 | var r = rgb[0] / 255,
|
---|
| 576 | g = rgb[1] / 255,
|
---|
| 577 | b = rgb[2] / 255,
|
---|
| 578 | c, m, y, k;
|
---|
| 579 |
|
---|
| 580 | k = Math.min(1 - r, 1 - g, 1 - b);
|
---|
| 581 | c = (1 - r - k) / (1 - k) || 0;
|
---|
| 582 | m = (1 - g - k) / (1 - k) || 0;
|
---|
| 583 | y = (1 - b - k) / (1 - k) || 0;
|
---|
| 584 | return [c * 100, m * 100, y * 100, k * 100];
|
---|
| 585 | }
|
---|
| 586 |
|
---|
| 587 | function rgb2keyword(rgb) {
|
---|
| 588 | return reverseKeywords[JSON.stringify(rgb)];
|
---|
| 589 | }
|
---|
| 590 |
|
---|
| 591 | function rgb2xyz(rgb) {
|
---|
| 592 | var r = rgb[0] / 255,
|
---|
| 593 | g = rgb[1] / 255,
|
---|
| 594 | b = rgb[2] / 255;
|
---|
| 595 |
|
---|
| 596 | // assume sRGB
|
---|
| 597 | r = r > 0.04045 ? Math.pow(((r + 0.055) / 1.055), 2.4) : (r / 12.92);
|
---|
| 598 | g = g > 0.04045 ? Math.pow(((g + 0.055) / 1.055), 2.4) : (g / 12.92);
|
---|
| 599 | b = b > 0.04045 ? Math.pow(((b + 0.055) / 1.055), 2.4) : (b / 12.92);
|
---|
| 600 |
|
---|
| 601 | var x = (r * 0.4124) + (g * 0.3576) + (b * 0.1805);
|
---|
| 602 | var y = (r * 0.2126) + (g * 0.7152) + (b * 0.0722);
|
---|
| 603 | var z = (r * 0.0193) + (g * 0.1192) + (b * 0.9505);
|
---|
| 604 |
|
---|
| 605 | return [x * 100, y *100, z * 100];
|
---|
| 606 | }
|
---|
| 607 |
|
---|
| 608 | function rgb2lab(rgb) {
|
---|
| 609 | var xyz = rgb2xyz(rgb),
|
---|
| 610 | x = xyz[0],
|
---|
| 611 | y = xyz[1],
|
---|
| 612 | z = xyz[2],
|
---|
| 613 | l, a, b;
|
---|
| 614 |
|
---|
| 615 | x /= 95.047;
|
---|
| 616 | y /= 100;
|
---|
| 617 | z /= 108.883;
|
---|
| 618 |
|
---|
| 619 | x = x > 0.008856 ? Math.pow(x, 1/3) : (7.787 * x) + (16 / 116);
|
---|
| 620 | y = y > 0.008856 ? Math.pow(y, 1/3) : (7.787 * y) + (16 / 116);
|
---|
| 621 | z = z > 0.008856 ? Math.pow(z, 1/3) : (7.787 * z) + (16 / 116);
|
---|
| 622 |
|
---|
| 623 | l = (116 * y) - 16;
|
---|
| 624 | a = 500 * (x - y);
|
---|
| 625 | b = 200 * (y - z);
|
---|
| 626 |
|
---|
| 627 | return [l, a, b];
|
---|
| 628 | }
|
---|
| 629 |
|
---|
| 630 | function rgb2lch(args) {
|
---|
| 631 | return lab2lch(rgb2lab(args));
|
---|
| 632 | }
|
---|
| 633 |
|
---|
| 634 | function hsl2rgb(hsl) {
|
---|
| 635 | var h = hsl[0] / 360,
|
---|
| 636 | s = hsl[1] / 100,
|
---|
| 637 | l = hsl[2] / 100,
|
---|
| 638 | t1, t2, t3, rgb, val;
|
---|
| 639 |
|
---|
| 640 | if (s == 0) {
|
---|
| 641 | val = l * 255;
|
---|
| 642 | return [val, val, val];
|
---|
| 643 | }
|
---|
| 644 |
|
---|
| 645 | if (l < 0.5)
|
---|
| 646 | t2 = l * (1 + s);
|
---|
| 647 | else
|
---|
| 648 | t2 = l + s - l * s;
|
---|
| 649 | t1 = 2 * l - t2;
|
---|
| 650 |
|
---|
| 651 | rgb = [0, 0, 0];
|
---|
| 652 | for (var i = 0; i < 3; i++) {
|
---|
| 653 | t3 = h + 1 / 3 * - (i - 1);
|
---|
| 654 | t3 < 0 && t3++;
|
---|
| 655 | t3 > 1 && t3--;
|
---|
| 656 |
|
---|
| 657 | if (6 * t3 < 1)
|
---|
| 658 | val = t1 + (t2 - t1) * 6 * t3;
|
---|
| 659 | else if (2 * t3 < 1)
|
---|
| 660 | val = t2;
|
---|
| 661 | else if (3 * t3 < 2)
|
---|
| 662 | val = t1 + (t2 - t1) * (2 / 3 - t3) * 6;
|
---|
| 663 | else
|
---|
| 664 | val = t1;
|
---|
| 665 |
|
---|
| 666 | rgb[i] = val * 255;
|
---|
| 667 | }
|
---|
| 668 |
|
---|
| 669 | return rgb;
|
---|
| 670 | }
|
---|
| 671 |
|
---|
| 672 | function hsl2hsv(hsl) {
|
---|
| 673 | var h = hsl[0],
|
---|
| 674 | s = hsl[1] / 100,
|
---|
| 675 | l = hsl[2] / 100,
|
---|
| 676 | sv, v;
|
---|
| 677 | l *= 2;
|
---|
| 678 | s *= (l <= 1) ? l : 2 - l;
|
---|
| 679 | v = (l + s) / 2;
|
---|
| 680 | sv = (2 * s) / (l + s);
|
---|
| 681 | return [h, sv * 100, v * 100];
|
---|
| 682 | }
|
---|
| 683 |
|
---|
| 684 | function hsl2hwb(args) {
|
---|
| 685 | return rgb2hwb(hsl2rgb(args));
|
---|
| 686 | }
|
---|
| 687 |
|
---|
| 688 | function hsl2cmyk(args) {
|
---|
| 689 | return rgb2cmyk(hsl2rgb(args));
|
---|
| 690 | }
|
---|
| 691 |
|
---|
| 692 | function hsl2keyword(args) {
|
---|
| 693 | return rgb2keyword(hsl2rgb(args));
|
---|
| 694 | }
|
---|
| 695 |
|
---|
| 696 |
|
---|
| 697 | function hsv2rgb(hsv) {
|
---|
| 698 | var h = hsv[0] / 60,
|
---|
| 699 | s = hsv[1] / 100,
|
---|
| 700 | v = hsv[2] / 100,
|
---|
| 701 | hi = Math.floor(h) % 6;
|
---|
| 702 |
|
---|
| 703 | var f = h - Math.floor(h),
|
---|
| 704 | p = 255 * v * (1 - s),
|
---|
| 705 | q = 255 * v * (1 - (s * f)),
|
---|
| 706 | t = 255 * v * (1 - (s * (1 - f))),
|
---|
| 707 | v = 255 * v;
|
---|
| 708 |
|
---|
| 709 | switch(hi) {
|
---|
| 710 | case 0:
|
---|
| 711 | return [v, t, p];
|
---|
| 712 | case 1:
|
---|
| 713 | return [q, v, p];
|
---|
| 714 | case 2:
|
---|
| 715 | return [p, v, t];
|
---|
| 716 | case 3:
|
---|
| 717 | return [p, q, v];
|
---|
| 718 | case 4:
|
---|
| 719 | return [t, p, v];
|
---|
| 720 | case 5:
|
---|
| 721 | return [v, p, q];
|
---|
| 722 | }
|
---|
| 723 | }
|
---|
| 724 |
|
---|
| 725 | function hsv2hsl(hsv) {
|
---|
| 726 | var h = hsv[0],
|
---|
| 727 | s = hsv[1] / 100,
|
---|
| 728 | v = hsv[2] / 100,
|
---|
| 729 | sl, l;
|
---|
| 730 |
|
---|
| 731 | l = (2 - s) * v;
|
---|
| 732 | sl = s * v;
|
---|
| 733 | sl /= (l <= 1) ? l : 2 - l;
|
---|
| 734 | sl = sl || 0;
|
---|
| 735 | l /= 2;
|
---|
| 736 | return [h, sl * 100, l * 100];
|
---|
| 737 | }
|
---|
| 738 |
|
---|
| 739 | function hsv2hwb(args) {
|
---|
| 740 | return rgb2hwb(hsv2rgb(args))
|
---|
| 741 | }
|
---|
| 742 |
|
---|
| 743 | function hsv2cmyk(args) {
|
---|
| 744 | return rgb2cmyk(hsv2rgb(args));
|
---|
| 745 | }
|
---|
| 746 |
|
---|
| 747 | function hsv2keyword(args) {
|
---|
| 748 | return rgb2keyword(hsv2rgb(args));
|
---|
| 749 | }
|
---|
| 750 |
|
---|
| 751 | // http://dev.w3.org/csswg/css-color/#hwb-to-rgb
|
---|
| 752 | function hwb2rgb(hwb) {
|
---|
| 753 | var h = hwb[0] / 360,
|
---|
| 754 | wh = hwb[1] / 100,
|
---|
| 755 | bl = hwb[2] / 100,
|
---|
| 756 | ratio = wh + bl,
|
---|
| 757 | i, v, f, n;
|
---|
| 758 |
|
---|
| 759 | // wh + bl cant be > 1
|
---|
| 760 | if (ratio > 1) {
|
---|
| 761 | wh /= ratio;
|
---|
| 762 | bl /= ratio;
|
---|
| 763 | }
|
---|
| 764 |
|
---|
| 765 | i = Math.floor(6 * h);
|
---|
| 766 | v = 1 - bl;
|
---|
| 767 | f = 6 * h - i;
|
---|
| 768 | if ((i & 0x01) != 0) {
|
---|
| 769 | f = 1 - f;
|
---|
| 770 | }
|
---|
| 771 | n = wh + f * (v - wh); // linear interpolation
|
---|
| 772 |
|
---|
| 773 | switch (i) {
|
---|
| 774 | default:
|
---|
| 775 | case 6:
|
---|
| 776 | case 0: r = v; g = n; b = wh; break;
|
---|
| 777 | case 1: r = n; g = v; b = wh; break;
|
---|
| 778 | case 2: r = wh; g = v; b = n; break;
|
---|
| 779 | case 3: r = wh; g = n; b = v; break;
|
---|
| 780 | case 4: r = n; g = wh; b = v; break;
|
---|
| 781 | case 5: r = v; g = wh; b = n; break;
|
---|
| 782 | }
|
---|
| 783 |
|
---|
| 784 | return [r * 255, g * 255, b * 255];
|
---|
| 785 | }
|
---|
| 786 |
|
---|
| 787 | function hwb2hsl(args) {
|
---|
| 788 | return rgb2hsl(hwb2rgb(args));
|
---|
| 789 | }
|
---|
| 790 |
|
---|
| 791 | function hwb2hsv(args) {
|
---|
| 792 | return rgb2hsv(hwb2rgb(args));
|
---|
| 793 | }
|
---|
| 794 |
|
---|
| 795 | function hwb2cmyk(args) {
|
---|
| 796 | return rgb2cmyk(hwb2rgb(args));
|
---|
| 797 | }
|
---|
| 798 |
|
---|
| 799 | function hwb2keyword(args) {
|
---|
| 800 | return rgb2keyword(hwb2rgb(args));
|
---|
| 801 | }
|
---|
| 802 |
|
---|
| 803 | function cmyk2rgb(cmyk) {
|
---|
| 804 | var c = cmyk[0] / 100,
|
---|
| 805 | m = cmyk[1] / 100,
|
---|
| 806 | y = cmyk[2] / 100,
|
---|
| 807 | k = cmyk[3] / 100,
|
---|
| 808 | r, g, b;
|
---|
| 809 |
|
---|
| 810 | r = 1 - Math.min(1, c * (1 - k) + k);
|
---|
| 811 | g = 1 - Math.min(1, m * (1 - k) + k);
|
---|
| 812 | b = 1 - Math.min(1, y * (1 - k) + k);
|
---|
| 813 | return [r * 255, g * 255, b * 255];
|
---|
| 814 | }
|
---|
| 815 |
|
---|
| 816 | function cmyk2hsl(args) {
|
---|
| 817 | return rgb2hsl(cmyk2rgb(args));
|
---|
| 818 | }
|
---|
| 819 |
|
---|
| 820 | function cmyk2hsv(args) {
|
---|
| 821 | return rgb2hsv(cmyk2rgb(args));
|
---|
| 822 | }
|
---|
| 823 |
|
---|
| 824 | function cmyk2hwb(args) {
|
---|
| 825 | return rgb2hwb(cmyk2rgb(args));
|
---|
| 826 | }
|
---|
| 827 |
|
---|
| 828 | function cmyk2keyword(args) {
|
---|
| 829 | return rgb2keyword(cmyk2rgb(args));
|
---|
| 830 | }
|
---|
| 831 |
|
---|
| 832 |
|
---|
| 833 | function xyz2rgb(xyz) {
|
---|
| 834 | var x = xyz[0] / 100,
|
---|
| 835 | y = xyz[1] / 100,
|
---|
| 836 | z = xyz[2] / 100,
|
---|
| 837 | r, g, b;
|
---|
| 838 |
|
---|
| 839 | r = (x * 3.2406) + (y * -1.5372) + (z * -0.4986);
|
---|
| 840 | g = (x * -0.9689) + (y * 1.8758) + (z * 0.0415);
|
---|
| 841 | b = (x * 0.0557) + (y * -0.2040) + (z * 1.0570);
|
---|
| 842 |
|
---|
| 843 | // assume sRGB
|
---|
| 844 | r = r > 0.0031308 ? ((1.055 * Math.pow(r, 1.0 / 2.4)) - 0.055)
|
---|
| 845 | : r = (r * 12.92);
|
---|
| 846 |
|
---|
| 847 | g = g > 0.0031308 ? ((1.055 * Math.pow(g, 1.0 / 2.4)) - 0.055)
|
---|
| 848 | : g = (g * 12.92);
|
---|
| 849 |
|
---|
| 850 | b = b > 0.0031308 ? ((1.055 * Math.pow(b, 1.0 / 2.4)) - 0.055)
|
---|
| 851 | : b = (b * 12.92);
|
---|
| 852 |
|
---|
| 853 | r = Math.min(Math.max(0, r), 1);
|
---|
| 854 | g = Math.min(Math.max(0, g), 1);
|
---|
| 855 | b = Math.min(Math.max(0, b), 1);
|
---|
| 856 |
|
---|
| 857 | return [r * 255, g * 255, b * 255];
|
---|
| 858 | }
|
---|
| 859 |
|
---|
| 860 | function xyz2lab(xyz) {
|
---|
| 861 | var x = xyz[0],
|
---|
| 862 | y = xyz[1],
|
---|
| 863 | z = xyz[2],
|
---|
| 864 | l, a, b;
|
---|
| 865 |
|
---|
| 866 | x /= 95.047;
|
---|
| 867 | y /= 100;
|
---|
| 868 | z /= 108.883;
|
---|
| 869 |
|
---|
| 870 | x = x > 0.008856 ? Math.pow(x, 1/3) : (7.787 * x) + (16 / 116);
|
---|
| 871 | y = y > 0.008856 ? Math.pow(y, 1/3) : (7.787 * y) + (16 / 116);
|
---|
| 872 | z = z > 0.008856 ? Math.pow(z, 1/3) : (7.787 * z) + (16 / 116);
|
---|
| 873 |
|
---|
| 874 | l = (116 * y) - 16;
|
---|
| 875 | a = 500 * (x - y);
|
---|
| 876 | b = 200 * (y - z);
|
---|
| 877 |
|
---|
| 878 | return [l, a, b];
|
---|
| 879 | }
|
---|
| 880 |
|
---|
| 881 | function xyz2lch(args) {
|
---|
| 882 | return lab2lch(xyz2lab(args));
|
---|
| 883 | }
|
---|
| 884 |
|
---|
| 885 | function lab2xyz(lab) {
|
---|
| 886 | var l = lab[0],
|
---|
| 887 | a = lab[1],
|
---|
| 888 | b = lab[2],
|
---|
| 889 | x, y, z, y2;
|
---|
| 890 |
|
---|
| 891 | if (l <= 8) {
|
---|
| 892 | y = (l * 100) / 903.3;
|
---|
| 893 | y2 = (7.787 * (y / 100)) + (16 / 116);
|
---|
| 894 | } else {
|
---|
| 895 | y = 100 * Math.pow((l + 16) / 116, 3);
|
---|
| 896 | y2 = Math.pow(y / 100, 1/3);
|
---|
| 897 | }
|
---|
| 898 |
|
---|
| 899 | x = x / 95.047 <= 0.008856 ? x = (95.047 * ((a / 500) + y2 - (16 / 116))) / 7.787 : 95.047 * Math.pow((a / 500) + y2, 3);
|
---|
| 900 |
|
---|
| 901 | z = z / 108.883 <= 0.008859 ? z = (108.883 * (y2 - (b / 200) - (16 / 116))) / 7.787 : 108.883 * Math.pow(y2 - (b / 200), 3);
|
---|
| 902 |
|
---|
| 903 | return [x, y, z];
|
---|
| 904 | }
|
---|
| 905 |
|
---|
| 906 | function lab2lch(lab) {
|
---|
| 907 | var l = lab[0],
|
---|
| 908 | a = lab[1],
|
---|
| 909 | b = lab[2],
|
---|
| 910 | hr, h, c;
|
---|
| 911 |
|
---|
| 912 | hr = Math.atan2(b, a);
|
---|
| 913 | h = hr * 360 / 2 / Math.PI;
|
---|
| 914 | if (h < 0) {
|
---|
| 915 | h += 360;
|
---|
| 916 | }
|
---|
| 917 | c = Math.sqrt(a * a + b * b);
|
---|
| 918 | return [l, c, h];
|
---|
| 919 | }
|
---|
| 920 |
|
---|
| 921 | function lab2rgb(args) {
|
---|
| 922 | return xyz2rgb(lab2xyz(args));
|
---|
| 923 | }
|
---|
| 924 |
|
---|
| 925 | function lch2lab(lch) {
|
---|
| 926 | var l = lch[0],
|
---|
| 927 | c = lch[1],
|
---|
| 928 | h = lch[2],
|
---|
| 929 | a, b, hr;
|
---|
| 930 |
|
---|
| 931 | hr = h / 360 * 2 * Math.PI;
|
---|
| 932 | a = c * Math.cos(hr);
|
---|
| 933 | b = c * Math.sin(hr);
|
---|
| 934 | return [l, a, b];
|
---|
| 935 | }
|
---|
| 936 |
|
---|
| 937 | function lch2xyz(args) {
|
---|
| 938 | return lab2xyz(lch2lab(args));
|
---|
| 939 | }
|
---|
| 940 |
|
---|
| 941 | function lch2rgb(args) {
|
---|
| 942 | return lab2rgb(lch2lab(args));
|
---|
| 943 | }
|
---|
| 944 |
|
---|
| 945 | function keyword2rgb(keyword) {
|
---|
| 946 | return cssKeywords[keyword];
|
---|
| 947 | }
|
---|
| 948 |
|
---|
| 949 | function keyword2hsl(args) {
|
---|
| 950 | return rgb2hsl(keyword2rgb(args));
|
---|
| 951 | }
|
---|
| 952 |
|
---|
| 953 | function keyword2hsv(args) {
|
---|
| 954 | return rgb2hsv(keyword2rgb(args));
|
---|
| 955 | }
|
---|
| 956 |
|
---|
| 957 | function keyword2hwb(args) {
|
---|
| 958 | return rgb2hwb(keyword2rgb(args));
|
---|
| 959 | }
|
---|
| 960 |
|
---|
| 961 | function keyword2cmyk(args) {
|
---|
| 962 | return rgb2cmyk(keyword2rgb(args));
|
---|
| 963 | }
|
---|
| 964 |
|
---|
| 965 | function keyword2lab(args) {
|
---|
| 966 | return rgb2lab(keyword2rgb(args));
|
---|
| 967 | }
|
---|
| 968 |
|
---|
| 969 | function keyword2xyz(args) {
|
---|
| 970 | return rgb2xyz(keyword2rgb(args));
|
---|
| 971 | }
|
---|
| 972 |
|
---|
| 973 | var cssKeywords = {
|
---|
| 974 | aliceblue: [240,248,255],
|
---|
| 975 | antiquewhite: [250,235,215],
|
---|
| 976 | aqua: [0,255,255],
|
---|
| 977 | aquamarine: [127,255,212],
|
---|
| 978 | azure: [240,255,255],
|
---|
| 979 | beige: [245,245,220],
|
---|
| 980 | bisque: [255,228,196],
|
---|
| 981 | black: [0,0,0],
|
---|
| 982 | blanchedalmond: [255,235,205],
|
---|
| 983 | blue: [0,0,255],
|
---|
| 984 | blueviolet: [138,43,226],
|
---|
| 985 | brown: [165,42,42],
|
---|
| 986 | burlywood: [222,184,135],
|
---|
| 987 | cadetblue: [95,158,160],
|
---|
| 988 | chartreuse: [127,255,0],
|
---|
| 989 | chocolate: [210,105,30],
|
---|
| 990 | coral: [255,127,80],
|
---|
| 991 | cornflowerblue: [100,149,237],
|
---|
| 992 | cornsilk: [255,248,220],
|
---|
| 993 | crimson: [220,20,60],
|
---|
| 994 | cyan: [0,255,255],
|
---|
| 995 | darkblue: [0,0,139],
|
---|
| 996 | darkcyan: [0,139,139],
|
---|
| 997 | darkgoldenrod: [184,134,11],
|
---|
| 998 | darkgray: [169,169,169],
|
---|
| 999 | darkgreen: [0,100,0],
|
---|
| 1000 | darkgrey: [169,169,169],
|
---|
| 1001 | darkkhaki: [189,183,107],
|
---|
| 1002 | darkmagenta: [139,0,139],
|
---|
| 1003 | darkolivegreen: [85,107,47],
|
---|
| 1004 | darkorange: [255,140,0],
|
---|
| 1005 | darkorchid: [153,50,204],
|
---|
| 1006 | darkred: [139,0,0],
|
---|
| 1007 | darksalmon: [233,150,122],
|
---|
| 1008 | darkseagreen: [143,188,143],
|
---|
| 1009 | darkslateblue: [72,61,139],
|
---|
| 1010 | darkslategray: [47,79,79],
|
---|
| 1011 | darkslategrey: [47,79,79],
|
---|
| 1012 | darkturquoise: [0,206,209],
|
---|
| 1013 | darkviolet: [148,0,211],
|
---|
| 1014 | deeppink: [255,20,147],
|
---|
| 1015 | deepskyblue: [0,191,255],
|
---|
| 1016 | dimgray: [105,105,105],
|
---|
| 1017 | dimgrey: [105,105,105],
|
---|
| 1018 | dodgerblue: [30,144,255],
|
---|
| 1019 | firebrick: [178,34,34],
|
---|
| 1020 | floralwhite: [255,250,240],
|
---|
| 1021 | forestgreen: [34,139,34],
|
---|
| 1022 | fuchsia: [255,0,255],
|
---|
| 1023 | gainsboro: [220,220,220],
|
---|
| 1024 | ghostwhite: [248,248,255],
|
---|
| 1025 | gold: [255,215,0],
|
---|
| 1026 | goldenrod: [218,165,32],
|
---|
| 1027 | gray: [128,128,128],
|
---|
| 1028 | green: [0,128,0],
|
---|
| 1029 | greenyellow: [173,255,47],
|
---|
| 1030 | grey: [128,128,128],
|
---|
| 1031 | honeydew: [240,255,240],
|
---|
| 1032 | hotpink: [255,105,180],
|
---|
| 1033 | indianred: [205,92,92],
|
---|
| 1034 | indigo: [75,0,130],
|
---|
| 1035 | ivory: [255,255,240],
|
---|
| 1036 | khaki: [240,230,140],
|
---|
| 1037 | lavender: [230,230,250],
|
---|
| 1038 | lavenderblush: [255,240,245],
|
---|
| 1039 | lawngreen: [124,252,0],
|
---|
| 1040 | lemonchiffon: [255,250,205],
|
---|
| 1041 | lightblue: [173,216,230],
|
---|
| 1042 | lightcoral: [240,128,128],
|
---|
| 1043 | lightcyan: [224,255,255],
|
---|
| 1044 | lightgoldenrodyellow: [250,250,210],
|
---|
| 1045 | lightgray: [211,211,211],
|
---|
| 1046 | lightgreen: [144,238,144],
|
---|
| 1047 | lightgrey: [211,211,211],
|
---|
| 1048 | lightpink: [255,182,193],
|
---|
| 1049 | lightsalmon: [255,160,122],
|
---|
| 1050 | lightseagreen: [32,178,170],
|
---|
| 1051 | lightskyblue: [135,206,250],
|
---|
| 1052 | lightslategray: [119,136,153],
|
---|
| 1053 | lightslategrey: [119,136,153],
|
---|
| 1054 | lightsteelblue: [176,196,222],
|
---|
| 1055 | lightyellow: [255,255,224],
|
---|
| 1056 | lime: [0,255,0],
|
---|
| 1057 | limegreen: [50,205,50],
|
---|
| 1058 | linen: [250,240,230],
|
---|
| 1059 | magenta: [255,0,255],
|
---|
| 1060 | maroon: [128,0,0],
|
---|
| 1061 | mediumaquamarine: [102,205,170],
|
---|
| 1062 | mediumblue: [0,0,205],
|
---|
| 1063 | mediumorchid: [186,85,211],
|
---|
| 1064 | mediumpurple: [147,112,219],
|
---|
| 1065 | mediumseagreen: [60,179,113],
|
---|
| 1066 | mediumslateblue: [123,104,238],
|
---|
| 1067 | mediumspringgreen: [0,250,154],
|
---|
| 1068 | mediumturquoise: [72,209,204],
|
---|
| 1069 | mediumvioletred: [199,21,133],
|
---|
| 1070 | midnightblue: [25,25,112],
|
---|
| 1071 | mintcream: [245,255,250],
|
---|
| 1072 | mistyrose: [255,228,225],
|
---|
| 1073 | moccasin: [255,228,181],
|
---|
| 1074 | navajowhite: [255,222,173],
|
---|
| 1075 | navy: [0,0,128],
|
---|
| 1076 | oldlace: [253,245,230],
|
---|
| 1077 | olive: [128,128,0],
|
---|
| 1078 | olivedrab: [107,142,35],
|
---|
| 1079 | orange: [255,165,0],
|
---|
| 1080 | orangered: [255,69,0],
|
---|
| 1081 | orchid: [218,112,214],
|
---|
| 1082 | palegoldenrod: [238,232,170],
|
---|
| 1083 | palegreen: [152,251,152],
|
---|
| 1084 | paleturquoise: [175,238,238],
|
---|
| 1085 | palevioletred: [219,112,147],
|
---|
| 1086 | papayawhip: [255,239,213],
|
---|
| 1087 | peachpuff: [255,218,185],
|
---|
| 1088 | peru: [205,133,63],
|
---|
| 1089 | pink: [255,192,203],
|
---|
| 1090 | plum: [221,160,221],
|
---|
| 1091 | powderblue: [176,224,230],
|
---|
| 1092 | purple: [128,0,128],
|
---|
| 1093 | rebeccapurple: [102, 51, 153],
|
---|
| 1094 | red: [255,0,0],
|
---|
| 1095 | rosybrown: [188,143,143],
|
---|
| 1096 | royalblue: [65,105,225],
|
---|
| 1097 | saddlebrown: [139,69,19],
|
---|
| 1098 | salmon: [250,128,114],
|
---|
| 1099 | sandybrown: [244,164,96],
|
---|
| 1100 | seagreen: [46,139,87],
|
---|
| 1101 | seashell: [255,245,238],
|
---|
| 1102 | sienna: [160,82,45],
|
---|
| 1103 | silver: [192,192,192],
|
---|
| 1104 | skyblue: [135,206,235],
|
---|
| 1105 | slateblue: [106,90,205],
|
---|
| 1106 | slategray: [112,128,144],
|
---|
| 1107 | slategrey: [112,128,144],
|
---|
| 1108 | snow: [255,250,250],
|
---|
| 1109 | springgreen: [0,255,127],
|
---|
| 1110 | steelblue: [70,130,180],
|
---|
| 1111 | tan: [210,180,140],
|
---|
| 1112 | teal: [0,128,128],
|
---|
| 1113 | thistle: [216,191,216],
|
---|
| 1114 | tomato: [255,99,71],
|
---|
| 1115 | turquoise: [64,224,208],
|
---|
| 1116 | violet: [238,130,238],
|
---|
| 1117 | wheat: [245,222,179],
|
---|
| 1118 | white: [255,255,255],
|
---|
| 1119 | whitesmoke: [245,245,245],
|
---|
| 1120 | yellow: [255,255,0],
|
---|
| 1121 | yellowgreen: [154,205,50]
|
---|
| 1122 | };
|
---|
| 1123 |
|
---|
| 1124 | var reverseKeywords = {};
|
---|
| 1125 | for (var key in cssKeywords) {
|
---|
| 1126 | reverseKeywords[JSON.stringify(cssKeywords[key])] = key;
|
---|
| 1127 | }
|
---|
| 1128 |
|
---|
| 1129 | },{}],3:[function(require,module,exports){
|
---|
| 1130 | var conversions = require("./conversions");
|
---|
| 1131 |
|
---|
| 1132 | var convert = function() {
|
---|
| 1133 | return new Converter();
|
---|
| 1134 | }
|
---|
| 1135 |
|
---|
| 1136 | for (var func in conversions) {
|
---|
| 1137 | // export Raw versions
|
---|
| 1138 | convert[func + "Raw"] = (function(func) {
|
---|
| 1139 | // accept array or plain args
|
---|
| 1140 | return function(arg) {
|
---|
| 1141 | if (typeof arg == "number")
|
---|
| 1142 | arg = Array.prototype.slice.call(arguments);
|
---|
| 1143 | return conversions[func](arg);
|
---|
| 1144 | }
|
---|
| 1145 | })(func);
|
---|
| 1146 |
|
---|
| 1147 | var pair = /(\w+)2(\w+)/.exec(func),
|
---|
| 1148 | from = pair[1],
|
---|
| 1149 | to = pair[2];
|
---|
| 1150 |
|
---|
| 1151 | // export rgb2hsl and ["rgb"]["hsl"]
|
---|
| 1152 | convert[from] = convert[from] || {};
|
---|
| 1153 |
|
---|
| 1154 | convert[from][to] = convert[func] = (function(func) {
|
---|
| 1155 | return function(arg) {
|
---|
| 1156 | if (typeof arg == "number")
|
---|
| 1157 | arg = Array.prototype.slice.call(arguments);
|
---|
| 1158 |
|
---|
| 1159 | var val = conversions[func](arg);
|
---|
| 1160 | if (typeof val == "string" || val === undefined)
|
---|
| 1161 | return val; // keyword
|
---|
| 1162 |
|
---|
| 1163 | for (var i = 0; i < val.length; i++)
|
---|
| 1164 | val[i] = Math.round(val[i]);
|
---|
| 1165 | return val;
|
---|
| 1166 | }
|
---|
| 1167 | })(func);
|
---|
| 1168 | }
|
---|
| 1169 |
|
---|
| 1170 |
|
---|
| 1171 | /* Converter does lazy conversion and caching */
|
---|
| 1172 | var Converter = function() {
|
---|
| 1173 | this.convs = {};
|
---|
| 1174 | };
|
---|
| 1175 |
|
---|
| 1176 | /* Either get the values for a space or
|
---|
| 1177 | set the values for a space, depending on args */
|
---|
| 1178 | Converter.prototype.routeSpace = function(space, args) {
|
---|
| 1179 | var values = args[0];
|
---|
| 1180 | if (values === undefined) {
|
---|
| 1181 | // color.rgb()
|
---|
| 1182 | return this.getValues(space);
|
---|
| 1183 | }
|
---|
| 1184 | // color.rgb(10, 10, 10)
|
---|
| 1185 | if (typeof values == "number") {
|
---|
| 1186 | values = Array.prototype.slice.call(args);
|
---|
| 1187 | }
|
---|
| 1188 |
|
---|
| 1189 | return this.setValues(space, values);
|
---|
| 1190 | };
|
---|
| 1191 |
|
---|
| 1192 | /* Set the values for a space, invalidating cache */
|
---|
| 1193 | Converter.prototype.setValues = function(space, values) {
|
---|
| 1194 | this.space = space;
|
---|
| 1195 | this.convs = {};
|
---|
| 1196 | this.convs[space] = values;
|
---|
| 1197 | return this;
|
---|
| 1198 | };
|
---|
| 1199 |
|
---|
| 1200 | /* Get the values for a space. If there's already
|
---|
| 1201 | a conversion for the space, fetch it, otherwise
|
---|
| 1202 | compute it */
|
---|
| 1203 | Converter.prototype.getValues = function(space) {
|
---|
| 1204 | var vals = this.convs[space];
|
---|
| 1205 | if (!vals) {
|
---|
| 1206 | var fspace = this.space,
|
---|
| 1207 | from = this.convs[fspace];
|
---|
| 1208 | vals = convert[fspace][space](from);
|
---|
| 1209 |
|
---|
| 1210 | this.convs[space] = vals;
|
---|
| 1211 | }
|
---|
| 1212 | return vals;
|
---|
| 1213 | };
|
---|
| 1214 |
|
---|
| 1215 | ["rgb", "hsl", "hsv", "cmyk", "keyword"].forEach(function(space) {
|
---|
| 1216 | Converter.prototype[space] = function(vals) {
|
---|
| 1217 | return this.routeSpace(space, arguments);
|
---|
| 1218 | }
|
---|
| 1219 | });
|
---|
| 1220 |
|
---|
| 1221 | module.exports = convert;
|
---|
| 1222 | },{"./conversions":2}],4:[function(require,module,exports){
|
---|
| 1223 | /* MIT license */
|
---|
| 1224 | var colorNames = require('color-name');
|
---|
| 1225 |
|
---|
| 1226 | module.exports = {
|
---|
| 1227 | getRgba: getRgba,
|
---|
| 1228 | getHsla: getHsla,
|
---|
| 1229 | getRgb: getRgb,
|
---|
| 1230 | getHsl: getHsl,
|
---|
| 1231 | getHwb: getHwb,
|
---|
| 1232 | getAlpha: getAlpha,
|
---|
| 1233 |
|
---|
| 1234 | hexString: hexString,
|
---|
| 1235 | rgbString: rgbString,
|
---|
| 1236 | rgbaString: rgbaString,
|
---|
| 1237 | percentString: percentString,
|
---|
| 1238 | percentaString: percentaString,
|
---|
| 1239 | hslString: hslString,
|
---|
| 1240 | hslaString: hslaString,
|
---|
| 1241 | hwbString: hwbString,
|
---|
| 1242 | keyword: keyword
|
---|
| 1243 | }
|
---|
| 1244 |
|
---|
| 1245 | function getRgba(string) {
|
---|
| 1246 | if (!string) {
|
---|
| 1247 | return;
|
---|
| 1248 | }
|
---|
| 1249 | var abbr = /^#([a-fA-F0-9]{3})$/,
|
---|
| 1250 | hex = /^#([a-fA-F0-9]{6})$/,
|
---|
| 1251 | rgba = /^rgba?\(\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/,
|
---|
| 1252 | per = /^rgba?\(\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/,
|
---|
| 1253 | keyword = /(\D+)/;
|
---|
| 1254 |
|
---|
| 1255 | var rgb = [0, 0, 0],
|
---|
| 1256 | a = 1,
|
---|
| 1257 | match = string.match(abbr);
|
---|
| 1258 | if (match) {
|
---|
| 1259 | match = match[1];
|
---|
| 1260 | for (var i = 0; i < rgb.length; i++) {
|
---|
| 1261 | rgb[i] = parseInt(match[i] + match[i], 16);
|
---|
| 1262 | }
|
---|
| 1263 | }
|
---|
| 1264 | else if (match = string.match(hex)) {
|
---|
| 1265 | match = match[1];
|
---|
| 1266 | for (var i = 0; i < rgb.length; i++) {
|
---|
| 1267 | rgb[i] = parseInt(match.slice(i * 2, i * 2 + 2), 16);
|
---|
| 1268 | }
|
---|
| 1269 | }
|
---|
| 1270 | else if (match = string.match(rgba)) {
|
---|
| 1271 | for (var i = 0; i < rgb.length; i++) {
|
---|
| 1272 | rgb[i] = parseInt(match[i + 1]);
|
---|
| 1273 | }
|
---|
| 1274 | a = parseFloat(match[4]);
|
---|
| 1275 | }
|
---|
| 1276 | else if (match = string.match(per)) {
|
---|
| 1277 | for (var i = 0; i < rgb.length; i++) {
|
---|
| 1278 | rgb[i] = Math.round(parseFloat(match[i + 1]) * 2.55);
|
---|
| 1279 | }
|
---|
| 1280 | a = parseFloat(match[4]);
|
---|
| 1281 | }
|
---|
| 1282 | else if (match = string.match(keyword)) {
|
---|
| 1283 | if (match[1] == "transparent") {
|
---|
| 1284 | return [0, 0, 0, 0];
|
---|
| 1285 | }
|
---|
| 1286 | rgb = colorNames[match[1]];
|
---|
| 1287 | if (!rgb) {
|
---|
| 1288 | return;
|
---|
| 1289 | }
|
---|
| 1290 | }
|
---|
| 1291 |
|
---|
| 1292 | for (var i = 0; i < rgb.length; i++) {
|
---|
| 1293 | rgb[i] = scale(rgb[i], 0, 255);
|
---|
| 1294 | }
|
---|
| 1295 | if (!a && a != 0) {
|
---|
| 1296 | a = 1;
|
---|
| 1297 | }
|
---|
| 1298 | else {
|
---|
| 1299 | a = scale(a, 0, 1);
|
---|
| 1300 | }
|
---|
| 1301 | rgb[3] = a;
|
---|
| 1302 | return rgb;
|
---|
| 1303 | }
|
---|
| 1304 |
|
---|
| 1305 | function getHsla(string) {
|
---|
| 1306 | if (!string) {
|
---|
| 1307 | return;
|
---|
| 1308 | }
|
---|
| 1309 | var hsl = /^hsla?\(\s*([+-]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)/;
|
---|
| 1310 | var match = string.match(hsl);
|
---|
| 1311 | if (match) {
|
---|
| 1312 | var alpha = parseFloat(match[4]);
|
---|
| 1313 | var h = scale(parseInt(match[1]), 0, 360),
|
---|
| 1314 | s = scale(parseFloat(match[2]), 0, 100),
|
---|
| 1315 | l = scale(parseFloat(match[3]), 0, 100),
|
---|
| 1316 | a = scale(isNaN(alpha) ? 1 : alpha, 0, 1);
|
---|
| 1317 | return [h, s, l, a];
|
---|
| 1318 | }
|
---|
| 1319 | }
|
---|
| 1320 |
|
---|
| 1321 | function getHwb(string) {
|
---|
| 1322 | if (!string) {
|
---|
| 1323 | return;
|
---|
| 1324 | }
|
---|
| 1325 | var hwb = /^hwb\(\s*([+-]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)/;
|
---|
| 1326 | var match = string.match(hwb);
|
---|
| 1327 | if (match) {
|
---|
| 1328 | var alpha = parseFloat(match[4]);
|
---|
| 1329 | var h = scale(parseInt(match[1]), 0, 360),
|
---|
| 1330 | w = scale(parseFloat(match[2]), 0, 100),
|
---|
| 1331 | b = scale(parseFloat(match[3]), 0, 100),
|
---|
| 1332 | a = scale(isNaN(alpha) ? 1 : alpha, 0, 1);
|
---|
| 1333 | return [h, w, b, a];
|
---|
| 1334 | }
|
---|
| 1335 | }
|
---|
| 1336 |
|
---|
| 1337 | function getRgb(string) {
|
---|
| 1338 | var rgba = getRgba(string);
|
---|
| 1339 | return rgba && rgba.slice(0, 3);
|
---|
| 1340 | }
|
---|
| 1341 |
|
---|
| 1342 | function getHsl(string) {
|
---|
| 1343 | var hsla = getHsla(string);
|
---|
| 1344 | return hsla && hsla.slice(0, 3);
|
---|
| 1345 | }
|
---|
| 1346 |
|
---|
| 1347 | function getAlpha(string) {
|
---|
| 1348 | var vals = getRgba(string);
|
---|
| 1349 | if (vals) {
|
---|
| 1350 | return vals[3];
|
---|
| 1351 | }
|
---|
| 1352 | else if (vals = getHsla(string)) {
|
---|
| 1353 | return vals[3];
|
---|
| 1354 | }
|
---|
| 1355 | else if (vals = getHwb(string)) {
|
---|
| 1356 | return vals[3];
|
---|
| 1357 | }
|
---|
| 1358 | }
|
---|
| 1359 |
|
---|
| 1360 | // generators
|
---|
| 1361 | function hexString(rgb) {
|
---|
| 1362 | return "#" + hexDouble(rgb[0]) + hexDouble(rgb[1])
|
---|
| 1363 | + hexDouble(rgb[2]);
|
---|
| 1364 | }
|
---|
| 1365 |
|
---|
| 1366 | function rgbString(rgba, alpha) {
|
---|
| 1367 | if (alpha < 1 || (rgba[3] && rgba[3] < 1)) {
|
---|
| 1368 | return rgbaString(rgba, alpha);
|
---|
| 1369 | }
|
---|
| 1370 | return "rgb(" + rgba[0] + ", " + rgba[1] + ", " + rgba[2] + ")";
|
---|
| 1371 | }
|
---|
| 1372 |
|
---|
| 1373 | function rgbaString(rgba, alpha) {
|
---|
| 1374 | if (alpha === undefined) {
|
---|
| 1375 | alpha = (rgba[3] !== undefined ? rgba[3] : 1);
|
---|
| 1376 | }
|
---|
| 1377 | return "rgba(" + rgba[0] + ", " + rgba[1] + ", " + rgba[2]
|
---|
| 1378 | + ", " + alpha + ")";
|
---|
| 1379 | }
|
---|
| 1380 |
|
---|
| 1381 | function percentString(rgba, alpha) {
|
---|
| 1382 | if (alpha < 1 || (rgba[3] && rgba[3] < 1)) {
|
---|
| 1383 | return percentaString(rgba, alpha);
|
---|
| 1384 | }
|
---|
| 1385 | var r = Math.round(rgba[0]/255 * 100),
|
---|
| 1386 | g = Math.round(rgba[1]/255 * 100),
|
---|
| 1387 | b = Math.round(rgba[2]/255 * 100);
|
---|
| 1388 |
|
---|
| 1389 | return "rgb(" + r + "%, " + g + "%, " + b + "%)";
|
---|
| 1390 | }
|
---|
| 1391 |
|
---|
| 1392 | function percentaString(rgba, alpha) {
|
---|
| 1393 | var r = Math.round(rgba[0]/255 * 100),
|
---|
| 1394 | g = Math.round(rgba[1]/255 * 100),
|
---|
| 1395 | b = Math.round(rgba[2]/255 * 100);
|
---|
| 1396 | return "rgba(" + r + "%, " + g + "%, " + b + "%, " + (alpha || rgba[3] || 1) + ")";
|
---|
| 1397 | }
|
---|
| 1398 |
|
---|
| 1399 | function hslString(hsla, alpha) {
|
---|
| 1400 | if (alpha < 1 || (hsla[3] && hsla[3] < 1)) {
|
---|
| 1401 | return hslaString(hsla, alpha);
|
---|
| 1402 | }
|
---|
| 1403 | return "hsl(" + hsla[0] + ", " + hsla[1] + "%, " + hsla[2] + "%)";
|
---|
| 1404 | }
|
---|
| 1405 |
|
---|
| 1406 | function hslaString(hsla, alpha) {
|
---|
| 1407 | if (alpha === undefined) {
|
---|
| 1408 | alpha = (hsla[3] !== undefined ? hsla[3] : 1);
|
---|
| 1409 | }
|
---|
| 1410 | return "hsla(" + hsla[0] + ", " + hsla[1] + "%, " + hsla[2] + "%, "
|
---|
| 1411 | + alpha + ")";
|
---|
| 1412 | }
|
---|
| 1413 |
|
---|
| 1414 | // hwb is a bit different than rgb(a) & hsl(a) since there is no alpha specific syntax
|
---|
| 1415 | // (hwb have alpha optional & 1 is default value)
|
---|
| 1416 | function hwbString(hwb, alpha) {
|
---|
| 1417 | if (alpha === undefined) {
|
---|
| 1418 | alpha = (hwb[3] !== undefined ? hwb[3] : 1);
|
---|
| 1419 | }
|
---|
| 1420 | return "hwb(" + hwb[0] + ", " + hwb[1] + "%, " + hwb[2] + "%"
|
---|
| 1421 | + (alpha !== undefined && alpha !== 1 ? ", " + alpha : "") + ")";
|
---|
| 1422 | }
|
---|
| 1423 |
|
---|
| 1424 | function keyword(rgb) {
|
---|
| 1425 | return reverseNames[rgb.slice(0, 3)];
|
---|
| 1426 | }
|
---|
| 1427 |
|
---|
| 1428 | // helpers
|
---|
| 1429 | function scale(num, min, max) {
|
---|
| 1430 | return Math.min(Math.max(min, num), max);
|
---|
| 1431 | }
|
---|
| 1432 |
|
---|
| 1433 | function hexDouble(num) {
|
---|
| 1434 | var str = num.toString(16).toUpperCase();
|
---|
| 1435 | return (str.length < 2) ? "0" + str : str;
|
---|
| 1436 | }
|
---|
| 1437 |
|
---|
| 1438 |
|
---|
| 1439 | //create a list of reverse color names
|
---|
| 1440 | var reverseNames = {};
|
---|
| 1441 | for (var name in colorNames) {
|
---|
| 1442 | reverseNames[colorNames[name]] = name;
|
---|
| 1443 | }
|
---|
| 1444 |
|
---|
| 1445 | },{"color-name":5}],5:[function(require,module,exports){
|
---|
| 1446 | module.exports={
|
---|
| 1447 | "aliceblue": [240, 248, 255],
|
---|
| 1448 | "antiquewhite": [250, 235, 215],
|
---|
| 1449 | "aqua": [0, 255, 255],
|
---|
| 1450 | "aquamarine": [127, 255, 212],
|
---|
| 1451 | "azure": [240, 255, 255],
|
---|
| 1452 | "beige": [245, 245, 220],
|
---|
| 1453 | "bisque": [255, 228, 196],
|
---|
| 1454 | "black": [0, 0, 0],
|
---|
| 1455 | "blanchedalmond": [255, 235, 205],
|
---|
| 1456 | "blue": [0, 0, 255],
|
---|
| 1457 | "blueviolet": [138, 43, 226],
|
---|
| 1458 | "brown": [165, 42, 42],
|
---|
| 1459 | "burlywood": [222, 184, 135],
|
---|
| 1460 | "cadetblue": [95, 158, 160],
|
---|
| 1461 | "chartreuse": [127, 255, 0],
|
---|
| 1462 | "chocolate": [210, 105, 30],
|
---|
| 1463 | "coral": [255, 127, 80],
|
---|
| 1464 | "cornflowerblue": [100, 149, 237],
|
---|
| 1465 | "cornsilk": [255, 248, 220],
|
---|
| 1466 | "crimson": [220, 20, 60],
|
---|
| 1467 | "cyan": [0, 255, 255],
|
---|
| 1468 | "darkblue": [0, 0, 139],
|
---|
| 1469 | "darkcyan": [0, 139, 139],
|
---|
| 1470 | "darkgoldenrod": [184, 134, 11],
|
---|
| 1471 | "darkgray": [169, 169, 169],
|
---|
| 1472 | "darkgreen": [0, 100, 0],
|
---|
| 1473 | "darkgrey": [169, 169, 169],
|
---|
| 1474 | "darkkhaki": [189, 183, 107],
|
---|
| 1475 | "darkmagenta": [139, 0, 139],
|
---|
| 1476 | "darkolivegreen": [85, 107, 47],
|
---|
| 1477 | "darkorange": [255, 140, 0],
|
---|
| 1478 | "darkorchid": [153, 50, 204],
|
---|
| 1479 | "darkred": [139, 0, 0],
|
---|
| 1480 | "darksalmon": [233, 150, 122],
|
---|
| 1481 | "darkseagreen": [143, 188, 143],
|
---|
| 1482 | "darkslateblue": [72, 61, 139],
|
---|
| 1483 | "darkslategray": [47, 79, 79],
|
---|
| 1484 | "darkslategrey": [47, 79, 79],
|
---|
| 1485 | "darkturquoise": [0, 206, 209],
|
---|
| 1486 | "darkviolet": [148, 0, 211],
|
---|
| 1487 | "deeppink": [255, 20, 147],
|
---|
| 1488 | "deepskyblue": [0, 191, 255],
|
---|
| 1489 | "dimgray": [105, 105, 105],
|
---|
| 1490 | "dimgrey": [105, 105, 105],
|
---|
| 1491 | "dodgerblue": [30, 144, 255],
|
---|
| 1492 | "firebrick": [178, 34, 34],
|
---|
| 1493 | "floralwhite": [255, 250, 240],
|
---|
| 1494 | "forestgreen": [34, 139, 34],
|
---|
| 1495 | "fuchsia": [255, 0, 255],
|
---|
| 1496 | "gainsboro": [220, 220, 220],
|
---|
| 1497 | "ghostwhite": [248, 248, 255],
|
---|
| 1498 | "gold": [255, 215, 0],
|
---|
| 1499 | "goldenrod": [218, 165, 32],
|
---|
| 1500 | "gray": [128, 128, 128],
|
---|
| 1501 | "green": [0, 128, 0],
|
---|
| 1502 | "greenyellow": [173, 255, 47],
|
---|
| 1503 | "grey": [128, 128, 128],
|
---|
| 1504 | "honeydew": [240, 255, 240],
|
---|
| 1505 | "hotpink": [255, 105, 180],
|
---|
| 1506 | "indianred": [205, 92, 92],
|
---|
| 1507 | "indigo": [75, 0, 130],
|
---|
| 1508 | "ivory": [255, 255, 240],
|
---|
| 1509 | "khaki": [240, 230, 140],
|
---|
| 1510 | "lavender": [230, 230, 250],
|
---|
| 1511 | "lavenderblush": [255, 240, 245],
|
---|
| 1512 | "lawngreen": [124, 252, 0],
|
---|
| 1513 | "lemonchiffon": [255, 250, 205],
|
---|
| 1514 | "lightblue": [173, 216, 230],
|
---|
| 1515 | "lightcoral": [240, 128, 128],
|
---|
| 1516 | "lightcyan": [224, 255, 255],
|
---|
| 1517 | "lightgoldenrodyellow": [250, 250, 210],
|
---|
| 1518 | "lightgray": [211, 211, 211],
|
---|
| 1519 | "lightgreen": [144, 238, 144],
|
---|
| 1520 | "lightgrey": [211, 211, 211],
|
---|
| 1521 | "lightpink": [255, 182, 193],
|
---|
| 1522 | "lightsalmon": [255, 160, 122],
|
---|
| 1523 | "lightseagreen": [32, 178, 170],
|
---|
| 1524 | "lightskyblue": [135, 206, 250],
|
---|
| 1525 | "lightslategray": [119, 136, 153],
|
---|
| 1526 | "lightslategrey": [119, 136, 153],
|
---|
| 1527 | "lightsteelblue": [176, 196, 222],
|
---|
| 1528 | "lightyellow": [255, 255, 224],
|
---|
| 1529 | "lime": [0, 255, 0],
|
---|
| 1530 | "limegreen": [50, 205, 50],
|
---|
| 1531 | "linen": [250, 240, 230],
|
---|
| 1532 | "magenta": [255, 0, 255],
|
---|
| 1533 | "maroon": [128, 0, 0],
|
---|
| 1534 | "mediumaquamarine": [102, 205, 170],
|
---|
| 1535 | "mediumblue": [0, 0, 205],
|
---|
| 1536 | "mediumorchid": [186, 85, 211],
|
---|
| 1537 | "mediumpurple": [147, 112, 219],
|
---|
| 1538 | "mediumseagreen": [60, 179, 113],
|
---|
| 1539 | "mediumslateblue": [123, 104, 238],
|
---|
| 1540 | "mediumspringgreen": [0, 250, 154],
|
---|
| 1541 | "mediumturquoise": [72, 209, 204],
|
---|
| 1542 | "mediumvioletred": [199, 21, 133],
|
---|
| 1543 | "midnightblue": [25, 25, 112],
|
---|
| 1544 | "mintcream": [245, 255, 250],
|
---|
| 1545 | "mistyrose": [255, 228, 225],
|
---|
| 1546 | "moccasin": [255, 228, 181],
|
---|
| 1547 | "navajowhite": [255, 222, 173],
|
---|
| 1548 | "navy": [0, 0, 128],
|
---|
| 1549 | "oldlace": [253, 245, 230],
|
---|
| 1550 | "olive": [128, 128, 0],
|
---|
| 1551 | "olivedrab": [107, 142, 35],
|
---|
| 1552 | "orange": [255, 165, 0],
|
---|
| 1553 | "orangered": [255, 69, 0],
|
---|
| 1554 | "orchid": [218, 112, 214],
|
---|
| 1555 | "palegoldenrod": [238, 232, 170],
|
---|
| 1556 | "palegreen": [152, 251, 152],
|
---|
| 1557 | "paleturquoise": [175, 238, 238],
|
---|
| 1558 | "palevioletred": [219, 112, 147],
|
---|
| 1559 | "papayawhip": [255, 239, 213],
|
---|
| 1560 | "peachpuff": [255, 218, 185],
|
---|
| 1561 | "peru": [205, 133, 63],
|
---|
| 1562 | "pink": [255, 192, 203],
|
---|
| 1563 | "plum": [221, 160, 221],
|
---|
| 1564 | "powderblue": [176, 224, 230],
|
---|
| 1565 | "purple": [128, 0, 128],
|
---|
| 1566 | "rebeccapurple": [102, 51, 153],
|
---|
| 1567 | "red": [255, 0, 0],
|
---|
| 1568 | "rosybrown": [188, 143, 143],
|
---|
| 1569 | "royalblue": [65, 105, 225],
|
---|
| 1570 | "saddlebrown": [139, 69, 19],
|
---|
| 1571 | "salmon": [250, 128, 114],
|
---|
| 1572 | "sandybrown": [244, 164, 96],
|
---|
| 1573 | "seagreen": [46, 139, 87],
|
---|
| 1574 | "seashell": [255, 245, 238],
|
---|
| 1575 | "sienna": [160, 82, 45],
|
---|
| 1576 | "silver": [192, 192, 192],
|
---|
| 1577 | "skyblue": [135, 206, 235],
|
---|
| 1578 | "slateblue": [106, 90, 205],
|
---|
| 1579 | "slategray": [112, 128, 144],
|
---|
| 1580 | "slategrey": [112, 128, 144],
|
---|
| 1581 | "snow": [255, 250, 250],
|
---|
| 1582 | "springgreen": [0, 255, 127],
|
---|
| 1583 | "steelblue": [70, 130, 180],
|
---|
| 1584 | "tan": [210, 180, 140],
|
---|
| 1585 | "teal": [0, 128, 128],
|
---|
| 1586 | "thistle": [216, 191, 216],
|
---|
| 1587 | "tomato": [255, 99, 71],
|
---|
| 1588 | "turquoise": [64, 224, 208],
|
---|
| 1589 | "violet": [238, 130, 238],
|
---|
| 1590 | "wheat": [245, 222, 179],
|
---|
| 1591 | "white": [255, 255, 255],
|
---|
| 1592 | "whitesmoke": [245, 245, 245],
|
---|
| 1593 | "yellow": [255, 255, 0],
|
---|
| 1594 | "yellowgreen": [154, 205, 50]
|
---|
| 1595 | }
|
---|
| 1596 | },{}],6:[function(require,module,exports){
|
---|
| 1597 | module.exports = require('./lib/geocrunch');
|
---|
| 1598 | },{"./lib/geocrunch":11}],7:[function(require,module,exports){
|
---|
| 1599 | // distance.js - Distance mixins for Paths
|
---|
| 1600 |
|
---|
| 1601 | var _ = require('underscore');
|
---|
| 1602 |
|
---|
| 1603 | var R = require('./constants').EARTHRADIUS;
|
---|
| 1604 | var units = require('./units');
|
---|
| 1605 | var flipCoords = require('./flipcoords');
|
---|
| 1606 |
|
---|
| 1607 | // Area conversions (from sqmeters)
|
---|
| 1608 | var convertFuncs = {
|
---|
| 1609 | sqmeters: function (a) {
|
---|
| 1610 | return a;
|
---|
| 1611 | },
|
---|
| 1612 | sqmiles: function (a) {
|
---|
| 1613 | return units.sqMeters.toSqMiles(a);
|
---|
| 1614 | },
|
---|
| 1615 | acres: function (a) {
|
---|
| 1616 | return units.sqMeters.toAcres(a);
|
---|
| 1617 | }
|
---|
| 1618 | };
|
---|
| 1619 |
|
---|
| 1620 | // Calculates area in square meters
|
---|
| 1621 | // Method taken from OpenLayers API, https://github.com/openlayers/openlayers/blob/master/lib/OpenLayers/Geometry/LinearRing.js#L270
|
---|
| 1622 | var calcArea = function (coordArray) {
|
---|
| 1623 | var area = 0, i, l, c1, c2;
|
---|
| 1624 | for (i = 0, l = coordArray.length; i < l; i += 1) {
|
---|
| 1625 | c1 = coordArray[i];
|
---|
| 1626 | c2 = coordArray[(i + 1) % coordArray.length]; // Access next item in array until last item is i, then accesses first (0)
|
---|
| 1627 | area = area + units.degrees.toRadians(c2[0] - c1[0]) * (2 + Math.sin(units.degrees.toRadians(c1[1])) + Math.sin(units.degrees.toRadians(c2[1])));
|
---|
| 1628 | }
|
---|
| 1629 | return Math.abs(area * R * R / 2);
|
---|
| 1630 | };
|
---|
| 1631 |
|
---|
| 1632 | var calcCenter = function (coordArray) {
|
---|
| 1633 | var offset = coordArray[0], twiceArea = 0, x = 0, y = 0, i, l, c1, c2, f;
|
---|
| 1634 | if (coordArray.length === 1) {
|
---|
| 1635 | return coordArray[0];
|
---|
| 1636 | }
|
---|
| 1637 | for (i = 0, l = coordArray.length; i < l; i += 1) {
|
---|
| 1638 | c1 = coordArray[i];
|
---|
| 1639 | c2 = coordArray[(i + 1) % coordArray.length]; // Access next item in array until last item is i, then accesses first (0)
|
---|
| 1640 | f = (c1[1] - offset[1]) * (c2[0] - offset[0]) - (c2[1] - offset[1]) * (c1[0] - offset[0]);
|
---|
| 1641 | twiceArea = twiceArea + f;
|
---|
| 1642 | x = x + ((c1[0] + c2[0] - 2 * offset[0]) * f);
|
---|
| 1643 | y = y + ((c1[1] + c2[1] - 2 * offset[1]) * f);
|
---|
| 1644 | }
|
---|
| 1645 | f = twiceArea * 3;
|
---|
| 1646 | return [x / f + offset[0], y / f + offset[1]];
|
---|
| 1647 | };
|
---|
| 1648 |
|
---|
| 1649 | module.exports = {
|
---|
| 1650 | _internalAreaCalc: function () {
|
---|
| 1651 | // If not set, set this._calcedArea to total area in UNITS
|
---|
| 1652 | // Checks for cache to prevent additional unnecessary calcs
|
---|
| 1653 | if (!this._calcedArea) {
|
---|
| 1654 | if (this._coords.length < 3) {
|
---|
| 1655 | this._calcedArea = 0;
|
---|
| 1656 | } else {
|
---|
| 1657 | this._calcedArea = calcArea(this._coords);
|
---|
| 1658 | }
|
---|
| 1659 | }
|
---|
| 1660 | },
|
---|
| 1661 | _internalCenterCalc: function () {
|
---|
| 1662 | if (!this._calcedCenter && this._coords.length) {
|
---|
| 1663 | this._calcedCenter = calcCenter(this._coords);
|
---|
| 1664 | }
|
---|
| 1665 | },
|
---|
| 1666 | area: function (options) {
|
---|
| 1667 | var opts = _.extend({
|
---|
| 1668 | units: 'sqmeters'
|
---|
| 1669 | }, options);
|
---|
| 1670 | this._internalAreaCalc();
|
---|
| 1671 | if (_.isFunction(convertFuncs[opts.units])) {
|
---|
| 1672 | return convertFuncs[opts.units](this._calcedArea);
|
---|
| 1673 | }
|
---|
| 1674 | // TODO. Handle non-matching units
|
---|
| 1675 | },
|
---|
| 1676 | center: function () {
|
---|
| 1677 | this._internalCenterCalc();
|
---|
| 1678 | return this._options.imBackwards === true ? flipCoords(this._calcedCenter) : this._calcedCenter;
|
---|
| 1679 | }
|
---|
| 1680 | };
|
---|
| 1681 | },{"./constants":8,"./flipcoords":10,"./units":13,"underscore":14}],8:[function(require,module,exports){
|
---|
| 1682 | // utils/constants.js
|
---|
| 1683 |
|
---|
| 1684 | module.exports = {
|
---|
| 1685 | EARTHRADIUS: 6371000 // R in meters
|
---|
| 1686 | };
|
---|
| 1687 | },{}],9:[function(require,module,exports){
|
---|
| 1688 | // distance.js - Distance mixins for Paths
|
---|
| 1689 |
|
---|
| 1690 | var _ = require('underscore');
|
---|
| 1691 |
|
---|
| 1692 | var R = require('./constants').EARTHRADIUS;
|
---|
| 1693 | var units = require('./units');
|
---|
| 1694 |
|
---|
| 1695 | // Distance conversions (from meters)
|
---|
| 1696 | var convertFuncs = {
|
---|
| 1697 | meters: function (d) {
|
---|
| 1698 | return d;
|
---|
| 1699 | },
|
---|
| 1700 | kilometers: function (d) {
|
---|
| 1701 | return units.meters.toKilometers(d);
|
---|
| 1702 | },
|
---|
| 1703 | feet: function (d) {
|
---|
| 1704 | return units.meters.toFeet(d);
|
---|
| 1705 | },
|
---|
| 1706 | miles: function (d) {
|
---|
| 1707 | return units.meters.toMiles(d);
|
---|
| 1708 | }
|
---|
| 1709 | };
|
---|
| 1710 |
|
---|
| 1711 | // Distance in meters
|
---|
| 1712 | // Always positive regardless of direction
|
---|
| 1713 | // Calculation based on Haversine Formula http://en.wikipedia.org/wiki/Haversine_formula
|
---|
| 1714 | // Another method is @ http://www.movable-type.co.uk/scripts/latlong-vincenty.html but seems way overcomplicated
|
---|
| 1715 | var calcDistance = function (coord1, coord2) {
|
---|
| 1716 | var deltaLng = units.degrees.toRadians(coord1[0] - coord2[0]),
|
---|
| 1717 | deltaLat = units.degrees.toRadians(coord1[1] - coord2[1]),
|
---|
| 1718 | lat1 = units.degrees.toRadians(coord1[1]),
|
---|
| 1719 | lat2 = units.degrees.toRadians(coord2[1]),
|
---|
| 1720 | hvsLng = Math.sin(deltaLng / 2),
|
---|
| 1721 | hvsLat = Math.sin(deltaLat / 2);
|
---|
| 1722 |
|
---|
| 1723 | var a = hvsLat * hvsLat + hvsLng * hvsLng * Math.cos(lat1) * Math.cos(lat2);
|
---|
| 1724 | return R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
|
---|
| 1725 | };
|
---|
| 1726 |
|
---|
| 1727 | module.exports = {
|
---|
| 1728 | _internalDistanceCalc: function () {
|
---|
| 1729 | // If not set, set this._calcedDistance to total distance in meters
|
---|
| 1730 | // Checks for cache to prevent additional unnecessary calcs
|
---|
| 1731 | var distance = 0, i, l;
|
---|
| 1732 | if (!this._calcedDistance) {
|
---|
| 1733 | for (i = 0, l = this._coords.length; i < l; i += 1) {
|
---|
| 1734 | if (i > 0) {
|
---|
| 1735 | distance = distance + calcDistance(this._coords[i - 1], this._coords[i]);
|
---|
| 1736 | }
|
---|
| 1737 | }
|
---|
| 1738 | this._calcedDistance = distance;
|
---|
| 1739 | }
|
---|
| 1740 | },
|
---|
| 1741 | distance: function (options) {
|
---|
| 1742 | var opts = _.extend({
|
---|
| 1743 | units: 'meters'
|
---|
| 1744 | }, options);
|
---|
| 1745 | this._internalDistanceCalc();
|
---|
| 1746 | if (_.isFunction(convertFuncs[opts.units])) {
|
---|
| 1747 | return convertFuncs[opts.units](this._calcedDistance);
|
---|
| 1748 | }
|
---|
| 1749 | // TODO. Handle non-matching units
|
---|
| 1750 | }
|
---|
| 1751 | };
|
---|
| 1752 | },{"./constants":8,"./units":13,"underscore":14}],10:[function(require,module,exports){
|
---|
| 1753 | // utils/flipcoords.js - Util functions for working with backwards coordinates [lat, lng]
|
---|
| 1754 |
|
---|
| 1755 | var _ = require('underscore');
|
---|
| 1756 |
|
---|
| 1757 | module.exports = function (backwardsCoordArray) {
|
---|
| 1758 | return _.map(backwardsCoordArray, function (backwardsCoord) {
|
---|
| 1759 | return [backwardsCoord[1], backwardsCoord[0]];
|
---|
| 1760 | });
|
---|
| 1761 | };
|
---|
| 1762 | },{"underscore":14}],11:[function(require,module,exports){
|
---|
| 1763 | // geocrunch.js
|
---|
| 1764 |
|
---|
| 1765 | var _ = require('underscore');
|
---|
| 1766 |
|
---|
| 1767 | var Path = require('./path');
|
---|
| 1768 | var distanceMixins = require('./distance'),
|
---|
| 1769 | areaMixins = require('./area');
|
---|
| 1770 |
|
---|
| 1771 | _.extend(Path.prototype, distanceMixins, areaMixins);
|
---|
| 1772 |
|
---|
| 1773 | exports.path = function (coords, options) {
|
---|
| 1774 | return new Path(coords, options);
|
---|
| 1775 | };
|
---|
| 1776 | },{"./area":7,"./distance":9,"./path":12,"underscore":14}],12:[function(require,module,exports){
|
---|
| 1777 | // path.js - Object for working with a linear path of coordinates
|
---|
| 1778 |
|
---|
| 1779 | var flipCoords = require('./flipcoords');
|
---|
| 1780 |
|
---|
| 1781 | var Path = function (coords, options) {
|
---|
| 1782 | this._options = options || {};
|
---|
| 1783 |
|
---|
| 1784 | // Set this._coords... Think about flipping at time of calcs for less iterations/better perf. May risk code clarity and mixin ease.
|
---|
| 1785 | coords = coords || [];
|
---|
| 1786 | this._coords = this._options.imBackwards === true ? flipCoords(coords) : coords;
|
---|
| 1787 | };
|
---|
| 1788 |
|
---|
| 1789 | module.exports = Path;
|
---|
| 1790 |
|
---|
| 1791 | },{"./flipcoords":10}],13:[function(require,module,exports){
|
---|
| 1792 | // units.js - Standard unit conversions
|
---|
| 1793 |
|
---|
| 1794 | exports.meters = {
|
---|
| 1795 | toFeet: function (m) {
|
---|
| 1796 | return m * 3.28084;
|
---|
| 1797 | },
|
---|
| 1798 | toKilometers: function (m) {
|
---|
| 1799 | return m * 0.001;
|
---|
| 1800 | },
|
---|
| 1801 | toMiles: function (m) {
|
---|
| 1802 | return m * 0.000621371;
|
---|
| 1803 | }
|
---|
| 1804 | };
|
---|
| 1805 |
|
---|
| 1806 | exports.sqMeters = {
|
---|
| 1807 | toSqMiles: function (m) {
|
---|
| 1808 | return m * 0.000000386102;
|
---|
| 1809 | },
|
---|
| 1810 | toAcres: function (m) {
|
---|
| 1811 | return m * 0.000247105;
|
---|
| 1812 | }
|
---|
| 1813 | };
|
---|
| 1814 |
|
---|
| 1815 | exports.degrees = {
|
---|
| 1816 | toRadians: function (d) {
|
---|
| 1817 | return d * Math.PI / 180;
|
---|
| 1818 | }
|
---|
| 1819 | };
|
---|
| 1820 | },{}],14:[function(require,module,exports){
|
---|
| 1821 | // Underscore.js 1.5.2
|
---|
| 1822 | // http://underscorejs.org
|
---|
| 1823 | // (c) 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
|
---|
| 1824 | // Underscore may be freely distributed under the MIT license.
|
---|
| 1825 |
|
---|
| 1826 | (function() {
|
---|
| 1827 |
|
---|
| 1828 | // Baseline setup
|
---|
| 1829 | // --------------
|
---|
| 1830 |
|
---|
| 1831 | // Establish the root object, `window` in the browser, or `exports` on the server.
|
---|
| 1832 | var root = this;
|
---|
| 1833 |
|
---|
| 1834 | // Save the previous value of the `_` variable.
|
---|
| 1835 | var previousUnderscore = root._;
|
---|
| 1836 |
|
---|
| 1837 | // Establish the object that gets returned to break out of a loop iteration.
|
---|
| 1838 | var breaker = {};
|
---|
| 1839 |
|
---|
| 1840 | // Save bytes in the minified (but not gzipped) version:
|
---|
| 1841 | var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;
|
---|
| 1842 |
|
---|
| 1843 | // Create quick reference variables for speed access to core prototypes.
|
---|
| 1844 | var
|
---|
| 1845 | push = ArrayProto.push,
|
---|
| 1846 | slice = ArrayProto.slice,
|
---|
| 1847 | concat = ArrayProto.concat,
|
---|
| 1848 | toString = ObjProto.toString,
|
---|
| 1849 | hasOwnProperty = ObjProto.hasOwnProperty;
|
---|
| 1850 |
|
---|
| 1851 | // All **ECMAScript 5** native function implementations that we hope to use
|
---|
| 1852 | // are declared here.
|
---|
| 1853 | var
|
---|
| 1854 | nativeForEach = ArrayProto.forEach,
|
---|
| 1855 | nativeMap = ArrayProto.map,
|
---|
| 1856 | nativeReduce = ArrayProto.reduce,
|
---|
| 1857 | nativeReduceRight = ArrayProto.reduceRight,
|
---|
| 1858 | nativeFilter = ArrayProto.filter,
|
---|
| 1859 | nativeEvery = ArrayProto.every,
|
---|
| 1860 | nativeSome = ArrayProto.some,
|
---|
| 1861 | nativeIndexOf = ArrayProto.indexOf,
|
---|
| 1862 | nativeLastIndexOf = ArrayProto.lastIndexOf,
|
---|
| 1863 | nativeIsArray = Array.isArray,
|
---|
| 1864 | nativeKeys = Object.keys,
|
---|
| 1865 | nativeBind = FuncProto.bind;
|
---|
| 1866 |
|
---|
| 1867 | // Create a safe reference to the Underscore object for use below.
|
---|
| 1868 | var _ = function(obj) {
|
---|
| 1869 | if (obj instanceof _) return obj;
|
---|
| 1870 | if (!(this instanceof _)) return new _(obj);
|
---|
| 1871 | this._wrapped = obj;
|
---|
| 1872 | };
|
---|
| 1873 |
|
---|
| 1874 | // Export the Underscore object for **Node.js**, with
|
---|
| 1875 | // backwards-compatibility for the old `require()` API. If we're in
|
---|
| 1876 | // the browser, add `_` as a global object via a string identifier,
|
---|
| 1877 | // for Closure Compiler "advanced" mode.
|
---|
| 1878 | if (typeof exports !== 'undefined') {
|
---|
| 1879 | if (typeof module !== 'undefined' && module.exports) {
|
---|
| 1880 | exports = module.exports = _;
|
---|
| 1881 | }
|
---|
| 1882 | exports._ = _;
|
---|
| 1883 | } else {
|
---|
| 1884 | root._ = _;
|
---|
| 1885 | }
|
---|
| 1886 |
|
---|
| 1887 | // Current version.
|
---|
| 1888 | _.VERSION = '1.5.2';
|
---|
| 1889 |
|
---|
| 1890 | // Collection Functions
|
---|
| 1891 | // --------------------
|
---|
| 1892 |
|
---|
| 1893 | // The cornerstone, an `each` implementation, aka `forEach`.
|
---|
| 1894 | // Handles objects with the built-in `forEach`, arrays, and raw objects.
|
---|
| 1895 | // Delegates to **ECMAScript 5**'s native `forEach` if available.
|
---|
| 1896 | var each = _.each = _.forEach = function(obj, iterator, context) {
|
---|
| 1897 | if (obj == null) return;
|
---|
| 1898 | if (nativeForEach && obj.forEach === nativeForEach) {
|
---|
| 1899 | obj.forEach(iterator, context);
|
---|
| 1900 | } else if (obj.length === +obj.length) {
|
---|
| 1901 | for (var i = 0, length = obj.length; i < length; i++) {
|
---|
| 1902 | if (iterator.call(context, obj[i], i, obj) === breaker) return;
|
---|
| 1903 | }
|
---|
| 1904 | } else {
|
---|
| 1905 | var keys = _.keys(obj);
|
---|
| 1906 | for (var i = 0, length = keys.length; i < length; i++) {
|
---|
| 1907 | if (iterator.call(context, obj[keys[i]], keys[i], obj) === breaker) return;
|
---|
| 1908 | }
|
---|
| 1909 | }
|
---|
| 1910 | };
|
---|
| 1911 |
|
---|
| 1912 | // Return the results of applying the iterator to each element.
|
---|
| 1913 | // Delegates to **ECMAScript 5**'s native `map` if available.
|
---|
| 1914 | _.map = _.collect = function(obj, iterator, context) {
|
---|
| 1915 | var results = [];
|
---|
| 1916 | if (obj == null) return results;
|
---|
| 1917 | if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
|
---|
| 1918 | each(obj, function(value, index, list) {
|
---|
| 1919 | results.push(iterator.call(context, value, index, list));
|
---|
| 1920 | });
|
---|
| 1921 | return results;
|
---|
| 1922 | };
|
---|
| 1923 |
|
---|
| 1924 | var reduceError = 'Reduce of empty array with no initial value';
|
---|
| 1925 |
|
---|
| 1926 | // **Reduce** builds up a single result from a list of values, aka `inject`,
|
---|
| 1927 | // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available.
|
---|
| 1928 | _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) {
|
---|
| 1929 | var initial = arguments.length > 2;
|
---|
| 1930 | if (obj == null) obj = [];
|
---|
| 1931 | if (nativeReduce && obj.reduce === nativeReduce) {
|
---|
| 1932 | if (context) iterator = _.bind(iterator, context);
|
---|
| 1933 | return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator);
|
---|
| 1934 | }
|
---|
| 1935 | each(obj, function(value, index, list) {
|
---|
| 1936 | if (!initial) {
|
---|
| 1937 | memo = value;
|
---|
| 1938 | initial = true;
|
---|
| 1939 | } else {
|
---|
| 1940 | memo = iterator.call(context, memo, value, index, list);
|
---|
| 1941 | }
|
---|
| 1942 | });
|
---|
| 1943 | if (!initial) throw new TypeError(reduceError);
|
---|
| 1944 | return memo;
|
---|
| 1945 | };
|
---|
| 1946 |
|
---|
| 1947 | // The right-associative version of reduce, also known as `foldr`.
|
---|
| 1948 | // Delegates to **ECMAScript 5**'s native `reduceRight` if available.
|
---|
| 1949 | _.reduceRight = _.foldr = function(obj, iterator, memo, context) {
|
---|
| 1950 | var initial = arguments.length > 2;
|
---|
| 1951 | if (obj == null) obj = [];
|
---|
| 1952 | if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {
|
---|
| 1953 | if (context) iterator = _.bind(iterator, context);
|
---|
| 1954 | return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);
|
---|
| 1955 | }
|
---|
| 1956 | var length = obj.length;
|
---|
| 1957 | if (length !== +length) {
|
---|
| 1958 | var keys = _.keys(obj);
|
---|
| 1959 | length = keys.length;
|
---|
| 1960 | }
|
---|
| 1961 | each(obj, function(value, index, list) {
|
---|
| 1962 | index = keys ? keys[--length] : --length;
|
---|
| 1963 | if (!initial) {
|
---|
| 1964 | memo = obj[index];
|
---|
| 1965 | initial = true;
|
---|
| 1966 | } else {
|
---|
| 1967 | memo = iterator.call(context, memo, obj[index], index, list);
|
---|
| 1968 | }
|
---|
| 1969 | });
|
---|
| 1970 | if (!initial) throw new TypeError(reduceError);
|
---|
| 1971 | return memo;
|
---|
| 1972 | };
|
---|
| 1973 |
|
---|
| 1974 | // Return the first value which passes a truth test. Aliased as `detect`.
|
---|
| 1975 | _.find = _.detect = function(obj, iterator, context) {
|
---|
| 1976 | var result;
|
---|
| 1977 | any(obj, function(value, index, list) {
|
---|
| 1978 | if (iterator.call(context, value, index, list)) {
|
---|
| 1979 | result = value;
|
---|
| 1980 | return true;
|
---|
| 1981 | }
|
---|
| 1982 | });
|
---|
| 1983 | return result;
|
---|
| 1984 | };
|
---|
| 1985 |
|
---|
| 1986 | // Return all the elements that pass a truth test.
|
---|
| 1987 | // Delegates to **ECMAScript 5**'s native `filter` if available.
|
---|
| 1988 | // Aliased as `select`.
|
---|
| 1989 | _.filter = _.select = function(obj, iterator, context) {
|
---|
| 1990 | var results = [];
|
---|
| 1991 | if (obj == null) return results;
|
---|
| 1992 | if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context);
|
---|
| 1993 | each(obj, function(value, index, list) {
|
---|
| 1994 | if (iterator.call(context, value, index, list)) results.push(value);
|
---|
| 1995 | });
|
---|
| 1996 | return results;
|
---|
| 1997 | };
|
---|
| 1998 |
|
---|
| 1999 | // Return all the elements for which a truth test fails.
|
---|
| 2000 | _.reject = function(obj, iterator, context) {
|
---|
| 2001 | return _.filter(obj, function(value, index, list) {
|
---|
| 2002 | return !iterator.call(context, value, index, list);
|
---|
| 2003 | }, context);
|
---|
| 2004 | };
|
---|
| 2005 |
|
---|
| 2006 | // Determine whether all of the elements match a truth test.
|
---|
| 2007 | // Delegates to **ECMAScript 5**'s native `every` if available.
|
---|
| 2008 | // Aliased as `all`.
|
---|
| 2009 | _.every = _.all = function(obj, iterator, context) {
|
---|
| 2010 | iterator || (iterator = _.identity);
|
---|
| 2011 | var result = true;
|
---|
| 2012 | if (obj == null) return result;
|
---|
| 2013 | if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context);
|
---|
| 2014 | each(obj, function(value, index, list) {
|
---|
| 2015 | if (!(result = result && iterator.call(context, value, index, list))) return breaker;
|
---|
| 2016 | });
|
---|
| 2017 | return !!result;
|
---|
| 2018 | };
|
---|
| 2019 |
|
---|
| 2020 | // Determine if at least one element in the object matches a truth test.
|
---|
| 2021 | // Delegates to **ECMAScript 5**'s native `some` if available.
|
---|
| 2022 | // Aliased as `any`.
|
---|
| 2023 | var any = _.some = _.any = function(obj, iterator, context) {
|
---|
| 2024 | iterator || (iterator = _.identity);
|
---|
| 2025 | var result = false;
|
---|
| 2026 | if (obj == null) return result;
|
---|
| 2027 | if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);
|
---|
| 2028 | each(obj, function(value, index, list) {
|
---|
| 2029 | if (result || (result = iterator.call(context, value, index, list))) return breaker;
|
---|
| 2030 | });
|
---|
| 2031 | return !!result;
|
---|
| 2032 | };
|
---|
| 2033 |
|
---|
| 2034 | // Determine if the array or object contains a given value (using `===`).
|
---|
| 2035 | // Aliased as `include`.
|
---|
| 2036 | _.contains = _.include = function(obj, target) {
|
---|
| 2037 | if (obj == null) return false;
|
---|
| 2038 | if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;
|
---|
| 2039 | return any(obj, function(value) {
|
---|
| 2040 | return value === target;
|
---|
| 2041 | });
|
---|
| 2042 | };
|
---|
| 2043 |
|
---|
| 2044 | // Invoke a method (with arguments) on every item in a collection.
|
---|
| 2045 | _.invoke = function(obj, method) {
|
---|
| 2046 | var args = slice.call(arguments, 2);
|
---|
| 2047 | var isFunc = _.isFunction(method);
|
---|
| 2048 | return _.map(obj, function(value) {
|
---|
| 2049 | return (isFunc ? method : value[method]).apply(value, args);
|
---|
| 2050 | });
|
---|
| 2051 | };
|
---|
| 2052 |
|
---|
| 2053 | // Convenience version of a common use case of `map`: fetching a property.
|
---|
| 2054 | _.pluck = function(obj, key) {
|
---|
| 2055 | return _.map(obj, function(value){ return value[key]; });
|
---|
| 2056 | };
|
---|
| 2057 |
|
---|
| 2058 | // Convenience version of a common use case of `filter`: selecting only objects
|
---|
| 2059 | // containing specific `key:value` pairs.
|
---|
| 2060 | _.where = function(obj, attrs, first) {
|
---|
| 2061 | if (_.isEmpty(attrs)) return first ? void 0 : [];
|
---|
| 2062 | return _[first ? 'find' : 'filter'](obj, function(value) {
|
---|
| 2063 | for (var key in attrs) {
|
---|
| 2064 | if (attrs[key] !== value[key]) return false;
|
---|
| 2065 | }
|
---|
| 2066 | return true;
|
---|
| 2067 | });
|
---|
| 2068 | };
|
---|
| 2069 |
|
---|
| 2070 | // Convenience version of a common use case of `find`: getting the first object
|
---|
| 2071 | // containing specific `key:value` pairs.
|
---|
| 2072 | _.findWhere = function(obj, attrs) {
|
---|
| 2073 | return _.where(obj, attrs, true);
|
---|
| 2074 | };
|
---|
| 2075 |
|
---|
| 2076 | // Return the maximum element or (element-based computation).
|
---|
| 2077 | // Can't optimize arrays of integers longer than 65,535 elements.
|
---|
| 2078 | // See [WebKit Bug 80797](https://bugs.webkit.org/show_bug.cgi?id=80797)
|
---|
| 2079 | _.max = function(obj, iterator, context) {
|
---|
| 2080 | if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
|
---|
| 2081 | return Math.max.apply(Math, obj);
|
---|
| 2082 | }
|
---|
| 2083 | if (!iterator && _.isEmpty(obj)) return -Infinity;
|
---|
| 2084 | var result = {computed : -Infinity, value: -Infinity};
|
---|
| 2085 | each(obj, function(value, index, list) {
|
---|
| 2086 | var computed = iterator ? iterator.call(context, value, index, list) : value;
|
---|
| 2087 | computed > result.computed && (result = {value : value, computed : computed});
|
---|
| 2088 | });
|
---|
| 2089 | return result.value;
|
---|
| 2090 | };
|
---|
| 2091 |
|
---|
| 2092 | // Return the minimum element (or element-based computation).
|
---|
| 2093 | _.min = function(obj, iterator, context) {
|
---|
| 2094 | if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
|
---|
| 2095 | return Math.min.apply(Math, obj);
|
---|
| 2096 | }
|
---|
| 2097 | if (!iterator && _.isEmpty(obj)) return Infinity;
|
---|
| 2098 | var result = {computed : Infinity, value: Infinity};
|
---|
| 2099 | each(obj, function(value, index, list) {
|
---|
| 2100 | var computed = iterator ? iterator.call(context, value, index, list) : value;
|
---|
| 2101 | computed < result.computed && (result = {value : value, computed : computed});
|
---|
| 2102 | });
|
---|
| 2103 | return result.value;
|
---|
| 2104 | };
|
---|
| 2105 |
|
---|
| 2106 | // Shuffle an array, using the modern version of the
|
---|
| 2107 | // [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle).
|
---|
| 2108 | _.shuffle = function(obj) {
|
---|
| 2109 | var rand;
|
---|
| 2110 | var index = 0;
|
---|
| 2111 | var shuffled = [];
|
---|
| 2112 | each(obj, function(value) {
|
---|
| 2113 | rand = _.random(index++);
|
---|
| 2114 | shuffled[index - 1] = shuffled[rand];
|
---|
| 2115 | shuffled[rand] = value;
|
---|
| 2116 | });
|
---|
| 2117 | return shuffled;
|
---|
| 2118 | };
|
---|
| 2119 |
|
---|
| 2120 | // Sample **n** random values from an array.
|
---|
| 2121 | // If **n** is not specified, returns a single random element from the array.
|
---|
| 2122 | // The internal `guard` argument allows it to work with `map`.
|
---|
| 2123 | _.sample = function(obj, n, guard) {
|
---|
| 2124 | if (arguments.length < 2 || guard) {
|
---|
| 2125 | return obj[_.random(obj.length - 1)];
|
---|
| 2126 | }
|
---|
| 2127 | return _.shuffle(obj).slice(0, Math.max(0, n));
|
---|
| 2128 | };
|
---|
| 2129 |
|
---|
| 2130 | // An internal function to generate lookup iterators.
|
---|
| 2131 | var lookupIterator = function(value) {
|
---|
| 2132 | return _.isFunction(value) ? value : function(obj){ return obj[value]; };
|
---|
| 2133 | };
|
---|
| 2134 |
|
---|
| 2135 | // Sort the object's values by a criterion produced by an iterator.
|
---|
| 2136 | _.sortBy = function(obj, value, context) {
|
---|
| 2137 | var iterator = lookupIterator(value);
|
---|
| 2138 | return _.pluck(_.map(obj, function(value, index, list) {
|
---|
| 2139 | return {
|
---|
| 2140 | value: value,
|
---|
| 2141 | index: index,
|
---|
| 2142 | criteria: iterator.call(context, value, index, list)
|
---|
| 2143 | };
|
---|
| 2144 | }).sort(function(left, right) {
|
---|
| 2145 | var a = left.criteria;
|
---|
| 2146 | var b = right.criteria;
|
---|
| 2147 | if (a !== b) {
|
---|
| 2148 | if (a > b || a === void 0) return 1;
|
---|
| 2149 | if (a < b || b === void 0) return -1;
|
---|
| 2150 | }
|
---|
| 2151 | return left.index - right.index;
|
---|
| 2152 | }), 'value');
|
---|
| 2153 | };
|
---|
| 2154 |
|
---|
| 2155 | // An internal function used for aggregate "group by" operations.
|
---|
| 2156 | var group = function(behavior) {
|
---|
| 2157 | return function(obj, value, context) {
|
---|
| 2158 | var result = {};
|
---|
| 2159 | var iterator = value == null ? _.identity : lookupIterator(value);
|
---|
| 2160 | each(obj, function(value, index) {
|
---|
| 2161 | var key = iterator.call(context, value, index, obj);
|
---|
| 2162 | behavior(result, key, value);
|
---|
| 2163 | });
|
---|
| 2164 | return result;
|
---|
| 2165 | };
|
---|
| 2166 | };
|
---|
| 2167 |
|
---|
| 2168 | // Groups the object's values by a criterion. Pass either a string attribute
|
---|
| 2169 | // to group by, or a function that returns the criterion.
|
---|
| 2170 | _.groupBy = group(function(result, key, value) {
|
---|
| 2171 | (_.has(result, key) ? result[key] : (result[key] = [])).push(value);
|
---|
| 2172 | });
|
---|
| 2173 |
|
---|
| 2174 | // Indexes the object's values by a criterion, similar to `groupBy`, but for
|
---|
| 2175 | // when you know that your index values will be unique.
|
---|
| 2176 | _.indexBy = group(function(result, key, value) {
|
---|
| 2177 | result[key] = value;
|
---|
| 2178 | });
|
---|
| 2179 |
|
---|
| 2180 | // Counts instances of an object that group by a certain criterion. Pass
|
---|
| 2181 | // either a string attribute to count by, or a function that returns the
|
---|
| 2182 | // criterion.
|
---|
| 2183 | _.countBy = group(function(result, key) {
|
---|
| 2184 | _.has(result, key) ? result[key]++ : result[key] = 1;
|
---|
| 2185 | });
|
---|
| 2186 |
|
---|
| 2187 | // Use a comparator function to figure out the smallest index at which
|
---|
| 2188 | // an object should be inserted so as to maintain order. Uses binary search.
|
---|
| 2189 | _.sortedIndex = function(array, obj, iterator, context) {
|
---|
| 2190 | iterator = iterator == null ? _.identity : lookupIterator(iterator);
|
---|
| 2191 | var value = iterator.call(context, obj);
|
---|
| 2192 | var low = 0, high = array.length;
|
---|
| 2193 | while (low < high) {
|
---|
| 2194 | var mid = (low + high) >>> 1;
|
---|
| 2195 | iterator.call(context, array[mid]) < value ? low = mid + 1 : high = mid;
|
---|
| 2196 | }
|
---|
| 2197 | return low;
|
---|
| 2198 | };
|
---|
| 2199 |
|
---|
| 2200 | // Safely create a real, live array from anything iterable.
|
---|
| 2201 | _.toArray = function(obj) {
|
---|
| 2202 | if (!obj) return [];
|
---|
| 2203 | if (_.isArray(obj)) return slice.call(obj);
|
---|
| 2204 | if (obj.length === +obj.length) return _.map(obj, _.identity);
|
---|
| 2205 | return _.values(obj);
|
---|
| 2206 | };
|
---|
| 2207 |
|
---|
| 2208 | // Return the number of elements in an object.
|
---|
| 2209 | _.size = function(obj) {
|
---|
| 2210 | if (obj == null) return 0;
|
---|
| 2211 | return (obj.length === +obj.length) ? obj.length : _.keys(obj).length;
|
---|
| 2212 | };
|
---|
| 2213 |
|
---|
| 2214 | // Array Functions
|
---|
| 2215 | // ---------------
|
---|
| 2216 |
|
---|
| 2217 | // Get the first element of an array. Passing **n** will return the first N
|
---|
| 2218 | // values in the array. Aliased as `head` and `take`. The **guard** check
|
---|
| 2219 | // allows it to work with `_.map`.
|
---|
| 2220 | _.first = _.head = _.take = function(array, n, guard) {
|
---|
| 2221 | if (array == null) return void 0;
|
---|
| 2222 | return (n == null) || guard ? array[0] : slice.call(array, 0, n);
|
---|
| 2223 | };
|
---|
| 2224 |
|
---|
| 2225 | // Returns everything but the last entry of the array. Especially useful on
|
---|
| 2226 | // the arguments object. Passing **n** will return all the values in
|
---|
| 2227 | // the array, excluding the last N. The **guard** check allows it to work with
|
---|
| 2228 | // `_.map`.
|
---|
| 2229 | _.initial = function(array, n, guard) {
|
---|
| 2230 | return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n));
|
---|
| 2231 | };
|
---|
| 2232 |
|
---|
| 2233 | // Get the last element of an array. Passing **n** will return the last N
|
---|
| 2234 | // values in the array. The **guard** check allows it to work with `_.map`.
|
---|
| 2235 | _.last = function(array, n, guard) {
|
---|
| 2236 | if (array == null) return void 0;
|
---|
| 2237 | if ((n == null) || guard) {
|
---|
| 2238 | return array[array.length - 1];
|
---|
| 2239 | } else {
|
---|
| 2240 | return slice.call(array, Math.max(array.length - n, 0));
|
---|
| 2241 | }
|
---|
| 2242 | };
|
---|
| 2243 |
|
---|
| 2244 | // Returns everything but the first entry of the array. Aliased as `tail` and `drop`.
|
---|
| 2245 | // Especially useful on the arguments object. Passing an **n** will return
|
---|
| 2246 | // the rest N values in the array. The **guard**
|
---|
| 2247 | // check allows it to work with `_.map`.
|
---|
| 2248 | _.rest = _.tail = _.drop = function(array, n, guard) {
|
---|
| 2249 | return slice.call(array, (n == null) || guard ? 1 : n);
|
---|
| 2250 | };
|
---|
| 2251 |
|
---|
| 2252 | // Trim out all falsy values from an array.
|
---|
| 2253 | _.compact = function(array) {
|
---|
| 2254 | return _.filter(array, _.identity);
|
---|
| 2255 | };
|
---|
| 2256 |
|
---|
| 2257 | // Internal implementation of a recursive `flatten` function.
|
---|
| 2258 | var flatten = function(input, shallow, output) {
|
---|
| 2259 | if (shallow && _.every(input, _.isArray)) {
|
---|
| 2260 | return concat.apply(output, input);
|
---|
| 2261 | }
|
---|
| 2262 | each(input, function(value) {
|
---|
| 2263 | if (_.isArray(value) || _.isArguments(value)) {
|
---|
| 2264 | shallow ? push.apply(output, value) : flatten(value, shallow, output);
|
---|
| 2265 | } else {
|
---|
| 2266 | output.push(value);
|
---|
| 2267 | }
|
---|
| 2268 | });
|
---|
| 2269 | return output;
|
---|
| 2270 | };
|
---|
| 2271 |
|
---|
| 2272 | // Flatten out an array, either recursively (by default), or just one level.
|
---|
| 2273 | _.flatten = function(array, shallow) {
|
---|
| 2274 | return flatten(array, shallow, []);
|
---|
| 2275 | };
|
---|
| 2276 |
|
---|
| 2277 | // Return a version of the array that does not contain the specified value(s).
|
---|
| 2278 | _.without = function(array) {
|
---|
| 2279 | return _.difference(array, slice.call(arguments, 1));
|
---|
| 2280 | };
|
---|
| 2281 |
|
---|
| 2282 | // Produce a duplicate-free version of the array. If the array has already
|
---|
| 2283 | // been sorted, you have the option of using a faster algorithm.
|
---|
| 2284 | // Aliased as `unique`.
|
---|
| 2285 | _.uniq = _.unique = function(array, isSorted, iterator, context) {
|
---|
| 2286 | if (_.isFunction(isSorted)) {
|
---|
| 2287 | context = iterator;
|
---|
| 2288 | iterator = isSorted;
|
---|
| 2289 | isSorted = false;
|
---|
| 2290 | }
|
---|
| 2291 | var initial = iterator ? _.map(array, iterator, context) : array;
|
---|
| 2292 | var results = [];
|
---|
| 2293 | var seen = [];
|
---|
| 2294 | each(initial, function(value, index) {
|
---|
| 2295 | if (isSorted ? (!index || seen[seen.length - 1] !== value) : !_.contains(seen, value)) {
|
---|
| 2296 | seen.push(value);
|
---|
| 2297 | results.push(array[index]);
|
---|
| 2298 | }
|
---|
| 2299 | });
|
---|
| 2300 | return results;
|
---|
| 2301 | };
|
---|
| 2302 |
|
---|
| 2303 | // Produce an array that contains the union: each distinct element from all of
|
---|
| 2304 | // the passed-in arrays.
|
---|
| 2305 | _.union = function() {
|
---|
| 2306 | return _.uniq(_.flatten(arguments, true));
|
---|
| 2307 | };
|
---|
| 2308 |
|
---|
| 2309 | // Produce an array that contains every item shared between all the
|
---|
| 2310 | // passed-in arrays.
|
---|
| 2311 | _.intersection = function(array) {
|
---|
| 2312 | var rest = slice.call(arguments, 1);
|
---|
| 2313 | return _.filter(_.uniq(array), function(item) {
|
---|
| 2314 | return _.every(rest, function(other) {
|
---|
| 2315 | return _.indexOf(other, item) >= 0;
|
---|
| 2316 | });
|
---|
| 2317 | });
|
---|
| 2318 | };
|
---|
| 2319 |
|
---|
| 2320 | // Take the difference between one array and a number of other arrays.
|
---|
| 2321 | // Only the elements present in just the first array will remain.
|
---|
| 2322 | _.difference = function(array) {
|
---|
| 2323 | var rest = concat.apply(ArrayProto, slice.call(arguments, 1));
|
---|
| 2324 | return _.filter(array, function(value){ return !_.contains(rest, value); });
|
---|
| 2325 | };
|
---|
| 2326 |
|
---|
| 2327 | // Zip together multiple lists into a single array -- elements that share
|
---|
| 2328 | // an index go together.
|
---|
| 2329 | _.zip = function() {
|
---|
| 2330 | var length = _.max(_.pluck(arguments, "length").concat(0));
|
---|
| 2331 | var results = new Array(length);
|
---|
| 2332 | for (var i = 0; i < length; i++) {
|
---|
| 2333 | results[i] = _.pluck(arguments, '' + i);
|
---|
| 2334 | }
|
---|
| 2335 | return results;
|
---|
| 2336 | };
|
---|
| 2337 |
|
---|
| 2338 | // Converts lists into objects. Pass either a single array of `[key, value]`
|
---|
| 2339 | // pairs, or two parallel arrays of the same length -- one of keys, and one of
|
---|
| 2340 | // the corresponding values.
|
---|
| 2341 | _.object = function(list, values) {
|
---|
| 2342 | if (list == null) return {};
|
---|
| 2343 | var result = {};
|
---|
| 2344 | for (var i = 0, length = list.length; i < length; i++) {
|
---|
| 2345 | if (values) {
|
---|
| 2346 | result[list[i]] = values[i];
|
---|
| 2347 | } else {
|
---|
| 2348 | result[list[i][0]] = list[i][1];
|
---|
| 2349 | }
|
---|
| 2350 | }
|
---|
| 2351 | return result;
|
---|
| 2352 | };
|
---|
| 2353 |
|
---|
| 2354 | // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**),
|
---|
| 2355 | // we need this function. Return the position of the first occurrence of an
|
---|
| 2356 | // item in an array, or -1 if the item is not included in the array.
|
---|
| 2357 | // Delegates to **ECMAScript 5**'s native `indexOf` if available.
|
---|
| 2358 | // If the array is large and already in sort order, pass `true`
|
---|
| 2359 | // for **isSorted** to use binary search.
|
---|
| 2360 | _.indexOf = function(array, item, isSorted) {
|
---|
| 2361 | if (array == null) return -1;
|
---|
| 2362 | var i = 0, length = array.length;
|
---|
| 2363 | if (isSorted) {
|
---|
| 2364 | if (typeof isSorted == 'number') {
|
---|
| 2365 | i = (isSorted < 0 ? Math.max(0, length + isSorted) : isSorted);
|
---|
| 2366 | } else {
|
---|
| 2367 | i = _.sortedIndex(array, item);
|
---|
| 2368 | return array[i] === item ? i : -1;
|
---|
| 2369 | }
|
---|
| 2370 | }
|
---|
| 2371 | if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item, isSorted);
|
---|
| 2372 | for (; i < length; i++) if (array[i] === item) return i;
|
---|
| 2373 | return -1;
|
---|
| 2374 | };
|
---|
| 2375 |
|
---|
| 2376 | // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.
|
---|
| 2377 | _.lastIndexOf = function(array, item, from) {
|
---|
| 2378 | if (array == null) return -1;
|
---|
| 2379 | var hasIndex = from != null;
|
---|
| 2380 | if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) {
|
---|
| 2381 | return hasIndex ? array.lastIndexOf(item, from) : array.lastIndexOf(item);
|
---|
| 2382 | }
|
---|
| 2383 | var i = (hasIndex ? from : array.length);
|
---|
| 2384 | while (i--) if (array[i] === item) return i;
|
---|
| 2385 | return -1;
|
---|
| 2386 | };
|
---|
| 2387 |
|
---|
| 2388 | // Generate an integer Array containing an arithmetic progression. A port of
|
---|
| 2389 | // the native Python `range()` function. See
|
---|
| 2390 | // [the Python documentation](http://docs.python.org/library/functions.html#range).
|
---|
| 2391 | _.range = function(start, stop, step) {
|
---|
| 2392 | if (arguments.length <= 1) {
|
---|
| 2393 | stop = start || 0;
|
---|
| 2394 | start = 0;
|
---|
| 2395 | }
|
---|
| 2396 | step = arguments[2] || 1;
|
---|
| 2397 |
|
---|
| 2398 | var length = Math.max(Math.ceil((stop - start) / step), 0);
|
---|
| 2399 | var idx = 0;
|
---|
| 2400 | var range = new Array(length);
|
---|
| 2401 |
|
---|
| 2402 | while(idx < length) {
|
---|
| 2403 | range[idx++] = start;
|
---|
| 2404 | start += step;
|
---|
| 2405 | }
|
---|
| 2406 |
|
---|
| 2407 | return range;
|
---|
| 2408 | };
|
---|
| 2409 |
|
---|
| 2410 | // Function (ahem) Functions
|
---|
| 2411 | // ------------------
|
---|
| 2412 |
|
---|
| 2413 | // Reusable constructor function for prototype setting.
|
---|
| 2414 | var ctor = function(){};
|
---|
| 2415 |
|
---|
| 2416 | // Create a function bound to a given object (assigning `this`, and arguments,
|
---|
| 2417 | // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if
|
---|
| 2418 | // available.
|
---|
| 2419 | _.bind = function(func, context) {
|
---|
| 2420 | var args, bound;
|
---|
| 2421 | if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
|
---|
| 2422 | if (!_.isFunction(func)) throw new TypeError;
|
---|
| 2423 | args = slice.call(arguments, 2);
|
---|
| 2424 | return bound = function() {
|
---|
| 2425 | if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments)));
|
---|
| 2426 | ctor.prototype = func.prototype;
|
---|
| 2427 | var self = new ctor;
|
---|
| 2428 | ctor.prototype = null;
|
---|
| 2429 | var result = func.apply(self, args.concat(slice.call(arguments)));
|
---|
| 2430 | if (Object(result) === result) return result;
|
---|
| 2431 | return self;
|
---|
| 2432 | };
|
---|
| 2433 | };
|
---|
| 2434 |
|
---|
| 2435 | // Partially apply a function by creating a version that has had some of its
|
---|
| 2436 | // arguments pre-filled, without changing its dynamic `this` context.
|
---|
| 2437 | _.partial = function(func) {
|
---|
| 2438 | var args = slice.call(arguments, 1);
|
---|
| 2439 | return function() {
|
---|
| 2440 | return func.apply(this, args.concat(slice.call(arguments)));
|
---|
| 2441 | };
|
---|
| 2442 | };
|
---|
| 2443 |
|
---|
| 2444 | // Bind all of an object's methods to that object. Useful for ensuring that
|
---|
| 2445 | // all callbacks defined on an object belong to it.
|
---|
| 2446 | _.bindAll = function(obj) {
|
---|
| 2447 | var funcs = slice.call(arguments, 1);
|
---|
| 2448 | if (funcs.length === 0) throw new Error("bindAll must be passed function names");
|
---|
| 2449 | each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); });
|
---|
| 2450 | return obj;
|
---|
| 2451 | };
|
---|
| 2452 |
|
---|
| 2453 | // Memoize an expensive function by storing its results.
|
---|
| 2454 | _.memoize = function(func, hasher) {
|
---|
| 2455 | var memo = {};
|
---|
| 2456 | hasher || (hasher = _.identity);
|
---|
| 2457 | return function() {
|
---|
| 2458 | var key = hasher.apply(this, arguments);
|
---|
| 2459 | return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments));
|
---|
| 2460 | };
|
---|
| 2461 | };
|
---|
| 2462 |
|
---|
| 2463 | // Delays a function for the given number of milliseconds, and then calls
|
---|
| 2464 | // it with the arguments supplied.
|
---|
| 2465 | _.delay = function(func, wait) {
|
---|
| 2466 | var args = slice.call(arguments, 2);
|
---|
| 2467 | return setTimeout(function(){ return func.apply(null, args); }, wait);
|
---|
| 2468 | };
|
---|
| 2469 |
|
---|
| 2470 | // Defers a function, scheduling it to run after the current call stack has
|
---|
| 2471 | // cleared.
|
---|
| 2472 | _.defer = function(func) {
|
---|
| 2473 | return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1)));
|
---|
| 2474 | };
|
---|
| 2475 |
|
---|
| 2476 | // Returns a function, that, when invoked, will only be triggered at most once
|
---|
| 2477 | // during a given window of time. Normally, the throttled function will run
|
---|
| 2478 | // as much as it can, without ever going more than once per `wait` duration;
|
---|
| 2479 | // but if you'd like to disable the execution on the leading edge, pass
|
---|
| 2480 | // `{leading: false}`. To disable execution on the trailing edge, ditto.
|
---|
| 2481 | _.throttle = function(func, wait, options) {
|
---|
| 2482 | var context, args, result;
|
---|
| 2483 | var timeout = null;
|
---|
| 2484 | var previous = 0;
|
---|
| 2485 | options || (options = {});
|
---|
| 2486 | var later = function() {
|
---|
| 2487 | previous = options.leading === false ? 0 : new Date;
|
---|
| 2488 | timeout = null;
|
---|
| 2489 | result = func.apply(context, args);
|
---|
| 2490 | };
|
---|
| 2491 | return function() {
|
---|
| 2492 | var now = new Date;
|
---|
| 2493 | if (!previous && options.leading === false) previous = now;
|
---|
| 2494 | var remaining = wait - (now - previous);
|
---|
| 2495 | context = this;
|
---|
| 2496 | args = arguments;
|
---|
| 2497 | if (remaining <= 0) {
|
---|
| 2498 | clearTimeout(timeout);
|
---|
| 2499 | timeout = null;
|
---|
| 2500 | previous = now;
|
---|
| 2501 | result = func.apply(context, args);
|
---|
| 2502 | } else if (!timeout && options.trailing !== false) {
|
---|
| 2503 | timeout = setTimeout(later, remaining);
|
---|
| 2504 | }
|
---|
| 2505 | return result;
|
---|
| 2506 | };
|
---|
| 2507 | };
|
---|
| 2508 |
|
---|
| 2509 | // Returns a function, that, as long as it continues to be invoked, will not
|
---|
| 2510 | // be triggered. The function will be called after it stops being called for
|
---|
| 2511 | // N milliseconds. If `immediate` is passed, trigger the function on the
|
---|
| 2512 | // leading edge, instead of the trailing.
|
---|
| 2513 | _.debounce = function(func, wait, immediate) {
|
---|
| 2514 | var timeout, args, context, timestamp, result;
|
---|
| 2515 | return function() {
|
---|
| 2516 | context = this;
|
---|
| 2517 | args = arguments;
|
---|
| 2518 | timestamp = new Date();
|
---|
| 2519 | var later = function() {
|
---|
| 2520 | var last = (new Date()) - timestamp;
|
---|
| 2521 | if (last < wait) {
|
---|
| 2522 | timeout = setTimeout(later, wait - last);
|
---|
| 2523 | } else {
|
---|
| 2524 | timeout = null;
|
---|
| 2525 | if (!immediate) result = func.apply(context, args);
|
---|
| 2526 | }
|
---|
| 2527 | };
|
---|
| 2528 | var callNow = immediate && !timeout;
|
---|
| 2529 | if (!timeout) {
|
---|
| 2530 | timeout = setTimeout(later, wait);
|
---|
| 2531 | }
|
---|
| 2532 | if (callNow) result = func.apply(context, args);
|
---|
| 2533 | return result;
|
---|
| 2534 | };
|
---|
| 2535 | };
|
---|
| 2536 |
|
---|
| 2537 | // Returns a function that will be executed at most one time, no matter how
|
---|
| 2538 | // often you call it. Useful for lazy initialization.
|
---|
| 2539 | _.once = function(func) {
|
---|
| 2540 | var ran = false, memo;
|
---|
| 2541 | return function() {
|
---|
| 2542 | if (ran) return memo;
|
---|
| 2543 | ran = true;
|
---|
| 2544 | memo = func.apply(this, arguments);
|
---|
| 2545 | func = null;
|
---|
| 2546 | return memo;
|
---|
| 2547 | };
|
---|
| 2548 | };
|
---|
| 2549 |
|
---|
| 2550 | // Returns the first function passed as an argument to the second,
|
---|
| 2551 | // allowing you to adjust arguments, run code before and after, and
|
---|
| 2552 | // conditionally execute the original function.
|
---|
| 2553 | _.wrap = function(func, wrapper) {
|
---|
| 2554 | return function() {
|
---|
| 2555 | var args = [func];
|
---|
| 2556 | push.apply(args, arguments);
|
---|
| 2557 | return wrapper.apply(this, args);
|
---|
| 2558 | };
|
---|
| 2559 | };
|
---|
| 2560 |
|
---|
| 2561 | // Returns a function that is the composition of a list of functions, each
|
---|
| 2562 | // consuming the return value of the function that follows.
|
---|
| 2563 | _.compose = function() {
|
---|
| 2564 | var funcs = arguments;
|
---|
| 2565 | return function() {
|
---|
| 2566 | var args = arguments;
|
---|
| 2567 | for (var i = funcs.length - 1; i >= 0; i--) {
|
---|
| 2568 | args = [funcs[i].apply(this, args)];
|
---|
| 2569 | }
|
---|
| 2570 | return args[0];
|
---|
| 2571 | };
|
---|
| 2572 | };
|
---|
| 2573 |
|
---|
| 2574 | // Returns a function that will only be executed after being called N times.
|
---|
| 2575 | _.after = function(times, func) {
|
---|
| 2576 | return function() {
|
---|
| 2577 | if (--times < 1) {
|
---|
| 2578 | return func.apply(this, arguments);
|
---|
| 2579 | }
|
---|
| 2580 | };
|
---|
| 2581 | };
|
---|
| 2582 |
|
---|
| 2583 | // Object Functions
|
---|
| 2584 | // ----------------
|
---|
| 2585 |
|
---|
| 2586 | // Retrieve the names of an object's properties.
|
---|
| 2587 | // Delegates to **ECMAScript 5**'s native `Object.keys`
|
---|
| 2588 | _.keys = nativeKeys || function(obj) {
|
---|
| 2589 | if (obj !== Object(obj)) throw new TypeError('Invalid object');
|
---|
| 2590 | var keys = [];
|
---|
| 2591 | for (var key in obj) if (_.has(obj, key)) keys.push(key);
|
---|
| 2592 | return keys;
|
---|
| 2593 | };
|
---|
| 2594 |
|
---|
| 2595 | // Retrieve the values of an object's properties.
|
---|
| 2596 | _.values = function(obj) {
|
---|
| 2597 | var keys = _.keys(obj);
|
---|
| 2598 | var length = keys.length;
|
---|
| 2599 | var values = new Array(length);
|
---|
| 2600 | for (var i = 0; i < length; i++) {
|
---|
| 2601 | values[i] = obj[keys[i]];
|
---|
| 2602 | }
|
---|
| 2603 | return values;
|
---|
| 2604 | };
|
---|
| 2605 |
|
---|
| 2606 | // Convert an object into a list of `[key, value]` pairs.
|
---|
| 2607 | _.pairs = function(obj) {
|
---|
| 2608 | var keys = _.keys(obj);
|
---|
| 2609 | var length = keys.length;
|
---|
| 2610 | var pairs = new Array(length);
|
---|
| 2611 | for (var i = 0; i < length; i++) {
|
---|
| 2612 | pairs[i] = [keys[i], obj[keys[i]]];
|
---|
| 2613 | }
|
---|
| 2614 | return pairs;
|
---|
| 2615 | };
|
---|
| 2616 |
|
---|
| 2617 | // Invert the keys and values of an object. The values must be serializable.
|
---|
| 2618 | _.invert = function(obj) {
|
---|
| 2619 | var result = {};
|
---|
| 2620 | var keys = _.keys(obj);
|
---|
| 2621 | for (var i = 0, length = keys.length; i < length; i++) {
|
---|
| 2622 | result[obj[keys[i]]] = keys[i];
|
---|
| 2623 | }
|
---|
| 2624 | return result;
|
---|
| 2625 | };
|
---|
| 2626 |
|
---|
| 2627 | // Return a sorted list of the function names available on the object.
|
---|
| 2628 | // Aliased as `methods`
|
---|
| 2629 | _.functions = _.methods = function(obj) {
|
---|
| 2630 | var names = [];
|
---|
| 2631 | for (var key in obj) {
|
---|
| 2632 | if (_.isFunction(obj[key])) names.push(key);
|
---|
| 2633 | }
|
---|
| 2634 | return names.sort();
|
---|
| 2635 | };
|
---|
| 2636 |
|
---|
| 2637 | // Extend a given object with all the properties in passed-in object(s).
|
---|
| 2638 | _.extend = function(obj) {
|
---|
| 2639 | each(slice.call(arguments, 1), function(source) {
|
---|
| 2640 | if (source) {
|
---|
| 2641 | for (var prop in source) {
|
---|
| 2642 | obj[prop] = source[prop];
|
---|
| 2643 | }
|
---|
| 2644 | }
|
---|
| 2645 | });
|
---|
| 2646 | return obj;
|
---|
| 2647 | };
|
---|
| 2648 |
|
---|
| 2649 | // Return a copy of the object only containing the whitelisted properties.
|
---|
| 2650 | _.pick = function(obj) {
|
---|
| 2651 | var copy = {};
|
---|
| 2652 | var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
|
---|
| 2653 | each(keys, function(key) {
|
---|
| 2654 | if (key in obj) copy[key] = obj[key];
|
---|
| 2655 | });
|
---|
| 2656 | return copy;
|
---|
| 2657 | };
|
---|
| 2658 |
|
---|
| 2659 | // Return a copy of the object without the blacklisted properties.
|
---|
| 2660 | _.omit = function(obj) {
|
---|
| 2661 | var copy = {};
|
---|
| 2662 | var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
|
---|
| 2663 | for (var key in obj) {
|
---|
| 2664 | if (!_.contains(keys, key)) copy[key] = obj[key];
|
---|
| 2665 | }
|
---|
| 2666 | return copy;
|
---|
| 2667 | };
|
---|
| 2668 |
|
---|
| 2669 | // Fill in a given object with default properties.
|
---|
| 2670 | _.defaults = function(obj) {
|
---|
| 2671 | each(slice.call(arguments, 1), function(source) {
|
---|
| 2672 | if (source) {
|
---|
| 2673 | for (var prop in source) {
|
---|
| 2674 | if (obj[prop] === void 0) obj[prop] = source[prop];
|
---|
| 2675 | }
|
---|
| 2676 | }
|
---|
| 2677 | });
|
---|
| 2678 | return obj;
|
---|
| 2679 | };
|
---|
| 2680 |
|
---|
| 2681 | // Create a (shallow-cloned) duplicate of an object.
|
---|
| 2682 | _.clone = function(obj) {
|
---|
| 2683 | if (!_.isObject(obj)) return obj;
|
---|
| 2684 | return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
|
---|
| 2685 | };
|
---|
| 2686 |
|
---|
| 2687 | // Invokes interceptor with the obj, and then returns obj.
|
---|
| 2688 | // The primary purpose of this method is to "tap into" a method chain, in
|
---|
| 2689 | // order to perform operations on intermediate results within the chain.
|
---|
| 2690 | _.tap = function(obj, interceptor) {
|
---|
| 2691 | interceptor(obj);
|
---|
| 2692 | return obj;
|
---|
| 2693 | };
|
---|
| 2694 |
|
---|
| 2695 | // Internal recursive comparison function for `isEqual`.
|
---|
| 2696 | var eq = function(a, b, aStack, bStack) {
|
---|
| 2697 | // Identical objects are equal. `0 === -0`, but they aren't identical.
|
---|
| 2698 | // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).
|
---|
| 2699 | if (a === b) return a !== 0 || 1 / a == 1 / b;
|
---|
| 2700 | // A strict comparison is necessary because `null == undefined`.
|
---|
| 2701 | if (a == null || b == null) return a === b;
|
---|
| 2702 | // Unwrap any wrapped objects.
|
---|
| 2703 | if (a instanceof _) a = a._wrapped;
|
---|
| 2704 | if (b instanceof _) b = b._wrapped;
|
---|
| 2705 | // Compare `[[Class]]` names.
|
---|
| 2706 | var className = toString.call(a);
|
---|
| 2707 | if (className != toString.call(b)) return false;
|
---|
| 2708 | switch (className) {
|
---|
| 2709 | // Strings, numbers, dates, and booleans are compared by value.
|
---|
| 2710 | case '[object String]':
|
---|
| 2711 | // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
|
---|
| 2712 | // equivalent to `new String("5")`.
|
---|
| 2713 | return a == String(b);
|
---|
| 2714 | case '[object Number]':
|
---|
| 2715 | // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for
|
---|
| 2716 | // other numeric values.
|
---|
| 2717 | return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b);
|
---|
| 2718 | case '[object Date]':
|
---|
| 2719 | case '[object Boolean]':
|
---|
| 2720 | // Coerce dates and booleans to numeric primitive values. Dates are compared by their
|
---|
| 2721 | // millisecond representations. Note that invalid dates with millisecond representations
|
---|
| 2722 | // of `NaN` are not equivalent.
|
---|
| 2723 | return +a == +b;
|
---|
| 2724 | // RegExps are compared by their source patterns and flags.
|
---|
| 2725 | case '[object RegExp]':
|
---|
| 2726 | return a.source == b.source &&
|
---|
| 2727 | a.global == b.global &&
|
---|
| 2728 | a.multiline == b.multiline &&
|
---|
| 2729 | a.ignoreCase == b.ignoreCase;
|
---|
| 2730 | }
|
---|
| 2731 | if (typeof a != 'object' || typeof b != 'object') return false;
|
---|
| 2732 | // Assume equality for cyclic structures. The algorithm for detecting cyclic
|
---|
| 2733 | // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
|
---|
| 2734 | var length = aStack.length;
|
---|
| 2735 | while (length--) {
|
---|
| 2736 | // Linear search. Performance is inversely proportional to the number of
|
---|
| 2737 | // unique nested structures.
|
---|
| 2738 | if (aStack[length] == a) return bStack[length] == b;
|
---|
| 2739 | }
|
---|
| 2740 | // Objects with different constructors are not equivalent, but `Object`s
|
---|
| 2741 | // from different frames are.
|
---|
| 2742 | var aCtor = a.constructor, bCtor = b.constructor;
|
---|
| 2743 | if (aCtor !== bCtor && !(_.isFunction(aCtor) && (aCtor instanceof aCtor) &&
|
---|
| 2744 | _.isFunction(bCtor) && (bCtor instanceof bCtor))) {
|
---|
| 2745 | return false;
|
---|
| 2746 | }
|
---|
| 2747 | // Add the first object to the stack of traversed objects.
|
---|
| 2748 | aStack.push(a);
|
---|
| 2749 | bStack.push(b);
|
---|
| 2750 | var size = 0, result = true;
|
---|
| 2751 | // Recursively compare objects and arrays.
|
---|
| 2752 | if (className == '[object Array]') {
|
---|
| 2753 | // Compare array lengths to determine if a deep comparison is necessary.
|
---|
| 2754 | size = a.length;
|
---|
| 2755 | result = size == b.length;
|
---|
| 2756 | if (result) {
|
---|
| 2757 | // Deep compare the contents, ignoring non-numeric properties.
|
---|
| 2758 | while (size--) {
|
---|
| 2759 | if (!(result = eq(a[size], b[size], aStack, bStack))) break;
|
---|
| 2760 | }
|
---|
| 2761 | }
|
---|
| 2762 | } else {
|
---|
| 2763 | // Deep compare objects.
|
---|
| 2764 | for (var key in a) {
|
---|
| 2765 | if (_.has(a, key)) {
|
---|
| 2766 | // Count the expected number of properties.
|
---|
| 2767 | size++;
|
---|
| 2768 | // Deep compare each member.
|
---|
| 2769 | if (!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))) break;
|
---|
| 2770 | }
|
---|
| 2771 | }
|
---|
| 2772 | // Ensure that both objects contain the same number of properties.
|
---|
| 2773 | if (result) {
|
---|
| 2774 | for (key in b) {
|
---|
| 2775 | if (_.has(b, key) && !(size--)) break;
|
---|
| 2776 | }
|
---|
| 2777 | result = !size;
|
---|
| 2778 | }
|
---|
| 2779 | }
|
---|
| 2780 | // Remove the first object from the stack of traversed objects.
|
---|
| 2781 | aStack.pop();
|
---|
| 2782 | bStack.pop();
|
---|
| 2783 | return result;
|
---|
| 2784 | };
|
---|
| 2785 |
|
---|
| 2786 | // Perform a deep comparison to check if two objects are equal.
|
---|
| 2787 | _.isEqual = function(a, b) {
|
---|
| 2788 | return eq(a, b, [], []);
|
---|
| 2789 | };
|
---|
| 2790 |
|
---|
| 2791 | // Is a given array, string, or object empty?
|
---|
| 2792 | // An "empty" object has no enumerable own-properties.
|
---|
| 2793 | _.isEmpty = function(obj) {
|
---|
| 2794 | if (obj == null) return true;
|
---|
| 2795 | if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;
|
---|
| 2796 | for (var key in obj) if (_.has(obj, key)) return false;
|
---|
| 2797 | return true;
|
---|
| 2798 | };
|
---|
| 2799 |
|
---|
| 2800 | // Is a given value a DOM element?
|
---|
| 2801 | _.isElement = function(obj) {
|
---|
| 2802 | return !!(obj && obj.nodeType === 1);
|
---|
| 2803 | };
|
---|
| 2804 |
|
---|
| 2805 | // Is a given value an array?
|
---|
| 2806 | // Delegates to ECMA5's native Array.isArray
|
---|
| 2807 | _.isArray = nativeIsArray || function(obj) {
|
---|
| 2808 | return toString.call(obj) == '[object Array]';
|
---|
| 2809 | };
|
---|
| 2810 |
|
---|
| 2811 | // Is a given variable an object?
|
---|
| 2812 | _.isObject = function(obj) {
|
---|
| 2813 | return obj === Object(obj);
|
---|
| 2814 | };
|
---|
| 2815 |
|
---|
| 2816 | // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp.
|
---|
| 2817 | each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) {
|
---|
| 2818 | _['is' + name] = function(obj) {
|
---|
| 2819 | return toString.call(obj) == '[object ' + name + ']';
|
---|
| 2820 | };
|
---|
| 2821 | });
|
---|
| 2822 |
|
---|
| 2823 | // Define a fallback version of the method in browsers (ahem, IE), where
|
---|
| 2824 | // there isn't any inspectable "Arguments" type.
|
---|
| 2825 | if (!_.isArguments(arguments)) {
|
---|
| 2826 | _.isArguments = function(obj) {
|
---|
| 2827 | return !!(obj && _.has(obj, 'callee'));
|
---|
| 2828 | };
|
---|
| 2829 | }
|
---|
| 2830 |
|
---|
| 2831 | // Optimize `isFunction` if appropriate.
|
---|
| 2832 | if (typeof (/./) !== 'function') {
|
---|
| 2833 | _.isFunction = function(obj) {
|
---|
| 2834 | return typeof obj === 'function';
|
---|
| 2835 | };
|
---|
| 2836 | }
|
---|
| 2837 |
|
---|
| 2838 | // Is a given object a finite number?
|
---|
| 2839 | _.isFinite = function(obj) {
|
---|
| 2840 | return isFinite(obj) && !isNaN(parseFloat(obj));
|
---|
| 2841 | };
|
---|
| 2842 |
|
---|
| 2843 | // Is the given value `NaN`? (NaN is the only number which does not equal itself).
|
---|
| 2844 | _.isNaN = function(obj) {
|
---|
| 2845 | return _.isNumber(obj) && obj != +obj;
|
---|
| 2846 | };
|
---|
| 2847 |
|
---|
| 2848 | // Is a given value a boolean?
|
---|
| 2849 | _.isBoolean = function(obj) {
|
---|
| 2850 | return obj === true || obj === false || toString.call(obj) == '[object Boolean]';
|
---|
| 2851 | };
|
---|
| 2852 |
|
---|
| 2853 | // Is a given value equal to null?
|
---|
| 2854 | _.isNull = function(obj) {
|
---|
| 2855 | return obj === null;
|
---|
| 2856 | };
|
---|
| 2857 |
|
---|
| 2858 | // Is a given variable undefined?
|
---|
| 2859 | _.isUndefined = function(obj) {
|
---|
| 2860 | return obj === void 0;
|
---|
| 2861 | };
|
---|
| 2862 |
|
---|
| 2863 | // Shortcut function for checking if an object has a given property directly
|
---|
| 2864 | // on itself (in other words, not on a prototype).
|
---|
| 2865 | _.has = function(obj, key) {
|
---|
| 2866 | return hasOwnProperty.call(obj, key);
|
---|
| 2867 | };
|
---|
| 2868 |
|
---|
| 2869 | // Utility Functions
|
---|
| 2870 | // -----------------
|
---|
| 2871 |
|
---|
| 2872 | // Run Underscore.js in *noConflict* mode, returning the `_` variable to its
|
---|
| 2873 | // previous owner. Returns a reference to the Underscore object.
|
---|
| 2874 | _.noConflict = function() {
|
---|
| 2875 | root._ = previousUnderscore;
|
---|
| 2876 | return this;
|
---|
| 2877 | };
|
---|
| 2878 |
|
---|
| 2879 | // Keep the identity function around for default iterators.
|
---|
| 2880 | _.identity = function(value) {
|
---|
| 2881 | return value;
|
---|
| 2882 | };
|
---|
| 2883 |
|
---|
| 2884 | // Run a function **n** times.
|
---|
| 2885 | _.times = function(n, iterator, context) {
|
---|
| 2886 | var accum = Array(Math.max(0, n));
|
---|
| 2887 | for (var i = 0; i < n; i++) accum[i] = iterator.call(context, i);
|
---|
| 2888 | return accum;
|
---|
| 2889 | };
|
---|
| 2890 |
|
---|
| 2891 | // Return a random integer between min and max (inclusive).
|
---|
| 2892 | _.random = function(min, max) {
|
---|
| 2893 | if (max == null) {
|
---|
| 2894 | max = min;
|
---|
| 2895 | min = 0;
|
---|
| 2896 | }
|
---|
| 2897 | return min + Math.floor(Math.random() * (max - min + 1));
|
---|
| 2898 | };
|
---|
| 2899 |
|
---|
| 2900 | // List of HTML entities for escaping.
|
---|
| 2901 | var entityMap = {
|
---|
| 2902 | escape: {
|
---|
| 2903 | '&': '&',
|
---|
| 2904 | '<': '<',
|
---|
| 2905 | '>': '>',
|
---|
| 2906 | '"': '"',
|
---|
| 2907 | "'": '''
|
---|
| 2908 | }
|
---|
| 2909 | };
|
---|
| 2910 | entityMap.unescape = _.invert(entityMap.escape);
|
---|
| 2911 |
|
---|
| 2912 | // Regexes containing the keys and values listed immediately above.
|
---|
| 2913 | var entityRegexes = {
|
---|
| 2914 | escape: new RegExp('[' + _.keys(entityMap.escape).join('') + ']', 'g'),
|
---|
| 2915 | unescape: new RegExp('(' + _.keys(entityMap.unescape).join('|') + ')', 'g')
|
---|
| 2916 | };
|
---|
| 2917 |
|
---|
| 2918 | // Functions for escaping and unescaping strings to/from HTML interpolation.
|
---|
| 2919 | _.each(['escape', 'unescape'], function(method) {
|
---|
| 2920 | _[method] = function(string) {
|
---|
| 2921 | if (string == null) return '';
|
---|
| 2922 | return ('' + string).replace(entityRegexes[method], function(match) {
|
---|
| 2923 | return entityMap[method][match];
|
---|
| 2924 | });
|
---|
| 2925 | };
|
---|
| 2926 | });
|
---|
| 2927 |
|
---|
| 2928 | // If the value of the named `property` is a function then invoke it with the
|
---|
| 2929 | // `object` as context; otherwise, return it.
|
---|
| 2930 | _.result = function(object, property) {
|
---|
| 2931 | if (object == null) return void 0;
|
---|
| 2932 | var value = object[property];
|
---|
| 2933 | return _.isFunction(value) ? value.call(object) : value;
|
---|
| 2934 | };
|
---|
| 2935 |
|
---|
| 2936 | // Add your own custom functions to the Underscore object.
|
---|
| 2937 | _.mixin = function(obj) {
|
---|
| 2938 | each(_.functions(obj), function(name) {
|
---|
| 2939 | var func = _[name] = obj[name];
|
---|
| 2940 | _.prototype[name] = function() {
|
---|
| 2941 | var args = [this._wrapped];
|
---|
| 2942 | push.apply(args, arguments);
|
---|
| 2943 | return result.call(this, func.apply(_, args));
|
---|
| 2944 | };
|
---|
| 2945 | });
|
---|
| 2946 | };
|
---|
| 2947 |
|
---|
| 2948 | // Generate a unique integer id (unique within the entire client session).
|
---|
| 2949 | // Useful for temporary DOM ids.
|
---|
| 2950 | var idCounter = 0;
|
---|
| 2951 | _.uniqueId = function(prefix) {
|
---|
| 2952 | var id = ++idCounter + '';
|
---|
| 2953 | return prefix ? prefix + id : id;
|
---|
| 2954 | };
|
---|
| 2955 |
|
---|
| 2956 | // By default, Underscore uses ERB-style template delimiters, change the
|
---|
| 2957 | // following template settings to use alternative delimiters.
|
---|
| 2958 | _.templateSettings = {
|
---|
| 2959 | evaluate : /<%([\s\S]+?)%>/g,
|
---|
| 2960 | interpolate : /<%=([\s\S]+?)%>/g,
|
---|
| 2961 | escape : /<%-([\s\S]+?)%>/g
|
---|
| 2962 | };
|
---|
| 2963 |
|
---|
| 2964 | // When customizing `templateSettings`, if you don't want to define an
|
---|
| 2965 | // interpolation, evaluation or escaping regex, we need one that is
|
---|
| 2966 | // guaranteed not to match.
|
---|
| 2967 | var noMatch = /(.)^/;
|
---|
| 2968 |
|
---|
| 2969 | // Certain characters need to be escaped so that they can be put into a
|
---|
| 2970 | // string literal.
|
---|
| 2971 | var escapes = {
|
---|
| 2972 | "'": "'",
|
---|
| 2973 | '\\': '\\',
|
---|
| 2974 | '\r': 'r',
|
---|
| 2975 | '\n': 'n',
|
---|
| 2976 | '\t': 't',
|
---|
| 2977 | '\u2028': 'u2028',
|
---|
| 2978 | '\u2029': 'u2029'
|
---|
| 2979 | };
|
---|
| 2980 |
|
---|
| 2981 | var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g;
|
---|
| 2982 |
|
---|
| 2983 | // JavaScript micro-templating, similar to John Resig's implementation.
|
---|
| 2984 | // Underscore templating handles arbitrary delimiters, preserves whitespace,
|
---|
| 2985 | // and correctly escapes quotes within interpolated code.
|
---|
| 2986 | _.template = function(text, data, settings) {
|
---|
| 2987 | var render;
|
---|
| 2988 | settings = _.defaults({}, settings, _.templateSettings);
|
---|
| 2989 |
|
---|
| 2990 | // Combine delimiters into one regular expression via alternation.
|
---|
| 2991 | var matcher = new RegExp([
|
---|
| 2992 | (settings.escape || noMatch).source,
|
---|
| 2993 | (settings.interpolate || noMatch).source,
|
---|
| 2994 | (settings.evaluate || noMatch).source
|
---|
| 2995 | ].join('|') + '|$', 'g');
|
---|
| 2996 |
|
---|
| 2997 | // Compile the template source, escaping string literals appropriately.
|
---|
| 2998 | var index = 0;
|
---|
| 2999 | var source = "__p+='";
|
---|
| 3000 | text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
|
---|
| 3001 | source += text.slice(index, offset)
|
---|
| 3002 | .replace(escaper, function(match) { return '\\' + escapes[match]; });
|
---|
| 3003 |
|
---|
| 3004 | if (escape) {
|
---|
| 3005 | source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
|
---|
| 3006 | }
|
---|
| 3007 | if (interpolate) {
|
---|
| 3008 | source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
|
---|
| 3009 | }
|
---|
| 3010 | if (evaluate) {
|
---|
| 3011 | source += "';\n" + evaluate + "\n__p+='";
|
---|
| 3012 | }
|
---|
| 3013 | index = offset + match.length;
|
---|
| 3014 | return match;
|
---|
| 3015 | });
|
---|
| 3016 | source += "';\n";
|
---|
| 3017 |
|
---|
| 3018 | // If a variable is not specified, place data values in local scope.
|
---|
| 3019 | if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';
|
---|
| 3020 |
|
---|
| 3021 | source = "var __t,__p='',__j=Array.prototype.join," +
|
---|
| 3022 | "print=function(){__p+=__j.call(arguments,'');};\n" +
|
---|
| 3023 | source + "return __p;\n";
|
---|
| 3024 |
|
---|
| 3025 | try {
|
---|
| 3026 | render = new Function(settings.variable || 'obj', '_', source);
|
---|
| 3027 | } catch (e) {
|
---|
| 3028 | e.source = source;
|
---|
| 3029 | throw e;
|
---|
| 3030 | }
|
---|
| 3031 |
|
---|
| 3032 | if (data) return render(data, _);
|
---|
| 3033 | var template = function(data) {
|
---|
| 3034 | return render.call(this, data, _);
|
---|
| 3035 | };
|
---|
| 3036 |
|
---|
| 3037 | // Provide the compiled function source as a convenience for precompilation.
|
---|
| 3038 | template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}';
|
---|
| 3039 |
|
---|
| 3040 | return template;
|
---|
| 3041 | };
|
---|
| 3042 |
|
---|
| 3043 | // Add a "chain" function, which will delegate to the wrapper.
|
---|
| 3044 | _.chain = function(obj) {
|
---|
| 3045 | return _(obj).chain();
|
---|
| 3046 | };
|
---|
| 3047 |
|
---|
| 3048 | // OOP
|
---|
| 3049 | // ---------------
|
---|
| 3050 | // If Underscore is called as a function, it returns a wrapped object that
|
---|
| 3051 | // can be used OO-style. This wrapper holds altered versions of all the
|
---|
| 3052 | // underscore functions. Wrapped objects may be chained.
|
---|
| 3053 |
|
---|
| 3054 | // Helper function to continue chaining intermediate results.
|
---|
| 3055 | var result = function(obj) {
|
---|
| 3056 | return this._chain ? _(obj).chain() : obj;
|
---|
| 3057 | };
|
---|
| 3058 |
|
---|
| 3059 | // Add all of the Underscore functions to the wrapper object.
|
---|
| 3060 | _.mixin(_);
|
---|
| 3061 |
|
---|
| 3062 | // Add all mutator Array functions to the wrapper.
|
---|
| 3063 | each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
|
---|
| 3064 | var method = ArrayProto[name];
|
---|
| 3065 | _.prototype[name] = function() {
|
---|
| 3066 | var obj = this._wrapped;
|
---|
| 3067 | method.apply(obj, arguments);
|
---|
| 3068 | if ((name == 'shift' || name == 'splice') && obj.length === 0) delete obj[0];
|
---|
| 3069 | return result.call(this, obj);
|
---|
| 3070 | };
|
---|
| 3071 | });
|
---|
| 3072 |
|
---|
| 3073 | // Add all accessor Array functions to the wrapper.
|
---|
| 3074 | each(['concat', 'join', 'slice'], function(name) {
|
---|
| 3075 | var method = ArrayProto[name];
|
---|
| 3076 | _.prototype[name] = function() {
|
---|
| 3077 | return result.call(this, method.apply(this._wrapped, arguments));
|
---|
| 3078 | };
|
---|
| 3079 | });
|
---|
| 3080 |
|
---|
| 3081 | _.extend(_.prototype, {
|
---|
| 3082 |
|
---|
| 3083 | // Start chaining a wrapped Underscore object.
|
---|
| 3084 | chain: function() {
|
---|
| 3085 | this._chain = true;
|
---|
| 3086 | return this;
|
---|
| 3087 | },
|
---|
| 3088 |
|
---|
| 3089 | // Extracts the result from a wrapped and chained object.
|
---|
| 3090 | value: function() {
|
---|
| 3091 | return this._wrapped;
|
---|
| 3092 | }
|
---|
| 3093 |
|
---|
| 3094 | });
|
---|
| 3095 |
|
---|
| 3096 | }).call(this);
|
---|
| 3097 |
|
---|
| 3098 | },{}],15:[function(require,module,exports){
|
---|
| 3099 |
|
---|
| 3100 | (function() {
|
---|
| 3101 |
|
---|
| 3102 | // Baseline setup
|
---|
| 3103 | // --------------
|
---|
| 3104 |
|
---|
| 3105 | // Establish the root object, `window` in the browser, or `global` on the server.
|
---|
| 3106 | var root = this;
|
---|
| 3107 |
|
---|
| 3108 | // Save the previous value of the `humanize` variable.
|
---|
| 3109 | var previousHumanize = root.humanize;
|
---|
| 3110 |
|
---|
| 3111 | var humanize = {};
|
---|
| 3112 |
|
---|
| 3113 | if (typeof exports !== 'undefined') {
|
---|
| 3114 | if (typeof module !== 'undefined' && module.exports) {
|
---|
| 3115 | exports = module.exports = humanize;
|
---|
| 3116 | }
|
---|
| 3117 | exports.humanize = humanize;
|
---|
| 3118 | } else {
|
---|
| 3119 | if (typeof define === 'function' && define.amd) {
|
---|
| 3120 | define('humanize', function() {
|
---|
| 3121 | return humanize;
|
---|
| 3122 | });
|
---|
| 3123 | }
|
---|
| 3124 | root.humanize = humanize;
|
---|
| 3125 | }
|
---|
| 3126 |
|
---|
| 3127 | humanize.noConflict = function() {
|
---|
| 3128 | root.humanize = previousHumanize;
|
---|
| 3129 | return this;
|
---|
| 3130 | };
|
---|
| 3131 |
|
---|
| 3132 | humanize.pad = function(str, count, padChar, type) {
|
---|
| 3133 | str += '';
|
---|
| 3134 | if (!padChar) {
|
---|
| 3135 | padChar = ' ';
|
---|
| 3136 | } else if (padChar.length > 1) {
|
---|
| 3137 | padChar = padChar.charAt(0);
|
---|
| 3138 | }
|
---|
| 3139 | type = (type === undefined) ? 'left' : 'right';
|
---|
| 3140 |
|
---|
| 3141 | if (type === 'right') {
|
---|
| 3142 | while (str.length < count) {
|
---|
| 3143 | str = str + padChar;
|
---|
| 3144 | }
|
---|
| 3145 | } else {
|
---|
| 3146 | // default to left
|
---|
| 3147 | while (str.length < count) {
|
---|
| 3148 | str = padChar + str;
|
---|
| 3149 | }
|
---|
| 3150 | }
|
---|
| 3151 |
|
---|
| 3152 | return str;
|
---|
| 3153 | };
|
---|
| 3154 |
|
---|
| 3155 | // gets current unix time
|
---|
| 3156 | humanize.time = function() {
|
---|
| 3157 | return new Date().getTime() / 1000;
|
---|
| 3158 | };
|
---|
| 3159 |
|
---|
| 3160 | /**
|
---|
| 3161 | * PHP-inspired date
|
---|
| 3162 | */
|
---|
| 3163 |
|
---|
| 3164 | /* jan feb mar apr may jun jul aug sep oct nov dec */
|
---|
| 3165 | var dayTableCommon = [ 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 ];
|
---|
| 3166 | var dayTableLeap = [ 0, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 ];
|
---|
| 3167 | // var mtable_common[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
|
---|
| 3168 | // static int ml_table_leap[13] = { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
|
---|
| 3169 |
|
---|
| 3170 |
|
---|
| 3171 | humanize.date = function(format, timestamp) {
|
---|
| 3172 | var jsdate = ((timestamp === undefined) ? new Date() : // Not provided
|
---|
| 3173 | (timestamp instanceof Date) ? new Date(timestamp) : // JS Date()
|
---|
| 3174 | new Date(timestamp * 1000) // UNIX timestamp (auto-convert to int)
|
---|
| 3175 | );
|
---|
| 3176 |
|
---|
| 3177 | var formatChr = /\\?([a-z])/gi;
|
---|
| 3178 | var formatChrCb = function (t, s) {
|
---|
| 3179 | return f[t] ? f[t]() : s;
|
---|
| 3180 | };
|
---|
| 3181 |
|
---|
| 3182 | var shortDayTxt = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
|
---|
| 3183 | var monthTxt = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
|
---|
| 3184 |
|
---|
| 3185 | var f = {
|
---|
| 3186 | /* Day */
|
---|
| 3187 | // Day of month w/leading 0; 01..31
|
---|
| 3188 | d: function () { return humanize.pad(f.j(), 2, '0'); },
|
---|
| 3189 |
|
---|
| 3190 | // Shorthand day name; Mon..Sun
|
---|
| 3191 | D: function () { return f.l().slice(0, 3); },
|
---|
| 3192 |
|
---|
| 3193 | // Day of month; 1..31
|
---|
| 3194 | j: function () { return jsdate.getDate(); },
|
---|
| 3195 |
|
---|
| 3196 | // Full day name; Monday..Sunday
|
---|
| 3197 | l: function () { return shortDayTxt[f.w()]; },
|
---|
| 3198 |
|
---|
| 3199 | // ISO-8601 day of week; 1[Mon]..7[Sun]
|
---|
| 3200 | N: function () { return f.w() || 7; },
|
---|
| 3201 |
|
---|
| 3202 | // Ordinal suffix for day of month; st, nd, rd, th
|
---|
| 3203 | S: function () {
|
---|
| 3204 | var j = f.j();
|
---|
| 3205 | return j > 4 && j < 21 ? 'th' : {1: 'st', 2: 'nd', 3: 'rd'}[j % 10] || 'th';
|
---|
| 3206 | },
|
---|
| 3207 |
|
---|
| 3208 | // Day of week; 0[Sun]..6[Sat]
|
---|
| 3209 | w: function () { return jsdate.getDay(); },
|
---|
| 3210 |
|
---|
| 3211 | // Day of year; 0..365
|
---|
| 3212 | z: function () {
|
---|
| 3213 | return (f.L() ? dayTableLeap[f.n()] : dayTableCommon[f.n()]) + f.j() - 1;
|
---|
| 3214 | },
|
---|
| 3215 |
|
---|
| 3216 | /* Week */
|
---|
| 3217 | // ISO-8601 week number
|
---|
| 3218 | W: function () {
|
---|
| 3219 | // days between midweek of this week and jan 4
|
---|
| 3220 | // (f.z() - f.N() + 1 + 3.5) - 3
|
---|
| 3221 | var midWeekDaysFromJan4 = f.z() - f.N() + 1.5;
|
---|
| 3222 | // 1 + number of weeks + rounded week
|
---|
| 3223 | return humanize.pad(1 + Math.floor(Math.abs(midWeekDaysFromJan4) / 7) + (midWeekDaysFromJan4 % 7 > 3.5 ? 1 : 0), 2, '0');
|
---|
| 3224 | },
|
---|
| 3225 |
|
---|
| 3226 | /* Month */
|
---|
| 3227 | // Full month name; January..December
|
---|
| 3228 | F: function () { return monthTxt[jsdate.getMonth()]; },
|
---|
| 3229 |
|
---|
| 3230 | // Month w/leading 0; 01..12
|
---|
| 3231 | m: function () { return humanize.pad(f.n(), 2, '0'); },
|
---|
| 3232 |
|
---|
| 3233 | // Shorthand month name; Jan..Dec
|
---|
| 3234 | M: function () { return f.F().slice(0, 3); },
|
---|
| 3235 |
|
---|
| 3236 | // Month; 1..12
|
---|
| 3237 | n: function () { return jsdate.getMonth() + 1; },
|
---|
| 3238 |
|
---|
| 3239 | // Days in month; 28..31
|
---|
| 3240 | t: function () { return (new Date(f.Y(), f.n(), 0)).getDate(); },
|
---|
| 3241 |
|
---|
| 3242 | /* Year */
|
---|
| 3243 | // Is leap year?; 0 or 1
|
---|
| 3244 | L: function () { return new Date(f.Y(), 1, 29).getMonth() === 1 ? 1 : 0; },
|
---|
| 3245 |
|
---|
| 3246 | // ISO-8601 year
|
---|
| 3247 | o: function () {
|
---|
| 3248 | var n = f.n();
|
---|
| 3249 | var W = f.W();
|
---|
| 3250 | return f.Y() + (n === 12 && W < 9 ? -1 : n === 1 && W > 9);
|
---|
| 3251 | },
|
---|
| 3252 |
|
---|
| 3253 | // Full year; e.g. 1980..2010
|
---|
| 3254 | Y: function () { return jsdate.getFullYear(); },
|
---|
| 3255 |
|
---|
| 3256 | // Last two digits of year; 00..99
|
---|
| 3257 | y: function () { return (String(f.Y())).slice(-2); },
|
---|
| 3258 |
|
---|
| 3259 | /* Time */
|
---|
| 3260 | // am or pm
|
---|
| 3261 | a: function () { return jsdate.getHours() > 11 ? 'pm' : 'am'; },
|
---|
| 3262 |
|
---|
| 3263 | // AM or PM
|
---|
| 3264 | A: function () { return f.a().toUpperCase(); },
|
---|
| 3265 |
|
---|
| 3266 | // Swatch Internet time; 000..999
|
---|
| 3267 | B: function () {
|
---|
| 3268 | var unixTime = jsdate.getTime() / 1000;
|
---|
| 3269 | var secondsPassedToday = unixTime % 86400 + 3600; // since it's based off of UTC+1
|
---|
| 3270 | if (secondsPassedToday < 0) { secondsPassedToday += 86400; }
|
---|
| 3271 | var beats = ((secondsPassedToday) / 86.4) % 1000;
|
---|
| 3272 | if (unixTime < 0) {
|
---|
| 3273 | return Math.ceil(beats);
|
---|
| 3274 | }
|
---|
| 3275 | return Math.floor(beats);
|
---|
| 3276 | },
|
---|
| 3277 |
|
---|
| 3278 | // 12-Hours; 1..12
|
---|
| 3279 | g: function () { return f.G() % 12 || 12; },
|
---|
| 3280 |
|
---|
| 3281 | // 24-Hours; 0..23
|
---|
| 3282 | G: function () { return jsdate.getHours(); },
|
---|
| 3283 |
|
---|
| 3284 | // 12-Hours w/leading 0; 01..12
|
---|
| 3285 | h: function () { return humanize.pad(f.g(), 2, '0'); },
|
---|
| 3286 |
|
---|
| 3287 | // 24-Hours w/leading 0; 00..23
|
---|
| 3288 | H: function () { return humanize.pad(f.G(), 2, '0'); },
|
---|
| 3289 |
|
---|
| 3290 | // Minutes w/leading 0; 00..59
|
---|
| 3291 | i: function () { return humanize.pad(jsdate.getMinutes(), 2, '0'); },
|
---|
| 3292 |
|
---|
| 3293 | // Seconds w/leading 0; 00..59
|
---|
| 3294 | s: function () { return humanize.pad(jsdate.getSeconds(), 2, '0'); },
|
---|
| 3295 |
|
---|
| 3296 | // Microseconds; 000000-999000
|
---|
| 3297 | u: function () { return humanize.pad(jsdate.getMilliseconds() * 1000, 6, '0'); },
|
---|
| 3298 |
|
---|
| 3299 | // Whether or not the date is in daylight savings time
|
---|
| 3300 | /*
|
---|
| 3301 | I: function () {
|
---|
| 3302 | // Compares Jan 1 minus Jan 1 UTC to Jul 1 minus Jul 1 UTC.
|
---|
| 3303 | // If they are not equal, then DST is observed.
|
---|
| 3304 | var Y = f.Y();
|
---|
| 3305 | return 0 + ((new Date(Y, 0) - Date.UTC(Y, 0)) !== (new Date(Y, 6) - Date.UTC(Y, 6)));
|
---|
| 3306 | },
|
---|
| 3307 | */
|
---|
| 3308 |
|
---|
| 3309 | // Difference to GMT in hour format; e.g. +0200
|
---|
| 3310 | O: function () {
|
---|
| 3311 | var tzo = jsdate.getTimezoneOffset();
|
---|
| 3312 | var tzoNum = Math.abs(tzo);
|
---|
| 3313 | return (tzo > 0 ? '-' : '+') + humanize.pad(Math.floor(tzoNum / 60) * 100 + tzoNum % 60, 4, '0');
|
---|
| 3314 | },
|
---|
| 3315 |
|
---|
| 3316 | // Difference to GMT w/colon; e.g. +02:00
|
---|
| 3317 | P: function () {
|
---|
| 3318 | var O = f.O();
|
---|
| 3319 | return (O.substr(0, 3) + ':' + O.substr(3, 2));
|
---|
| 3320 | },
|
---|
| 3321 |
|
---|
| 3322 | // Timezone offset in seconds (-43200..50400)
|
---|
| 3323 | Z: function () { return -jsdate.getTimezoneOffset() * 60; },
|
---|
| 3324 |
|
---|
| 3325 | // Full Date/Time, ISO-8601 date
|
---|
| 3326 | c: function () { return 'Y-m-d\\TH:i:sP'.replace(formatChr, formatChrCb); },
|
---|
| 3327 |
|
---|
| 3328 | // RFC 2822
|
---|
| 3329 | r: function () { return 'D, d M Y H:i:s O'.replace(formatChr, formatChrCb); },
|
---|
| 3330 |
|
---|
| 3331 | // Seconds since UNIX epoch
|
---|
| 3332 | U: function () { return jsdate.getTime() / 1000 || 0; }
|
---|
| 3333 | };
|
---|
| 3334 |
|
---|
| 3335 | return format.replace(formatChr, formatChrCb);
|
---|
| 3336 | };
|
---|
| 3337 |
|
---|
| 3338 |
|
---|
| 3339 | /**
|
---|
| 3340 | * format number by adding thousands separaters and significant digits while rounding
|
---|
| 3341 | */
|
---|
| 3342 | humanize.numberFormat = function(number, decimals, decPoint, thousandsSep) {
|
---|
| 3343 | decimals = isNaN(decimals) ? 2 : Math.abs(decimals);
|
---|
| 3344 | decPoint = (decPoint === undefined) ? '.' : decPoint;
|
---|
| 3345 | thousandsSep = (thousandsSep === undefined) ? ',' : thousandsSep;
|
---|
| 3346 |
|
---|
| 3347 | var sign = number < 0 ? '-' : '';
|
---|
| 3348 | number = Math.abs(+number || 0);
|
---|
| 3349 |
|
---|
| 3350 | var intPart = parseInt(number.toFixed(decimals), 10) + '';
|
---|
| 3351 | var j = intPart.length > 3 ? intPart.length % 3 : 0;
|
---|
| 3352 |
|
---|
| 3353 | return sign + (j ? intPart.substr(0, j) + thousandsSep : '') + intPart.substr(j).replace(/(\d{3})(?=\d)/g, '$1' + thousandsSep) + (decimals ? decPoint + Math.abs(number - intPart).toFixed(decimals).slice(2) : '');
|
---|
| 3354 | };
|
---|
| 3355 |
|
---|
| 3356 |
|
---|
| 3357 | /**
|
---|
| 3358 | * For dates that are the current day or within one day, return 'today', 'tomorrow' or 'yesterday', as appropriate.
|
---|
| 3359 | * Otherwise, format the date using the passed in format string.
|
---|
| 3360 | *
|
---|
| 3361 | * Examples (when 'today' is 17 Feb 2007):
|
---|
| 3362 | * 16 Feb 2007 becomes yesterday.
|
---|
| 3363 | * 17 Feb 2007 becomes today.
|
---|
| 3364 | * 18 Feb 2007 becomes tomorrow.
|
---|
| 3365 | * Any other day is formatted according to given argument or the DATE_FORMAT setting if no argument is given.
|
---|
| 3366 | */
|
---|
| 3367 | humanize.naturalDay = function(timestamp, format) {
|
---|
| 3368 | timestamp = (timestamp === undefined) ? humanize.time() : timestamp;
|
---|
| 3369 | format = (format === undefined) ? 'Y-m-d' : format;
|
---|
| 3370 |
|
---|
| 3371 | var oneDay = 86400;
|
---|
| 3372 | var d = new Date();
|
---|
| 3373 | var today = (new Date(d.getFullYear(), d.getMonth(), d.getDate())).getTime() / 1000;
|
---|
| 3374 |
|
---|
| 3375 | if (timestamp < today && timestamp >= today - oneDay) {
|
---|
| 3376 | return 'yesterday';
|
---|
| 3377 | } else if (timestamp >= today && timestamp < today + oneDay) {
|
---|
| 3378 | return 'today';
|
---|
| 3379 | } else if (timestamp >= today + oneDay && timestamp < today + 2 * oneDay) {
|
---|
| 3380 | return 'tomorrow';
|
---|
| 3381 | }
|
---|
| 3382 |
|
---|
| 3383 | return humanize.date(format, timestamp);
|
---|
| 3384 | };
|
---|
| 3385 |
|
---|
| 3386 | /**
|
---|
| 3387 | * returns a string representing how many seconds, minutes or hours ago it was or will be in the future
|
---|
| 3388 | * Will always return a relative time, most granular of seconds to least granular of years. See unit tests for more details
|
---|
| 3389 | */
|
---|
| 3390 | humanize.relativeTime = function(timestamp) {
|
---|
| 3391 | timestamp = (timestamp === undefined) ? humanize.time() : timestamp;
|
---|
| 3392 |
|
---|
| 3393 | var currTime = humanize.time();
|
---|
| 3394 | var timeDiff = currTime - timestamp;
|
---|
| 3395 |
|
---|
| 3396 | // within 2 seconds
|
---|
| 3397 | if (timeDiff < 2 && timeDiff > -2) {
|
---|
| 3398 | return (timeDiff >= 0 ? 'just ' : '') + 'now';
|
---|
| 3399 | }
|
---|
| 3400 |
|
---|
| 3401 | // within a minute
|
---|
| 3402 | if (timeDiff < 60 && timeDiff > -60) {
|
---|
| 3403 | return (timeDiff >= 0 ? Math.floor(timeDiff) + ' seconds ago' : 'in ' + Math.floor(-timeDiff) + ' seconds');
|
---|
| 3404 | }
|
---|
| 3405 |
|
---|
| 3406 | // within 2 minutes
|
---|
| 3407 | if (timeDiff < 120 && timeDiff > -120) {
|
---|
| 3408 | return (timeDiff >= 0 ? 'about a minute ago' : 'in about a minute');
|
---|
| 3409 | }
|
---|
| 3410 |
|
---|
| 3411 | // within an hour
|
---|
| 3412 | if (timeDiff < 3600 && timeDiff > -3600) {
|
---|
| 3413 | return (timeDiff >= 0 ? Math.floor(timeDiff / 60) + ' minutes ago' : 'in ' + Math.floor(-timeDiff / 60) + ' minutes');
|
---|
| 3414 | }
|
---|
| 3415 |
|
---|
| 3416 | // within 2 hours
|
---|
| 3417 | if (timeDiff < 7200 && timeDiff > -7200) {
|
---|
| 3418 | return (timeDiff >= 0 ? 'about an hour ago' : 'in about an hour');
|
---|
| 3419 | }
|
---|
| 3420 |
|
---|
| 3421 | // within 24 hours
|
---|
| 3422 | if (timeDiff < 86400 && timeDiff > -86400) {
|
---|
| 3423 | return (timeDiff >= 0 ? Math.floor(timeDiff / 3600) + ' hours ago' : 'in ' + Math.floor(-timeDiff / 3600) + ' hours');
|
---|
| 3424 | }
|
---|
| 3425 |
|
---|
| 3426 | // within 2 days
|
---|
| 3427 | var days2 = 2 * 86400;
|
---|
| 3428 | if (timeDiff < days2 && timeDiff > -days2) {
|
---|
| 3429 | return (timeDiff >= 0 ? '1 day ago' : 'in 1 day');
|
---|
| 3430 | }
|
---|
| 3431 |
|
---|
| 3432 | // within 29 days
|
---|
| 3433 | var days29 = 29 * 86400;
|
---|
| 3434 | if (timeDiff < days29 && timeDiff > -days29) {
|
---|
| 3435 | return (timeDiff >= 0 ? Math.floor(timeDiff / 86400) + ' days ago' : 'in ' + Math.floor(-timeDiff / 86400) + ' days');
|
---|
| 3436 | }
|
---|
| 3437 |
|
---|
| 3438 | // within 60 days
|
---|
| 3439 | var days60 = 60 * 86400;
|
---|
| 3440 | if (timeDiff < days60 && timeDiff > -days60) {
|
---|
| 3441 | return (timeDiff >= 0 ? 'about a month ago' : 'in about a month');
|
---|
| 3442 | }
|
---|
| 3443 |
|
---|
| 3444 | var currTimeYears = parseInt(humanize.date('Y', currTime), 10);
|
---|
| 3445 | var timestampYears = parseInt(humanize.date('Y', timestamp), 10);
|
---|
| 3446 | var currTimeMonths = currTimeYears * 12 + parseInt(humanize.date('n', currTime), 10);
|
---|
| 3447 | var timestampMonths = timestampYears * 12 + parseInt(humanize.date('n', timestamp), 10);
|
---|
| 3448 |
|
---|
| 3449 | // within a year
|
---|
| 3450 | var monthDiff = currTimeMonths - timestampMonths;
|
---|
| 3451 | if (monthDiff < 12 && monthDiff > -12) {
|
---|
| 3452 | return (monthDiff >= 0 ? monthDiff + ' months ago' : 'in ' + (-monthDiff) + ' months');
|
---|
| 3453 | }
|
---|
| 3454 |
|
---|
| 3455 | var yearDiff = currTimeYears - timestampYears;
|
---|
| 3456 | if (yearDiff < 2 && yearDiff > -2) {
|
---|
| 3457 | return (yearDiff >= 0 ? 'a year ago' : 'in a year');
|
---|
| 3458 | }
|
---|
| 3459 |
|
---|
| 3460 | return (yearDiff >= 0 ? yearDiff + ' years ago' : 'in ' + (-yearDiff) + ' years');
|
---|
| 3461 | };
|
---|
| 3462 |
|
---|
| 3463 | /**
|
---|
| 3464 | * Converts an integer to its ordinal as a string.
|
---|
| 3465 | *
|
---|
| 3466 | * 1 becomes 1st
|
---|
| 3467 | * 2 becomes 2nd
|
---|
| 3468 | * 3 becomes 3rd etc
|
---|
| 3469 | */
|
---|
| 3470 | humanize.ordinal = function(number) {
|
---|
| 3471 | number = parseInt(number, 10);
|
---|
| 3472 | number = isNaN(number) ? 0 : number;
|
---|
| 3473 | var sign = number < 0 ? '-' : '';
|
---|
| 3474 | number = Math.abs(number);
|
---|
| 3475 | var tens = number % 100;
|
---|
| 3476 |
|
---|
| 3477 | return sign + number + (tens > 4 && tens < 21 ? 'th' : {1: 'st', 2: 'nd', 3: 'rd'}[number % 10] || 'th');
|
---|
| 3478 | };
|
---|
| 3479 |
|
---|
| 3480 | /**
|
---|
| 3481 | * Formats the value like a 'human-readable' file size (i.e. '13 KB', '4.1 MB', '102 bytes', etc).
|
---|
| 3482 | *
|
---|
| 3483 | * For example:
|
---|
| 3484 | * If value is 123456789, the output would be 117.7 MB.
|
---|
| 3485 | */
|
---|
| 3486 | humanize.filesize = function(filesize, kilo, decimals, decPoint, thousandsSep, suffixSep) {
|
---|
| 3487 | kilo = (kilo === undefined) ? 1024 : kilo;
|
---|
| 3488 | if (filesize <= 0) { return '0 bytes'; }
|
---|
| 3489 | if (filesize < kilo && decimals === undefined) { decimals = 0; }
|
---|
| 3490 | if (suffixSep === undefined) { suffixSep = ' '; }
|
---|
| 3491 | return humanize.intword(filesize, ['bytes', 'KB', 'MB', 'GB', 'TB', 'PB'], kilo, decimals, decPoint, thousandsSep, suffixSep);
|
---|
| 3492 | };
|
---|
| 3493 |
|
---|
| 3494 | /**
|
---|
| 3495 | * Formats the value like a 'human-readable' number (i.e. '13 K', '4.1 M', '102', etc).
|
---|
| 3496 | *
|
---|
| 3497 | * For example:
|
---|
| 3498 | * If value is 123456789, the output would be 117.7 M.
|
---|
| 3499 | */
|
---|
| 3500 | humanize.intword = function(number, units, kilo, decimals, decPoint, thousandsSep, suffixSep) {
|
---|
| 3501 | var humanized, unit;
|
---|
| 3502 |
|
---|
| 3503 | units = units || ['', 'K', 'M', 'B', 'T'],
|
---|
| 3504 | unit = units.length - 1,
|
---|
| 3505 | kilo = kilo || 1000,
|
---|
| 3506 | decimals = isNaN(decimals) ? 2 : Math.abs(decimals),
|
---|
| 3507 | decPoint = decPoint || '.',
|
---|
| 3508 | thousandsSep = thousandsSep || ',',
|
---|
| 3509 | suffixSep = suffixSep || '';
|
---|
| 3510 |
|
---|
| 3511 | for (var i=0; i < units.length; i++) {
|
---|
| 3512 | if (number < Math.pow(kilo, i+1)) {
|
---|
| 3513 | unit = i;
|
---|
| 3514 | break;
|
---|
| 3515 | }
|
---|
| 3516 | }
|
---|
| 3517 | humanized = number / Math.pow(kilo, unit);
|
---|
| 3518 |
|
---|
| 3519 | var suffix = units[unit] ? suffixSep + units[unit] : '';
|
---|
| 3520 | return humanize.numberFormat(humanized, decimals, decPoint, thousandsSep) + suffix;
|
---|
| 3521 | };
|
---|
| 3522 |
|
---|
| 3523 | /**
|
---|
| 3524 | * Replaces line breaks in plain text with appropriate HTML
|
---|
| 3525 | * A single newline becomes an HTML line break (<br />) and a new line followed by a blank line becomes a paragraph break (</p>).
|
---|
| 3526 | *
|
---|
| 3527 | * For example:
|
---|
| 3528 | * If value is Joel\nis a\n\nslug, the output will be <p>Joel<br />is a</p><p>slug</p>
|
---|
| 3529 | */
|
---|
| 3530 | humanize.linebreaks = function(str) {
|
---|
| 3531 | // remove beginning and ending newlines
|
---|
| 3532 | str = str.replace(/^([\n|\r]*)/, '');
|
---|
| 3533 | str = str.replace(/([\n|\r]*)$/, '');
|
---|
| 3534 |
|
---|
| 3535 | // normalize all to \n
|
---|
| 3536 | str = str.replace(/(\r\n|\n|\r)/g, "\n");
|
---|
| 3537 |
|
---|
| 3538 | // any consecutive new lines more than 2 gets turned into p tags
|
---|
| 3539 | str = str.replace(/(\n{2,})/g, '</p><p>');
|
---|
| 3540 |
|
---|
| 3541 | // any that are singletons get turned into br
|
---|
| 3542 | str = str.replace(/\n/g, '<br />');
|
---|
| 3543 | return '<p>' + str + '</p>';
|
---|
| 3544 | };
|
---|
| 3545 |
|
---|
| 3546 | /**
|
---|
| 3547 | * Converts all newlines in a piece of plain text to HTML line breaks (<br />).
|
---|
| 3548 | */
|
---|
| 3549 | humanize.nl2br = function(str) {
|
---|
| 3550 | return str.replace(/(\r\n|\n|\r)/g, '<br />');
|
---|
| 3551 | };
|
---|
| 3552 |
|
---|
| 3553 | /**
|
---|
| 3554 | * Truncates a string if it is longer than the specified number of characters.
|
---|
| 3555 | * Truncated strings will end with a translatable ellipsis sequence ('…').
|
---|
| 3556 | */
|
---|
| 3557 | humanize.truncatechars = function(string, length) {
|
---|
| 3558 | if (string.length <= length) { return string; }
|
---|
| 3559 | return string.substr(0, length) + '…';
|
---|
| 3560 | };
|
---|
| 3561 |
|
---|
| 3562 | /**
|
---|
| 3563 | * Truncates a string after a certain number of words.
|
---|
| 3564 | * Newlines within the string will be removed.
|
---|
| 3565 | */
|
---|
| 3566 | humanize.truncatewords = function(string, numWords) {
|
---|
| 3567 | var words = string.split(' ');
|
---|
| 3568 | if (words.length < numWords) { return string; }
|
---|
| 3569 | return words.slice(0, numWords).join(' ') + '…';
|
---|
| 3570 | };
|
---|
| 3571 |
|
---|
| 3572 | }).call(this);
|
---|
| 3573 |
|
---|
| 3574 | },{}],16:[function(require,module,exports){
|
---|
| 3575 | // Underscore.js 1.7.0
|
---|
| 3576 | // http://underscorejs.org
|
---|
| 3577 | // (c) 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
|
---|
| 3578 | // Underscore may be freely distributed under the MIT license.
|
---|
| 3579 |
|
---|
| 3580 | (function() {
|
---|
| 3581 |
|
---|
| 3582 | // Baseline setup
|
---|
| 3583 | // --------------
|
---|
| 3584 |
|
---|
| 3585 | // Establish the root object, `window` in the browser, or `exports` on the server.
|
---|
| 3586 | var root = this;
|
---|
| 3587 |
|
---|
| 3588 | // Save the previous value of the `_` variable.
|
---|
| 3589 | var previousUnderscore = root._;
|
---|
| 3590 |
|
---|
| 3591 | // Save bytes in the minified (but not gzipped) version:
|
---|
| 3592 | var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;
|
---|
| 3593 |
|
---|
| 3594 | // Create quick reference variables for speed access to core prototypes.
|
---|
| 3595 | var
|
---|
| 3596 | push = ArrayProto.push,
|
---|
| 3597 | slice = ArrayProto.slice,
|
---|
| 3598 | concat = ArrayProto.concat,
|
---|
| 3599 | toString = ObjProto.toString,
|
---|
| 3600 | hasOwnProperty = ObjProto.hasOwnProperty;
|
---|
| 3601 |
|
---|
| 3602 | // All **ECMAScript 5** native function implementations that we hope to use
|
---|
| 3603 | // are declared here.
|
---|
| 3604 | var
|
---|
| 3605 | nativeIsArray = Array.isArray,
|
---|
| 3606 | nativeKeys = Object.keys,
|
---|
| 3607 | nativeBind = FuncProto.bind;
|
---|
| 3608 |
|
---|
| 3609 | // Create a safe reference to the Underscore object for use below.
|
---|
| 3610 | var _ = function(obj) {
|
---|
| 3611 | if (obj instanceof _) return obj;
|
---|
| 3612 | if (!(this instanceof _)) return new _(obj);
|
---|
| 3613 | this._wrapped = obj;
|
---|
| 3614 | };
|
---|
| 3615 |
|
---|
| 3616 | // Export the Underscore object for **Node.js**, with
|
---|
| 3617 | // backwards-compatibility for the old `require()` API. If we're in
|
---|
| 3618 | // the browser, add `_` as a global object.
|
---|
| 3619 | if (typeof exports !== 'undefined') {
|
---|
| 3620 | if (typeof module !== 'undefined' && module.exports) {
|
---|
| 3621 | exports = module.exports = _;
|
---|
| 3622 | }
|
---|
| 3623 | exports._ = _;
|
---|
| 3624 | } else {
|
---|
| 3625 | root._ = _;
|
---|
| 3626 | }
|
---|
| 3627 |
|
---|
| 3628 | // Current version.
|
---|
| 3629 | _.VERSION = '1.7.0';
|
---|
| 3630 |
|
---|
| 3631 | // Internal function that returns an efficient (for current engines) version
|
---|
| 3632 | // of the passed-in callback, to be repeatedly applied in other Underscore
|
---|
| 3633 | // functions.
|
---|
| 3634 | var createCallback = function(func, context, argCount) {
|
---|
| 3635 | if (context === void 0) return func;
|
---|
| 3636 | switch (argCount == null ? 3 : argCount) {
|
---|
| 3637 | case 1: return function(value) {
|
---|
| 3638 | return func.call(context, value);
|
---|
| 3639 | };
|
---|
| 3640 | case 2: return function(value, other) {
|
---|
| 3641 | return func.call(context, value, other);
|
---|
| 3642 | };
|
---|
| 3643 | case 3: return function(value, index, collection) {
|
---|
| 3644 | return func.call(context, value, index, collection);
|
---|
| 3645 | };
|
---|
| 3646 | case 4: return function(accumulator, value, index, collection) {
|
---|
| 3647 | return func.call(context, accumulator, value, index, collection);
|
---|
| 3648 | };
|
---|
| 3649 | }
|
---|
| 3650 | return function() {
|
---|
| 3651 | return func.apply(context, arguments);
|
---|
| 3652 | };
|
---|
| 3653 | };
|
---|
| 3654 |
|
---|
| 3655 | // A mostly-internal function to generate callbacks that can be applied
|
---|
| 3656 | // to each element in a collection, returning the desired result — either
|
---|
| 3657 | // identity, an arbitrary callback, a property matcher, or a property accessor.
|
---|
| 3658 | _.iteratee = function(value, context, argCount) {
|
---|
| 3659 | if (value == null) return _.identity;
|
---|
| 3660 | if (_.isFunction(value)) return createCallback(value, context, argCount);
|
---|
| 3661 | if (_.isObject(value)) return _.matches(value);
|
---|
| 3662 | return _.property(value);
|
---|
| 3663 | };
|
---|
| 3664 |
|
---|
| 3665 | // Collection Functions
|
---|
| 3666 | // --------------------
|
---|
| 3667 |
|
---|
| 3668 | // The cornerstone, an `each` implementation, aka `forEach`.
|
---|
| 3669 | // Handles raw objects in addition to array-likes. Treats all
|
---|
| 3670 | // sparse array-likes as if they were dense.
|
---|
| 3671 | _.each = _.forEach = function(obj, iteratee, context) {
|
---|
| 3672 | if (obj == null) return obj;
|
---|
| 3673 | iteratee = createCallback(iteratee, context);
|
---|
| 3674 | var i, length = obj.length;
|
---|
| 3675 | if (length === +length) {
|
---|
| 3676 | for (i = 0; i < length; i++) {
|
---|
| 3677 | iteratee(obj[i], i, obj);
|
---|
| 3678 | }
|
---|
| 3679 | } else {
|
---|
| 3680 | var keys = _.keys(obj);
|
---|
| 3681 | for (i = 0, length = keys.length; i < length; i++) {
|
---|
| 3682 | iteratee(obj[keys[i]], keys[i], obj);
|
---|
| 3683 | }
|
---|
| 3684 | }
|
---|
| 3685 | return obj;
|
---|
| 3686 | };
|
---|
| 3687 |
|
---|
| 3688 | // Return the results of applying the iteratee to each element.
|
---|
| 3689 | _.map = _.collect = function(obj, iteratee, context) {
|
---|
| 3690 | if (obj == null) return [];
|
---|
| 3691 | iteratee = _.iteratee(iteratee, context);
|
---|
| 3692 | var keys = obj.length !== +obj.length && _.keys(obj),
|
---|
| 3693 | length = (keys || obj).length,
|
---|
| 3694 | results = Array(length),
|
---|
| 3695 | currentKey;
|
---|
| 3696 | for (var index = 0; index < length; index++) {
|
---|
| 3697 | currentKey = keys ? keys[index] : index;
|
---|
| 3698 | results[index] = iteratee(obj[currentKey], currentKey, obj);
|
---|
| 3699 | }
|
---|
| 3700 | return results;
|
---|
| 3701 | };
|
---|
| 3702 |
|
---|
| 3703 | var reduceError = 'Reduce of empty array with no initial value';
|
---|
| 3704 |
|
---|
| 3705 | // **Reduce** builds up a single result from a list of values, aka `inject`,
|
---|
| 3706 | // or `foldl`.
|
---|
| 3707 | _.reduce = _.foldl = _.inject = function(obj, iteratee, memo, context) {
|
---|
| 3708 | if (obj == null) obj = [];
|
---|
| 3709 | iteratee = createCallback(iteratee, context, 4);
|
---|
| 3710 | var keys = obj.length !== +obj.length && _.keys(obj),
|
---|
| 3711 | length = (keys || obj).length,
|
---|
| 3712 | index = 0, currentKey;
|
---|
| 3713 | if (arguments.length < 3) {
|
---|
| 3714 | if (!length) throw new TypeError(reduceError);
|
---|
| 3715 | memo = obj[keys ? keys[index++] : index++];
|
---|
| 3716 | }
|
---|
| 3717 | for (; index < length; index++) {
|
---|
| 3718 | currentKey = keys ? keys[index] : index;
|
---|
| 3719 | memo = iteratee(memo, obj[currentKey], currentKey, obj);
|
---|
| 3720 | }
|
---|
| 3721 | return memo;
|
---|
| 3722 | };
|
---|
| 3723 |
|
---|
| 3724 | // The right-associative version of reduce, also known as `foldr`.
|
---|
| 3725 | _.reduceRight = _.foldr = function(obj, iteratee, memo, context) {
|
---|
| 3726 | if (obj == null) obj = [];
|
---|
| 3727 | iteratee = createCallback(iteratee, context, 4);
|
---|
| 3728 | var keys = obj.length !== + obj.length && _.keys(obj),
|
---|
| 3729 | index = (keys || obj).length,
|
---|
| 3730 | currentKey;
|
---|
| 3731 | if (arguments.length < 3) {
|
---|
| 3732 | if (!index) throw new TypeError(reduceError);
|
---|
| 3733 | memo = obj[keys ? keys[--index] : --index];
|
---|
| 3734 | }
|
---|
| 3735 | while (index--) {
|
---|
| 3736 | currentKey = keys ? keys[index] : index;
|
---|
| 3737 | memo = iteratee(memo, obj[currentKey], currentKey, obj);
|
---|
| 3738 | }
|
---|
| 3739 | return memo;
|
---|
| 3740 | };
|
---|
| 3741 |
|
---|
| 3742 | // Return the first value which passes a truth test. Aliased as `detect`.
|
---|
| 3743 | _.find = _.detect = function(obj, predicate, context) {
|
---|
| 3744 | var result;
|
---|
| 3745 | predicate = _.iteratee(predicate, context);
|
---|
| 3746 | _.some(obj, function(value, index, list) {
|
---|
| 3747 | if (predicate(value, index, list)) {
|
---|
| 3748 | result = value;
|
---|
| 3749 | return true;
|
---|
| 3750 | }
|
---|
| 3751 | });
|
---|
| 3752 | return result;
|
---|
| 3753 | };
|
---|
| 3754 |
|
---|
| 3755 | // Return all the elements that pass a truth test.
|
---|
| 3756 | // Aliased as `select`.
|
---|
| 3757 | _.filter = _.select = function(obj, predicate, context) {
|
---|
| 3758 | var results = [];
|
---|
| 3759 | if (obj == null) return results;
|
---|
| 3760 | predicate = _.iteratee(predicate, context);
|
---|
| 3761 | _.each(obj, function(value, index, list) {
|
---|
| 3762 | if (predicate(value, index, list)) results.push(value);
|
---|
| 3763 | });
|
---|
| 3764 | return results;
|
---|
| 3765 | };
|
---|
| 3766 |
|
---|
| 3767 | // Return all the elements for which a truth test fails.
|
---|
| 3768 | _.reject = function(obj, predicate, context) {
|
---|
| 3769 | return _.filter(obj, _.negate(_.iteratee(predicate)), context);
|
---|
| 3770 | };
|
---|
| 3771 |
|
---|
| 3772 | // Determine whether all of the elements match a truth test.
|
---|
| 3773 | // Aliased as `all`.
|
---|
| 3774 | _.every = _.all = function(obj, predicate, context) {
|
---|
| 3775 | if (obj == null) return true;
|
---|
| 3776 | predicate = _.iteratee(predicate, context);
|
---|
| 3777 | var keys = obj.length !== +obj.length && _.keys(obj),
|
---|
| 3778 | length = (keys || obj).length,
|
---|
| 3779 | index, currentKey;
|
---|
| 3780 | for (index = 0; index < length; index++) {
|
---|
| 3781 | currentKey = keys ? keys[index] : index;
|
---|
| 3782 | if (!predicate(obj[currentKey], currentKey, obj)) return false;
|
---|
| 3783 | }
|
---|
| 3784 | return true;
|
---|
| 3785 | };
|
---|
| 3786 |
|
---|
| 3787 | // Determine if at least one element in the object matches a truth test.
|
---|
| 3788 | // Aliased as `any`.
|
---|
| 3789 | _.some = _.any = function(obj, predicate, context) {
|
---|
| 3790 | if (obj == null) return false;
|
---|
| 3791 | predicate = _.iteratee(predicate, context);
|
---|
| 3792 | var keys = obj.length !== +obj.length && _.keys(obj),
|
---|
| 3793 | length = (keys || obj).length,
|
---|
| 3794 | index, currentKey;
|
---|
| 3795 | for (index = 0; index < length; index++) {
|
---|
| 3796 | currentKey = keys ? keys[index] : index;
|
---|
| 3797 | if (predicate(obj[currentKey], currentKey, obj)) return true;
|
---|
| 3798 | }
|
---|
| 3799 | return false;
|
---|
| 3800 | };
|
---|
| 3801 |
|
---|
| 3802 | // Determine if the array or object contains a given value (using `===`).
|
---|
| 3803 | // Aliased as `include`.
|
---|
| 3804 | _.contains = _.include = function(obj, target) {
|
---|
| 3805 | if (obj == null) return false;
|
---|
| 3806 | if (obj.length !== +obj.length) obj = _.values(obj);
|
---|
| 3807 | return _.indexOf(obj, target) >= 0;
|
---|
| 3808 | };
|
---|
| 3809 |
|
---|
| 3810 | // Invoke a method (with arguments) on every item in a collection.
|
---|
| 3811 | _.invoke = function(obj, method) {
|
---|
| 3812 | var args = slice.call(arguments, 2);
|
---|
| 3813 | var isFunc = _.isFunction(method);
|
---|
| 3814 | return _.map(obj, function(value) {
|
---|
| 3815 | return (isFunc ? method : value[method]).apply(value, args);
|
---|
| 3816 | });
|
---|
| 3817 | };
|
---|
| 3818 |
|
---|
| 3819 | // Convenience version of a common use case of `map`: fetching a property.
|
---|
| 3820 | _.pluck = function(obj, key) {
|
---|
| 3821 | return _.map(obj, _.property(key));
|
---|
| 3822 | };
|
---|
| 3823 |
|
---|
| 3824 | // Convenience version of a common use case of `filter`: selecting only objects
|
---|
| 3825 | // containing specific `key:value` pairs.
|
---|
| 3826 | _.where = function(obj, attrs) {
|
---|
| 3827 | return _.filter(obj, _.matches(attrs));
|
---|
| 3828 | };
|
---|
| 3829 |
|
---|
| 3830 | // Convenience version of a common use case of `find`: getting the first object
|
---|
| 3831 | // containing specific `key:value` pairs.
|
---|
| 3832 | _.findWhere = function(obj, attrs) {
|
---|
| 3833 | return _.find(obj, _.matches(attrs));
|
---|
| 3834 | };
|
---|
| 3835 |
|
---|
| 3836 | // Return the maximum element (or element-based computation).
|
---|
| 3837 | _.max = function(obj, iteratee, context) {
|
---|
| 3838 | var result = -Infinity, lastComputed = -Infinity,
|
---|
| 3839 | value, computed;
|
---|
| 3840 | if (iteratee == null && obj != null) {
|
---|
| 3841 | obj = obj.length === +obj.length ? obj : _.values(obj);
|
---|
| 3842 | for (var i = 0, length = obj.length; i < length; i++) {
|
---|
| 3843 | value = obj[i];
|
---|
| 3844 | if (value > result) {
|
---|
| 3845 | result = value;
|
---|
| 3846 | }
|
---|
| 3847 | }
|
---|
| 3848 | } else {
|
---|
| 3849 | iteratee = _.iteratee(iteratee, context);
|
---|
| 3850 | _.each(obj, function(value, index, list) {
|
---|
| 3851 | computed = iteratee(value, index, list);
|
---|
| 3852 | if (computed > lastComputed || computed === -Infinity && result === -Infinity) {
|
---|
| 3853 | result = value;
|
---|
| 3854 | lastComputed = computed;
|
---|
| 3855 | }
|
---|
| 3856 | });
|
---|
| 3857 | }
|
---|
| 3858 | return result;
|
---|
| 3859 | };
|
---|
| 3860 |
|
---|
| 3861 | // Return the minimum element (or element-based computation).
|
---|
| 3862 | _.min = function(obj, iteratee, context) {
|
---|
| 3863 | var result = Infinity, lastComputed = Infinity,
|
---|
| 3864 | value, computed;
|
---|
| 3865 | if (iteratee == null && obj != null) {
|
---|
| 3866 | obj = obj.length === +obj.length ? obj : _.values(obj);
|
---|
| 3867 | for (var i = 0, length = obj.length; i < length; i++) {
|
---|
| 3868 | value = obj[i];
|
---|
| 3869 | if (value < result) {
|
---|
| 3870 | result = value;
|
---|
| 3871 | }
|
---|
| 3872 | }
|
---|
| 3873 | } else {
|
---|
| 3874 | iteratee = _.iteratee(iteratee, context);
|
---|
| 3875 | _.each(obj, function(value, index, list) {
|
---|
| 3876 | computed = iteratee(value, index, list);
|
---|
| 3877 | if (computed < lastComputed || computed === Infinity && result === Infinity) {
|
---|
| 3878 | result = value;
|
---|
| 3879 | lastComputed = computed;
|
---|
| 3880 | }
|
---|
| 3881 | });
|
---|
| 3882 | }
|
---|
| 3883 | return result;
|
---|
| 3884 | };
|
---|
| 3885 |
|
---|
| 3886 | // Shuffle a collection, using the modern version of the
|
---|
| 3887 | // [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle).
|
---|
| 3888 | _.shuffle = function(obj) {
|
---|
| 3889 | var set = obj && obj.length === +obj.length ? obj : _.values(obj);
|
---|
| 3890 | var length = set.length;
|
---|
| 3891 | var shuffled = Array(length);
|
---|
| 3892 | for (var index = 0, rand; index < length; index++) {
|
---|
| 3893 | rand = _.random(0, index);
|
---|
| 3894 | if (rand !== index) shuffled[index] = shuffled[rand];
|
---|
| 3895 | shuffled[rand] = set[index];
|
---|
| 3896 | }
|
---|
| 3897 | return shuffled;
|
---|
| 3898 | };
|
---|
| 3899 |
|
---|
| 3900 | // Sample **n** random values from a collection.
|
---|
| 3901 | // If **n** is not specified, returns a single random element.
|
---|
| 3902 | // The internal `guard` argument allows it to work with `map`.
|
---|
| 3903 | _.sample = function(obj, n, guard) {
|
---|
| 3904 | if (n == null || guard) {
|
---|
| 3905 | if (obj.length !== +obj.length) obj = _.values(obj);
|
---|
| 3906 | return obj[_.random(obj.length - 1)];
|
---|
| 3907 | }
|
---|
| 3908 | return _.shuffle(obj).slice(0, Math.max(0, n));
|
---|
| 3909 | };
|
---|
| 3910 |
|
---|
| 3911 | // Sort the object's values by a criterion produced by an iteratee.
|
---|
| 3912 | _.sortBy = function(obj, iteratee, context) {
|
---|
| 3913 | iteratee = _.iteratee(iteratee, context);
|
---|
| 3914 | return _.pluck(_.map(obj, function(value, index, list) {
|
---|
| 3915 | return {
|
---|
| 3916 | value: value,
|
---|
| 3917 | index: index,
|
---|
| 3918 | criteria: iteratee(value, index, list)
|
---|
| 3919 | };
|
---|
| 3920 | }).sort(function(left, right) {
|
---|
| 3921 | var a = left.criteria;
|
---|
| 3922 | var b = right.criteria;
|
---|
| 3923 | if (a !== b) {
|
---|
| 3924 | if (a > b || a === void 0) return 1;
|
---|
| 3925 | if (a < b || b === void 0) return -1;
|
---|
| 3926 | }
|
---|
| 3927 | return left.index - right.index;
|
---|
| 3928 | }), 'value');
|
---|
| 3929 | };
|
---|
| 3930 |
|
---|
| 3931 | // An internal function used for aggregate "group by" operations.
|
---|
| 3932 | var group = function(behavior) {
|
---|
| 3933 | return function(obj, iteratee, context) {
|
---|
| 3934 | var result = {};
|
---|
| 3935 | iteratee = _.iteratee(iteratee, context);
|
---|
| 3936 | _.each(obj, function(value, index) {
|
---|
| 3937 | var key = iteratee(value, index, obj);
|
---|
| 3938 | behavior(result, value, key);
|
---|
| 3939 | });
|
---|
| 3940 | return result;
|
---|
| 3941 | };
|
---|
| 3942 | };
|
---|
| 3943 |
|
---|
| 3944 | // Groups the object's values by a criterion. Pass either a string attribute
|
---|
| 3945 | // to group by, or a function that returns the criterion.
|
---|
| 3946 | _.groupBy = group(function(result, value, key) {
|
---|
| 3947 | if (_.has(result, key)) result[key].push(value); else result[key] = [value];
|
---|
| 3948 | });
|
---|
| 3949 |
|
---|
| 3950 | // Indexes the object's values by a criterion, similar to `groupBy`, but for
|
---|
| 3951 | // when you know that your index values will be unique.
|
---|
| 3952 | _.indexBy = group(function(result, value, key) {
|
---|
| 3953 | result[key] = value;
|
---|
| 3954 | });
|
---|
| 3955 |
|
---|
| 3956 | // Counts instances of an object that group by a certain criterion. Pass
|
---|
| 3957 | // either a string attribute to count by, or a function that returns the
|
---|
| 3958 | // criterion.
|
---|
| 3959 | _.countBy = group(function(result, value, key) {
|
---|
| 3960 | if (_.has(result, key)) result[key]++; else result[key] = 1;
|
---|
| 3961 | });
|
---|
| 3962 |
|
---|
| 3963 | // Use a comparator function to figure out the smallest index at which
|
---|
| 3964 | // an object should be inserted so as to maintain order. Uses binary search.
|
---|
| 3965 | _.sortedIndex = function(array, obj, iteratee, context) {
|
---|
| 3966 | iteratee = _.iteratee(iteratee, context, 1);
|
---|
| 3967 | var value = iteratee(obj);
|
---|
| 3968 | var low = 0, high = array.length;
|
---|
| 3969 | while (low < high) {
|
---|
| 3970 | var mid = low + high >>> 1;
|
---|
| 3971 | if (iteratee(array[mid]) < value) low = mid + 1; else high = mid;
|
---|
| 3972 | }
|
---|
| 3973 | return low;
|
---|
| 3974 | };
|
---|
| 3975 |
|
---|
| 3976 | // Safely create a real, live array from anything iterable.
|
---|
| 3977 | _.toArray = function(obj) {
|
---|
| 3978 | if (!obj) return [];
|
---|
| 3979 | if (_.isArray(obj)) return slice.call(obj);
|
---|
| 3980 | if (obj.length === +obj.length) return _.map(obj, _.identity);
|
---|
| 3981 | return _.values(obj);
|
---|
| 3982 | };
|
---|
| 3983 |
|
---|
| 3984 | // Return the number of elements in an object.
|
---|
| 3985 | _.size = function(obj) {
|
---|
| 3986 | if (obj == null) return 0;
|
---|
| 3987 | return obj.length === +obj.length ? obj.length : _.keys(obj).length;
|
---|
| 3988 | };
|
---|
| 3989 |
|
---|
| 3990 | // Split a collection into two arrays: one whose elements all satisfy the given
|
---|
| 3991 | // predicate, and one whose elements all do not satisfy the predicate.
|
---|
| 3992 | _.partition = function(obj, predicate, context) {
|
---|
| 3993 | predicate = _.iteratee(predicate, context);
|
---|
| 3994 | var pass = [], fail = [];
|
---|
| 3995 | _.each(obj, function(value, key, obj) {
|
---|
| 3996 | (predicate(value, key, obj) ? pass : fail).push(value);
|
---|
| 3997 | });
|
---|
| 3998 | return [pass, fail];
|
---|
| 3999 | };
|
---|
| 4000 |
|
---|
| 4001 | // Array Functions
|
---|
| 4002 | // ---------------
|
---|
| 4003 |
|
---|
| 4004 | // Get the first element of an array. Passing **n** will return the first N
|
---|
| 4005 | // values in the array. Aliased as `head` and `take`. The **guard** check
|
---|
| 4006 | // allows it to work with `_.map`.
|
---|
| 4007 | _.first = _.head = _.take = function(array, n, guard) {
|
---|
| 4008 | if (array == null) return void 0;
|
---|
| 4009 | if (n == null || guard) return array[0];
|
---|
| 4010 | if (n < 0) return [];
|
---|
| 4011 | return slice.call(array, 0, n);
|
---|
| 4012 | };
|
---|
| 4013 |
|
---|
| 4014 | // Returns everything but the last entry of the array. Especially useful on
|
---|
| 4015 | // the arguments object. Passing **n** will return all the values in
|
---|
| 4016 | // the array, excluding the last N. The **guard** check allows it to work with
|
---|
| 4017 | // `_.map`.
|
---|
| 4018 | _.initial = function(array, n, guard) {
|
---|
| 4019 | return slice.call(array, 0, Math.max(0, array.length - (n == null || guard ? 1 : n)));
|
---|
| 4020 | };
|
---|
| 4021 |
|
---|
| 4022 | // Get the last element of an array. Passing **n** will return the last N
|
---|
| 4023 | // values in the array. The **guard** check allows it to work with `_.map`.
|
---|
| 4024 | _.last = function(array, n, guard) {
|
---|
| 4025 | if (array == null) return void 0;
|
---|
| 4026 | if (n == null || guard) return array[array.length - 1];
|
---|
| 4027 | return slice.call(array, Math.max(array.length - n, 0));
|
---|
| 4028 | };
|
---|
| 4029 |
|
---|
| 4030 | // Returns everything but the first entry of the array. Aliased as `tail` and `drop`.
|
---|
| 4031 | // Especially useful on the arguments object. Passing an **n** will return
|
---|
| 4032 | // the rest N values in the array. The **guard**
|
---|
| 4033 | // check allows it to work with `_.map`.
|
---|
| 4034 | _.rest = _.tail = _.drop = function(array, n, guard) {
|
---|
| 4035 | return slice.call(array, n == null || guard ? 1 : n);
|
---|
| 4036 | };
|
---|
| 4037 |
|
---|
| 4038 | // Trim out all falsy values from an array.
|
---|
| 4039 | _.compact = function(array) {
|
---|
| 4040 | return _.filter(array, _.identity);
|
---|
| 4041 | };
|
---|
| 4042 |
|
---|
| 4043 | // Internal implementation of a recursive `flatten` function.
|
---|
| 4044 | var flatten = function(input, shallow, strict, output) {
|
---|
| 4045 | if (shallow && _.every(input, _.isArray)) {
|
---|
| 4046 | return concat.apply(output, input);
|
---|
| 4047 | }
|
---|
| 4048 | for (var i = 0, length = input.length; i < length; i++) {
|
---|
| 4049 | var value = input[i];
|
---|
| 4050 | if (!_.isArray(value) && !_.isArguments(value)) {
|
---|
| 4051 | if (!strict) output.push(value);
|
---|
| 4052 | } else if (shallow) {
|
---|
| 4053 | push.apply(output, value);
|
---|
| 4054 | } else {
|
---|
| 4055 | flatten(value, shallow, strict, output);
|
---|
| 4056 | }
|
---|
| 4057 | }
|
---|
| 4058 | return output;
|
---|
| 4059 | };
|
---|
| 4060 |
|
---|
| 4061 | // Flatten out an array, either recursively (by default), or just one level.
|
---|
| 4062 | _.flatten = function(array, shallow) {
|
---|
| 4063 | return flatten(array, shallow, false, []);
|
---|
| 4064 | };
|
---|
| 4065 |
|
---|
| 4066 | // Return a version of the array that does not contain the specified value(s).
|
---|
| 4067 | _.without = function(array) {
|
---|
| 4068 | return _.difference(array, slice.call(arguments, 1));
|
---|
| 4069 | };
|
---|
| 4070 |
|
---|
| 4071 | // Produce a duplicate-free version of the array. If the array has already
|
---|
| 4072 | // been sorted, you have the option of using a faster algorithm.
|
---|
| 4073 | // Aliased as `unique`.
|
---|
| 4074 | _.uniq = _.unique = function(array, isSorted, iteratee, context) {
|
---|
| 4075 | if (array == null) return [];
|
---|
| 4076 | if (!_.isBoolean(isSorted)) {
|
---|
| 4077 | context = iteratee;
|
---|
| 4078 | iteratee = isSorted;
|
---|
| 4079 | isSorted = false;
|
---|
| 4080 | }
|
---|
| 4081 | if (iteratee != null) iteratee = _.iteratee(iteratee, context);
|
---|
| 4082 | var result = [];
|
---|
| 4083 | var seen = [];
|
---|
| 4084 | for (var i = 0, length = array.length; i < length; i++) {
|
---|
| 4085 | var value = array[i];
|
---|
| 4086 | if (isSorted) {
|
---|
| 4087 | if (!i || seen !== value) result.push(value);
|
---|
| 4088 | seen = value;
|
---|
| 4089 | } else if (iteratee) {
|
---|
| 4090 | var computed = iteratee(value, i, array);
|
---|
| 4091 | if (_.indexOf(seen, computed) < 0) {
|
---|
| 4092 | seen.push(computed);
|
---|
| 4093 | result.push(value);
|
---|
| 4094 | }
|
---|
| 4095 | } else if (_.indexOf(result, value) < 0) {
|
---|
| 4096 | result.push(value);
|
---|
| 4097 | }
|
---|
| 4098 | }
|
---|
| 4099 | return result;
|
---|
| 4100 | };
|
---|
| 4101 |
|
---|
| 4102 | // Produce an array that contains the union: each distinct element from all of
|
---|
| 4103 | // the passed-in arrays.
|
---|
| 4104 | _.union = function() {
|
---|
| 4105 | return _.uniq(flatten(arguments, true, true, []));
|
---|
| 4106 | };
|
---|
| 4107 |
|
---|
| 4108 | // Produce an array that contains every item shared between all the
|
---|
| 4109 | // passed-in arrays.
|
---|
| 4110 | _.intersection = function(array) {
|
---|
| 4111 | if (array == null) return [];
|
---|
| 4112 | var result = [];
|
---|
| 4113 | var argsLength = arguments.length;
|
---|
| 4114 | for (var i = 0, length = array.length; i < length; i++) {
|
---|
| 4115 | var item = array[i];
|
---|
| 4116 | if (_.contains(result, item)) continue;
|
---|
| 4117 | for (var j = 1; j < argsLength; j++) {
|
---|
| 4118 | if (!_.contains(arguments[j], item)) break;
|
---|
| 4119 | }
|
---|
| 4120 | if (j === argsLength) result.push(item);
|
---|
| 4121 | }
|
---|
| 4122 | return result;
|
---|
| 4123 | };
|
---|
| 4124 |
|
---|
| 4125 | // Take the difference between one array and a number of other arrays.
|
---|
| 4126 | // Only the elements present in just the first array will remain.
|
---|
| 4127 | _.difference = function(array) {
|
---|
| 4128 | var rest = flatten(slice.call(arguments, 1), true, true, []);
|
---|
| 4129 | return _.filter(array, function(value){
|
---|
| 4130 | return !_.contains(rest, value);
|
---|
| 4131 | });
|
---|
| 4132 | };
|
---|
| 4133 |
|
---|
| 4134 | // Zip together multiple lists into a single array -- elements that share
|
---|
| 4135 | // an index go together.
|
---|
| 4136 | _.zip = function(array) {
|
---|
| 4137 | if (array == null) return [];
|
---|
| 4138 | var length = _.max(arguments, 'length').length;
|
---|
| 4139 | var results = Array(length);
|
---|
| 4140 | for (var i = 0; i < length; i++) {
|
---|
| 4141 | results[i] = _.pluck(arguments, i);
|
---|
| 4142 | }
|
---|
| 4143 | return results;
|
---|
| 4144 | };
|
---|
| 4145 |
|
---|
| 4146 | // Converts lists into objects. Pass either a single array of `[key, value]`
|
---|
| 4147 | // pairs, or two parallel arrays of the same length -- one of keys, and one of
|
---|
| 4148 | // the corresponding values.
|
---|
| 4149 | _.object = function(list, values) {
|
---|
| 4150 | if (list == null) return {};
|
---|
| 4151 | var result = {};
|
---|
| 4152 | for (var i = 0, length = list.length; i < length; i++) {
|
---|
| 4153 | if (values) {
|
---|
| 4154 | result[list[i]] = values[i];
|
---|
| 4155 | } else {
|
---|
| 4156 | result[list[i][0]] = list[i][1];
|
---|
| 4157 | }
|
---|
| 4158 | }
|
---|
| 4159 | return result;
|
---|
| 4160 | };
|
---|
| 4161 |
|
---|
| 4162 | // Return the position of the first occurrence of an item in an array,
|
---|
| 4163 | // or -1 if the item is not included in the array.
|
---|
| 4164 | // If the array is large and already in sort order, pass `true`
|
---|
| 4165 | // for **isSorted** to use binary search.
|
---|
| 4166 | _.indexOf = function(array, item, isSorted) {
|
---|
| 4167 | if (array == null) return -1;
|
---|
| 4168 | var i = 0, length = array.length;
|
---|
| 4169 | if (isSorted) {
|
---|
| 4170 | if (typeof isSorted == 'number') {
|
---|
| 4171 | i = isSorted < 0 ? Math.max(0, length + isSorted) : isSorted;
|
---|
| 4172 | } else {
|
---|
| 4173 | i = _.sortedIndex(array, item);
|
---|
| 4174 | return array[i] === item ? i : -1;
|
---|
| 4175 | }
|
---|
| 4176 | }
|
---|
| 4177 | for (; i < length; i++) if (array[i] === item) return i;
|
---|
| 4178 | return -1;
|
---|
| 4179 | };
|
---|
| 4180 |
|
---|
| 4181 | _.lastIndexOf = function(array, item, from) {
|
---|
| 4182 | if (array == null) return -1;
|
---|
| 4183 | var idx = array.length;
|
---|
| 4184 | if (typeof from == 'number') {
|
---|
| 4185 | idx = from < 0 ? idx + from + 1 : Math.min(idx, from + 1);
|
---|
| 4186 | }
|
---|
| 4187 | while (--idx >= 0) if (array[idx] === item) return idx;
|
---|
| 4188 | return -1;
|
---|
| 4189 | };
|
---|
| 4190 |
|
---|
| 4191 | // Generate an integer Array containing an arithmetic progression. A port of
|
---|
| 4192 | // the native Python `range()` function. See
|
---|
| 4193 | // [the Python documentation](http://docs.python.org/library/functions.html#range).
|
---|
| 4194 | _.range = function(start, stop, step) {
|
---|
| 4195 | if (arguments.length <= 1) {
|
---|
| 4196 | stop = start || 0;
|
---|
| 4197 | start = 0;
|
---|
| 4198 | }
|
---|
| 4199 | step = step || 1;
|
---|
| 4200 |
|
---|
| 4201 | var length = Math.max(Math.ceil((stop - start) / step), 0);
|
---|
| 4202 | var range = Array(length);
|
---|
| 4203 |
|
---|
| 4204 | for (var idx = 0; idx < length; idx++, start += step) {
|
---|
| 4205 | range[idx] = start;
|
---|
| 4206 | }
|
---|
| 4207 |
|
---|
| 4208 | return range;
|
---|
| 4209 | };
|
---|
| 4210 |
|
---|
| 4211 | // Function (ahem) Functions
|
---|
| 4212 | // ------------------
|
---|
| 4213 |
|
---|
| 4214 | // Reusable constructor function for prototype setting.
|
---|
| 4215 | var Ctor = function(){};
|
---|
| 4216 |
|
---|
| 4217 | // Create a function bound to a given object (assigning `this`, and arguments,
|
---|
| 4218 | // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if
|
---|
| 4219 | // available.
|
---|
| 4220 | _.bind = function(func, context) {
|
---|
| 4221 | var args, bound;
|
---|
| 4222 | if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
|
---|
| 4223 | if (!_.isFunction(func)) throw new TypeError('Bind must be called on a function');
|
---|
| 4224 | args = slice.call(arguments, 2);
|
---|
| 4225 | bound = function() {
|
---|
| 4226 | if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments)));
|
---|
| 4227 | Ctor.prototype = func.prototype;
|
---|
| 4228 | var self = new Ctor;
|
---|
| 4229 | Ctor.prototype = null;
|
---|
| 4230 | var result = func.apply(self, args.concat(slice.call(arguments)));
|
---|
| 4231 | if (_.isObject(result)) return result;
|
---|
| 4232 | return self;
|
---|
| 4233 | };
|
---|
| 4234 | return bound;
|
---|
| 4235 | };
|
---|
| 4236 |
|
---|
| 4237 | // Partially apply a function by creating a version that has had some of its
|
---|
| 4238 | // arguments pre-filled, without changing its dynamic `this` context. _ acts
|
---|
| 4239 | // as a placeholder, allowing any combination of arguments to be pre-filled.
|
---|
| 4240 | _.partial = function(func) {
|
---|
| 4241 | var boundArgs = slice.call(arguments, 1);
|
---|
| 4242 | return function() {
|
---|
| 4243 | var position = 0;
|
---|
| 4244 | var args = boundArgs.slice();
|
---|
| 4245 | for (var i = 0, length = args.length; i < length; i++) {
|
---|
| 4246 | if (args[i] === _) args[i] = arguments[position++];
|
---|
| 4247 | }
|
---|
| 4248 | while (position < arguments.length) args.push(arguments[position++]);
|
---|
| 4249 | return func.apply(this, args);
|
---|
| 4250 | };
|
---|
| 4251 | };
|
---|
| 4252 |
|
---|
| 4253 | // Bind a number of an object's methods to that object. Remaining arguments
|
---|
| 4254 | // are the method names to be bound. Useful for ensuring that all callbacks
|
---|
| 4255 | // defined on an object belong to it.
|
---|
| 4256 | _.bindAll = function(obj) {
|
---|
| 4257 | var i, length = arguments.length, key;
|
---|
| 4258 | if (length <= 1) throw new Error('bindAll must be passed function names');
|
---|
| 4259 | for (i = 1; i < length; i++) {
|
---|
| 4260 | key = arguments[i];
|
---|
| 4261 | obj[key] = _.bind(obj[key], obj);
|
---|
| 4262 | }
|
---|
| 4263 | return obj;
|
---|
| 4264 | };
|
---|
| 4265 |
|
---|
| 4266 | // Memoize an expensive function by storing its results.
|
---|
| 4267 | _.memoize = function(func, hasher) {
|
---|
| 4268 | var memoize = function(key) {
|
---|
| 4269 | var cache = memoize.cache;
|
---|
| 4270 | var address = hasher ? hasher.apply(this, arguments) : key;
|
---|
| 4271 | if (!_.has(cache, address)) cache[address] = func.apply(this, arguments);
|
---|
| 4272 | return cache[address];
|
---|
| 4273 | };
|
---|
| 4274 | memoize.cache = {};
|
---|
| 4275 | return memoize;
|
---|
| 4276 | };
|
---|
| 4277 |
|
---|
| 4278 | // Delays a function for the given number of milliseconds, and then calls
|
---|
| 4279 | // it with the arguments supplied.
|
---|
| 4280 | _.delay = function(func, wait) {
|
---|
| 4281 | var args = slice.call(arguments, 2);
|
---|
| 4282 | return setTimeout(function(){
|
---|
| 4283 | return func.apply(null, args);
|
---|
| 4284 | }, wait);
|
---|
| 4285 | };
|
---|
| 4286 |
|
---|
| 4287 | // Defers a function, scheduling it to run after the current call stack has
|
---|
| 4288 | // cleared.
|
---|
| 4289 | _.defer = function(func) {
|
---|
| 4290 | return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1)));
|
---|
| 4291 | };
|
---|
| 4292 |
|
---|
| 4293 | // Returns a function, that, when invoked, will only be triggered at most once
|
---|
| 4294 | // during a given window of time. Normally, the throttled function will run
|
---|
| 4295 | // as much as it can, without ever going more than once per `wait` duration;
|
---|
| 4296 | // but if you'd like to disable the execution on the leading edge, pass
|
---|
| 4297 | // `{leading: false}`. To disable execution on the trailing edge, ditto.
|
---|
| 4298 | _.throttle = function(func, wait, options) {
|
---|
| 4299 | var context, args, result;
|
---|
| 4300 | var timeout = null;
|
---|
| 4301 | var previous = 0;
|
---|
| 4302 | if (!options) options = {};
|
---|
| 4303 | var later = function() {
|
---|
| 4304 | previous = options.leading === false ? 0 : _.now();
|
---|
| 4305 | timeout = null;
|
---|
| 4306 | result = func.apply(context, args);
|
---|
| 4307 | if (!timeout) context = args = null;
|
---|
| 4308 | };
|
---|
| 4309 | return function() {
|
---|
| 4310 | var now = _.now();
|
---|
| 4311 | if (!previous && options.leading === false) previous = now;
|
---|
| 4312 | var remaining = wait - (now - previous);
|
---|
| 4313 | context = this;
|
---|
| 4314 | args = arguments;
|
---|
| 4315 | if (remaining <= 0 || remaining > wait) {
|
---|
| 4316 | clearTimeout(timeout);
|
---|
| 4317 | timeout = null;
|
---|
| 4318 | previous = now;
|
---|
| 4319 | result = func.apply(context, args);
|
---|
| 4320 | if (!timeout) context = args = null;
|
---|
| 4321 | } else if (!timeout && options.trailing !== false) {
|
---|
| 4322 | timeout = setTimeout(later, remaining);
|
---|
| 4323 | }
|
---|
| 4324 | return result;
|
---|
| 4325 | };
|
---|
| 4326 | };
|
---|
| 4327 |
|
---|
| 4328 | // Returns a function, that, as long as it continues to be invoked, will not
|
---|
| 4329 | // be triggered. The function will be called after it stops being called for
|
---|
| 4330 | // N milliseconds. If `immediate` is passed, trigger the function on the
|
---|
| 4331 | // leading edge, instead of the trailing.
|
---|
| 4332 | _.debounce = function(func, wait, immediate) {
|
---|
| 4333 | var timeout, args, context, timestamp, result;
|
---|
| 4334 |
|
---|
| 4335 | var later = function() {
|
---|
| 4336 | var last = _.now() - timestamp;
|
---|
| 4337 |
|
---|
| 4338 | if (last < wait && last > 0) {
|
---|
| 4339 | timeout = setTimeout(later, wait - last);
|
---|
| 4340 | } else {
|
---|
| 4341 | timeout = null;
|
---|
| 4342 | if (!immediate) {
|
---|
| 4343 | result = func.apply(context, args);
|
---|
| 4344 | if (!timeout) context = args = null;
|
---|
| 4345 | }
|
---|
| 4346 | }
|
---|
| 4347 | };
|
---|
| 4348 |
|
---|
| 4349 | return function() {
|
---|
| 4350 | context = this;
|
---|
| 4351 | args = arguments;
|
---|
| 4352 | timestamp = _.now();
|
---|
| 4353 | var callNow = immediate && !timeout;
|
---|
| 4354 | if (!timeout) timeout = setTimeout(later, wait);
|
---|
| 4355 | if (callNow) {
|
---|
| 4356 | result = func.apply(context, args);
|
---|
| 4357 | context = args = null;
|
---|
| 4358 | }
|
---|
| 4359 |
|
---|
| 4360 | return result;
|
---|
| 4361 | };
|
---|
| 4362 | };
|
---|
| 4363 |
|
---|
| 4364 | // Returns the first function passed as an argument to the second,
|
---|
| 4365 | // allowing you to adjust arguments, run code before and after, and
|
---|
| 4366 | // conditionally execute the original function.
|
---|
| 4367 | _.wrap = function(func, wrapper) {
|
---|
| 4368 | return _.partial(wrapper, func);
|
---|
| 4369 | };
|
---|
| 4370 |
|
---|
| 4371 | // Returns a negated version of the passed-in predicate.
|
---|
| 4372 | _.negate = function(predicate) {
|
---|
| 4373 | return function() {
|
---|
| 4374 | return !predicate.apply(this, arguments);
|
---|
| 4375 | };
|
---|
| 4376 | };
|
---|
| 4377 |
|
---|
| 4378 | // Returns a function that is the composition of a list of functions, each
|
---|
| 4379 | // consuming the return value of the function that follows.
|
---|
| 4380 | _.compose = function() {
|
---|
| 4381 | var args = arguments;
|
---|
| 4382 | var start = args.length - 1;
|
---|
| 4383 | return function() {
|
---|
| 4384 | var i = start;
|
---|
| 4385 | var result = args[start].apply(this, arguments);
|
---|
| 4386 | while (i--) result = args[i].call(this, result);
|
---|
| 4387 | return result;
|
---|
| 4388 | };
|
---|
| 4389 | };
|
---|
| 4390 |
|
---|
| 4391 | // Returns a function that will only be executed after being called N times.
|
---|
| 4392 | _.after = function(times, func) {
|
---|
| 4393 | return function() {
|
---|
| 4394 | if (--times < 1) {
|
---|
| 4395 | return func.apply(this, arguments);
|
---|
| 4396 | }
|
---|
| 4397 | };
|
---|
| 4398 | };
|
---|
| 4399 |
|
---|
| 4400 | // Returns a function that will only be executed before being called N times.
|
---|
| 4401 | _.before = function(times, func) {
|
---|
| 4402 | var memo;
|
---|
| 4403 | return function() {
|
---|
| 4404 | if (--times > 0) {
|
---|
| 4405 | memo = func.apply(this, arguments);
|
---|
| 4406 | } else {
|
---|
| 4407 | func = null;
|
---|
| 4408 | }
|
---|
| 4409 | return memo;
|
---|
| 4410 | };
|
---|
| 4411 | };
|
---|
| 4412 |
|
---|
| 4413 | // Returns a function that will be executed at most one time, no matter how
|
---|
| 4414 | // often you call it. Useful for lazy initialization.
|
---|
| 4415 | _.once = _.partial(_.before, 2);
|
---|
| 4416 |
|
---|
| 4417 | // Object Functions
|
---|
| 4418 | // ----------------
|
---|
| 4419 |
|
---|
| 4420 | // Retrieve the names of an object's properties.
|
---|
| 4421 | // Delegates to **ECMAScript 5**'s native `Object.keys`
|
---|
| 4422 | _.keys = function(obj) {
|
---|
| 4423 | if (!_.isObject(obj)) return [];
|
---|
| 4424 | if (nativeKeys) return nativeKeys(obj);
|
---|
| 4425 | var keys = [];
|
---|
| 4426 | for (var key in obj) if (_.has(obj, key)) keys.push(key);
|
---|
| 4427 | return keys;
|
---|
| 4428 | };
|
---|
| 4429 |
|
---|
| 4430 | // Retrieve the values of an object's properties.
|
---|
| 4431 | _.values = function(obj) {
|
---|
| 4432 | var keys = _.keys(obj);
|
---|
| 4433 | var length = keys.length;
|
---|
| 4434 | var values = Array(length);
|
---|
| 4435 | for (var i = 0; i < length; i++) {
|
---|
| 4436 | values[i] = obj[keys[i]];
|
---|
| 4437 | }
|
---|
| 4438 | return values;
|
---|
| 4439 | };
|
---|
| 4440 |
|
---|
| 4441 | // Convert an object into a list of `[key, value]` pairs.
|
---|
| 4442 | _.pairs = function(obj) {
|
---|
| 4443 | var keys = _.keys(obj);
|
---|
| 4444 | var length = keys.length;
|
---|
| 4445 | var pairs = Array(length);
|
---|
| 4446 | for (var i = 0; i < length; i++) {
|
---|
| 4447 | pairs[i] = [keys[i], obj[keys[i]]];
|
---|
| 4448 | }
|
---|
| 4449 | return pairs;
|
---|
| 4450 | };
|
---|
| 4451 |
|
---|
| 4452 | // Invert the keys and values of an object. The values must be serializable.
|
---|
| 4453 | _.invert = function(obj) {
|
---|
| 4454 | var result = {};
|
---|
| 4455 | var keys = _.keys(obj);
|
---|
| 4456 | for (var i = 0, length = keys.length; i < length; i++) {
|
---|
| 4457 | result[obj[keys[i]]] = keys[i];
|
---|
| 4458 | }
|
---|
| 4459 | return result;
|
---|
| 4460 | };
|
---|
| 4461 |
|
---|
| 4462 | // Return a sorted list of the function names available on the object.
|
---|
| 4463 | // Aliased as `methods`
|
---|
| 4464 | _.functions = _.methods = function(obj) {
|
---|
| 4465 | var names = [];
|
---|
| 4466 | for (var key in obj) {
|
---|
| 4467 | if (_.isFunction(obj[key])) names.push(key);
|
---|
| 4468 | }
|
---|
| 4469 | return names.sort();
|
---|
| 4470 | };
|
---|
| 4471 |
|
---|
| 4472 | // Extend a given object with all the properties in passed-in object(s).
|
---|
| 4473 | _.extend = function(obj) {
|
---|
| 4474 | if (!_.isObject(obj)) return obj;
|
---|
| 4475 | var source, prop;
|
---|
| 4476 | for (var i = 1, length = arguments.length; i < length; i++) {
|
---|
| 4477 | source = arguments[i];
|
---|
| 4478 | for (prop in source) {
|
---|
| 4479 | if (hasOwnProperty.call(source, prop)) {
|
---|
| 4480 | obj[prop] = source[prop];
|
---|
| 4481 | }
|
---|
| 4482 | }
|
---|
| 4483 | }
|
---|
| 4484 | return obj;
|
---|
| 4485 | };
|
---|
| 4486 |
|
---|
| 4487 | // Return a copy of the object only containing the whitelisted properties.
|
---|
| 4488 | _.pick = function(obj, iteratee, context) {
|
---|
| 4489 | var result = {}, key;
|
---|
| 4490 | if (obj == null) return result;
|
---|
| 4491 | if (_.isFunction(iteratee)) {
|
---|
| 4492 | iteratee = createCallback(iteratee, context);
|
---|
| 4493 | for (key in obj) {
|
---|
| 4494 | var value = obj[key];
|
---|
| 4495 | if (iteratee(value, key, obj)) result[key] = value;
|
---|
| 4496 | }
|
---|
| 4497 | } else {
|
---|
| 4498 | var keys = concat.apply([], slice.call(arguments, 1));
|
---|
| 4499 | obj = new Object(obj);
|
---|
| 4500 | for (var i = 0, length = keys.length; i < length; i++) {
|
---|
| 4501 | key = keys[i];
|
---|
| 4502 | if (key in obj) result[key] = obj[key];
|
---|
| 4503 | }
|
---|
| 4504 | }
|
---|
| 4505 | return result;
|
---|
| 4506 | };
|
---|
| 4507 |
|
---|
| 4508 | // Return a copy of the object without the blacklisted properties.
|
---|
| 4509 | _.omit = function(obj, iteratee, context) {
|
---|
| 4510 | if (_.isFunction(iteratee)) {
|
---|
| 4511 | iteratee = _.negate(iteratee);
|
---|
| 4512 | } else {
|
---|
| 4513 | var keys = _.map(concat.apply([], slice.call(arguments, 1)), String);
|
---|
| 4514 | iteratee = function(value, key) {
|
---|
| 4515 | return !_.contains(keys, key);
|
---|
| 4516 | };
|
---|
| 4517 | }
|
---|
| 4518 | return _.pick(obj, iteratee, context);
|
---|
| 4519 | };
|
---|
| 4520 |
|
---|
| 4521 | // Fill in a given object with default properties.
|
---|
| 4522 | _.defaults = function(obj) {
|
---|
| 4523 | if (!_.isObject(obj)) return obj;
|
---|
| 4524 | for (var i = 1, length = arguments.length; i < length; i++) {
|
---|
| 4525 | var source = arguments[i];
|
---|
| 4526 | for (var prop in source) {
|
---|
| 4527 | if (obj[prop] === void 0) obj[prop] = source[prop];
|
---|
| 4528 | }
|
---|
| 4529 | }
|
---|
| 4530 | return obj;
|
---|
| 4531 | };
|
---|
| 4532 |
|
---|
| 4533 | // Create a (shallow-cloned) duplicate of an object.
|
---|
| 4534 | _.clone = function(obj) {
|
---|
| 4535 | if (!_.isObject(obj)) return obj;
|
---|
| 4536 | return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
|
---|
| 4537 | };
|
---|
| 4538 |
|
---|
| 4539 | // Invokes interceptor with the obj, and then returns obj.
|
---|
| 4540 | // The primary purpose of this method is to "tap into" a method chain, in
|
---|
| 4541 | // order to perform operations on intermediate results within the chain.
|
---|
| 4542 | _.tap = function(obj, interceptor) {
|
---|
| 4543 | interceptor(obj);
|
---|
| 4544 | return obj;
|
---|
| 4545 | };
|
---|
| 4546 |
|
---|
| 4547 | // Internal recursive comparison function for `isEqual`.
|
---|
| 4548 | var eq = function(a, b, aStack, bStack) {
|
---|
| 4549 | // Identical objects are equal. `0 === -0`, but they aren't identical.
|
---|
| 4550 | // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).
|
---|
| 4551 | if (a === b) return a !== 0 || 1 / a === 1 / b;
|
---|
| 4552 | // A strict comparison is necessary because `null == undefined`.
|
---|
| 4553 | if (a == null || b == null) return a === b;
|
---|
| 4554 | // Unwrap any wrapped objects.
|
---|
| 4555 | if (a instanceof _) a = a._wrapped;
|
---|
| 4556 | if (b instanceof _) b = b._wrapped;
|
---|
| 4557 | // Compare `[[Class]]` names.
|
---|
| 4558 | var className = toString.call(a);
|
---|
| 4559 | if (className !== toString.call(b)) return false;
|
---|
| 4560 | switch (className) {
|
---|
| 4561 | // Strings, numbers, regular expressions, dates, and booleans are compared by value.
|
---|
| 4562 | case '[object RegExp]':
|
---|
| 4563 | // RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i')
|
---|
| 4564 | case '[object String]':
|
---|
| 4565 | // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
|
---|
| 4566 | // equivalent to `new String("5")`.
|
---|
| 4567 | return '' + a === '' + b;
|
---|
| 4568 | case '[object Number]':
|
---|
| 4569 | // `NaN`s are equivalent, but non-reflexive.
|
---|
| 4570 | // Object(NaN) is equivalent to NaN
|
---|
| 4571 | if (+a !== +a) return +b !== +b;
|
---|
| 4572 | // An `egal` comparison is performed for other numeric values.
|
---|
| 4573 | return +a === 0 ? 1 / +a === 1 / b : +a === +b;
|
---|
| 4574 | case '[object Date]':
|
---|
| 4575 | case '[object Boolean]':
|
---|
| 4576 | // Coerce dates and booleans to numeric primitive values. Dates are compared by their
|
---|
| 4577 | // millisecond representations. Note that invalid dates with millisecond representations
|
---|
| 4578 | // of `NaN` are not equivalent.
|
---|
| 4579 | return +a === +b;
|
---|
| 4580 | }
|
---|
| 4581 | if (typeof a != 'object' || typeof b != 'object') return false;
|
---|
| 4582 | // Assume equality for cyclic structures. The algorithm for detecting cyclic
|
---|
| 4583 | // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
|
---|
| 4584 | var length = aStack.length;
|
---|
| 4585 | while (length--) {
|
---|
| 4586 | // Linear search. Performance is inversely proportional to the number of
|
---|
| 4587 | // unique nested structures.
|
---|
| 4588 | if (aStack[length] === a) return bStack[length] === b;
|
---|
| 4589 | }
|
---|
| 4590 | // Objects with different constructors are not equivalent, but `Object`s
|
---|
| 4591 | // from different frames are.
|
---|
| 4592 | var aCtor = a.constructor, bCtor = b.constructor;
|
---|
| 4593 | if (
|
---|
| 4594 | aCtor !== bCtor &&
|
---|
| 4595 | // Handle Object.create(x) cases
|
---|
| 4596 | 'constructor' in a && 'constructor' in b &&
|
---|
| 4597 | !(_.isFunction(aCtor) && aCtor instanceof aCtor &&
|
---|
| 4598 | _.isFunction(bCtor) && bCtor instanceof bCtor)
|
---|
| 4599 | ) {
|
---|
| 4600 | return false;
|
---|
| 4601 | }
|
---|
| 4602 | // Add the first object to the stack of traversed objects.
|
---|
| 4603 | aStack.push(a);
|
---|
| 4604 | bStack.push(b);
|
---|
| 4605 | var size, result;
|
---|
| 4606 | // Recursively compare objects and arrays.
|
---|
| 4607 | if (className === '[object Array]') {
|
---|
| 4608 | // Compare array lengths to determine if a deep comparison is necessary.
|
---|
| 4609 | size = a.length;
|
---|
| 4610 | result = size === b.length;
|
---|
| 4611 | if (result) {
|
---|
| 4612 | // Deep compare the contents, ignoring non-numeric properties.
|
---|
| 4613 | while (size--) {
|
---|
| 4614 | if (!(result = eq(a[size], b[size], aStack, bStack))) break;
|
---|
| 4615 | }
|
---|
| 4616 | }
|
---|
| 4617 | } else {
|
---|
| 4618 | // Deep compare objects.
|
---|
| 4619 | var keys = _.keys(a), key;
|
---|
| 4620 | size = keys.length;
|
---|
| 4621 | // Ensure that both objects contain the same number of properties before comparing deep equality.
|
---|
| 4622 | result = _.keys(b).length === size;
|
---|
| 4623 | if (result) {
|
---|
| 4624 | while (size--) {
|
---|
| 4625 | // Deep compare each member
|
---|
| 4626 | key = keys[size];
|
---|
| 4627 | if (!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))) break;
|
---|
| 4628 | }
|
---|
| 4629 | }
|
---|
| 4630 | }
|
---|
| 4631 | // Remove the first object from the stack of traversed objects.
|
---|
| 4632 | aStack.pop();
|
---|
| 4633 | bStack.pop();
|
---|
| 4634 | return result;
|
---|
| 4635 | };
|
---|
| 4636 |
|
---|
| 4637 | // Perform a deep comparison to check if two objects are equal.
|
---|
| 4638 | _.isEqual = function(a, b) {
|
---|
| 4639 | return eq(a, b, [], []);
|
---|
| 4640 | };
|
---|
| 4641 |
|
---|
| 4642 | // Is a given array, string, or object empty?
|
---|
| 4643 | // An "empty" object has no enumerable own-properties.
|
---|
| 4644 | _.isEmpty = function(obj) {
|
---|
| 4645 | if (obj == null) return true;
|
---|
| 4646 | if (_.isArray(obj) || _.isString(obj) || _.isArguments(obj)) return obj.length === 0;
|
---|
| 4647 | for (var key in obj) if (_.has(obj, key)) return false;
|
---|
| 4648 | return true;
|
---|
| 4649 | };
|
---|
| 4650 |
|
---|
| 4651 | // Is a given value a DOM element?
|
---|
| 4652 | _.isElement = function(obj) {
|
---|
| 4653 | return !!(obj && obj.nodeType === 1);
|
---|
| 4654 | };
|
---|
| 4655 |
|
---|
| 4656 | // Is a given value an array?
|
---|
| 4657 | // Delegates to ECMA5's native Array.isArray
|
---|
| 4658 | _.isArray = nativeIsArray || function(obj) {
|
---|
| 4659 | return toString.call(obj) === '[object Array]';
|
---|
| 4660 | };
|
---|
| 4661 |
|
---|
| 4662 | // Is a given variable an object?
|
---|
| 4663 | _.isObject = function(obj) {
|
---|
| 4664 | var type = typeof obj;
|
---|
| 4665 | return type === 'function' || type === 'object' && !!obj;
|
---|
| 4666 | };
|
---|
| 4667 |
|
---|
| 4668 | // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp.
|
---|
| 4669 | _.each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) {
|
---|
| 4670 | _['is' + name] = function(obj) {
|
---|
| 4671 | return toString.call(obj) === '[object ' + name + ']';
|
---|
| 4672 | };
|
---|
| 4673 | });
|
---|
| 4674 |
|
---|
| 4675 | // Define a fallback version of the method in browsers (ahem, IE), where
|
---|
| 4676 | // there isn't any inspectable "Arguments" type.
|
---|
| 4677 | if (!_.isArguments(arguments)) {
|
---|
| 4678 | _.isArguments = function(obj) {
|
---|
| 4679 | return _.has(obj, 'callee');
|
---|
| 4680 | };
|
---|
| 4681 | }
|
---|
| 4682 |
|
---|
| 4683 | // Optimize `isFunction` if appropriate. Work around an IE 11 bug.
|
---|
| 4684 | if (typeof /./ !== 'function') {
|
---|
| 4685 | _.isFunction = function(obj) {
|
---|
| 4686 | return typeof obj == 'function' || false;
|
---|
| 4687 | };
|
---|
| 4688 | }
|
---|
| 4689 |
|
---|
| 4690 | // Is a given object a finite number?
|
---|
| 4691 | _.isFinite = function(obj) {
|
---|
| 4692 | return isFinite(obj) && !isNaN(parseFloat(obj));
|
---|
| 4693 | };
|
---|
| 4694 |
|
---|
| 4695 | // Is the given value `NaN`? (NaN is the only number which does not equal itself).
|
---|
| 4696 | _.isNaN = function(obj) {
|
---|
| 4697 | return _.isNumber(obj) && obj !== +obj;
|
---|
| 4698 | };
|
---|
| 4699 |
|
---|
| 4700 | // Is a given value a boolean?
|
---|
| 4701 | _.isBoolean = function(obj) {
|
---|
| 4702 | return obj === true || obj === false || toString.call(obj) === '[object Boolean]';
|
---|
| 4703 | };
|
---|
| 4704 |
|
---|
| 4705 | // Is a given value equal to null?
|
---|
| 4706 | _.isNull = function(obj) {
|
---|
| 4707 | return obj === null;
|
---|
| 4708 | };
|
---|
| 4709 |
|
---|
| 4710 | // Is a given variable undefined?
|
---|
| 4711 | _.isUndefined = function(obj) {
|
---|
| 4712 | return obj === void 0;
|
---|
| 4713 | };
|
---|
| 4714 |
|
---|
| 4715 | // Shortcut function for checking if an object has a given property directly
|
---|
| 4716 | // on itself (in other words, not on a prototype).
|
---|
| 4717 | _.has = function(obj, key) {
|
---|
| 4718 | return obj != null && hasOwnProperty.call(obj, key);
|
---|
| 4719 | };
|
---|
| 4720 |
|
---|
| 4721 | // Utility Functions
|
---|
| 4722 | // -----------------
|
---|
| 4723 |
|
---|
| 4724 | // Run Underscore.js in *noConflict* mode, returning the `_` variable to its
|
---|
| 4725 | // previous owner. Returns a reference to the Underscore object.
|
---|
| 4726 | _.noConflict = function() {
|
---|
| 4727 | root._ = previousUnderscore;
|
---|
| 4728 | return this;
|
---|
| 4729 | };
|
---|
| 4730 |
|
---|
| 4731 | // Keep the identity function around for default iteratees.
|
---|
| 4732 | _.identity = function(value) {
|
---|
| 4733 | return value;
|
---|
| 4734 | };
|
---|
| 4735 |
|
---|
| 4736 | _.constant = function(value) {
|
---|
| 4737 | return function() {
|
---|
| 4738 | return value;
|
---|
| 4739 | };
|
---|
| 4740 | };
|
---|
| 4741 |
|
---|
| 4742 | _.noop = function(){};
|
---|
| 4743 |
|
---|
| 4744 | _.property = function(key) {
|
---|
| 4745 | return function(obj) {
|
---|
| 4746 | return obj[key];
|
---|
| 4747 | };
|
---|
| 4748 | };
|
---|
| 4749 |
|
---|
| 4750 | // Returns a predicate for checking whether an object has a given set of `key:value` pairs.
|
---|
| 4751 | _.matches = function(attrs) {
|
---|
| 4752 | var pairs = _.pairs(attrs), length = pairs.length;
|
---|
| 4753 | return function(obj) {
|
---|
| 4754 | if (obj == null) return !length;
|
---|
| 4755 | obj = new Object(obj);
|
---|
| 4756 | for (var i = 0; i < length; i++) {
|
---|
| 4757 | var pair = pairs[i], key = pair[0];
|
---|
| 4758 | if (pair[1] !== obj[key] || !(key in obj)) return false;
|
---|
| 4759 | }
|
---|
| 4760 | return true;
|
---|
| 4761 | };
|
---|
| 4762 | };
|
---|
| 4763 |
|
---|
| 4764 | // Run a function **n** times.
|
---|
| 4765 | _.times = function(n, iteratee, context) {
|
---|
| 4766 | var accum = Array(Math.max(0, n));
|
---|
| 4767 | iteratee = createCallback(iteratee, context, 1);
|
---|
| 4768 | for (var i = 0; i < n; i++) accum[i] = iteratee(i);
|
---|
| 4769 | return accum;
|
---|
| 4770 | };
|
---|
| 4771 |
|
---|
| 4772 | // Return a random integer between min and max (inclusive).
|
---|
| 4773 | _.random = function(min, max) {
|
---|
| 4774 | if (max == null) {
|
---|
| 4775 | max = min;
|
---|
| 4776 | min = 0;
|
---|
| 4777 | }
|
---|
| 4778 | return min + Math.floor(Math.random() * (max - min + 1));
|
---|
| 4779 | };
|
---|
| 4780 |
|
---|
| 4781 | // A (possibly faster) way to get the current timestamp as an integer.
|
---|
| 4782 | _.now = Date.now || function() {
|
---|
| 4783 | return new Date().getTime();
|
---|
| 4784 | };
|
---|
| 4785 |
|
---|
| 4786 | // List of HTML entities for escaping.
|
---|
| 4787 | var escapeMap = {
|
---|
| 4788 | '&': '&',
|
---|
| 4789 | '<': '<',
|
---|
| 4790 | '>': '>',
|
---|
| 4791 | '"': '"',
|
---|
| 4792 | "'": ''',
|
---|
| 4793 | '`': '`'
|
---|
| 4794 | };
|
---|
| 4795 | var unescapeMap = _.invert(escapeMap);
|
---|
| 4796 |
|
---|
| 4797 | // Functions for escaping and unescaping strings to/from HTML interpolation.
|
---|
| 4798 | var createEscaper = function(map) {
|
---|
| 4799 | var escaper = function(match) {
|
---|
| 4800 | return map[match];
|
---|
| 4801 | };
|
---|
| 4802 | // Regexes for identifying a key that needs to be escaped
|
---|
| 4803 | var source = '(?:' + _.keys(map).join('|') + ')';
|
---|
| 4804 | var testRegexp = RegExp(source);
|
---|
| 4805 | var replaceRegexp = RegExp(source, 'g');
|
---|
| 4806 | return function(string) {
|
---|
| 4807 | string = string == null ? '' : '' + string;
|
---|
| 4808 | return testRegexp.test(string) ? string.replace(replaceRegexp, escaper) : string;
|
---|
| 4809 | };
|
---|
| 4810 | };
|
---|
| 4811 | _.escape = createEscaper(escapeMap);
|
---|
| 4812 | _.unescape = createEscaper(unescapeMap);
|
---|
| 4813 |
|
---|
| 4814 | // If the value of the named `property` is a function then invoke it with the
|
---|
| 4815 | // `object` as context; otherwise, return it.
|
---|
| 4816 | _.result = function(object, property) {
|
---|
| 4817 | if (object == null) return void 0;
|
---|
| 4818 | var value = object[property];
|
---|
| 4819 | return _.isFunction(value) ? object[property]() : value;
|
---|
| 4820 | };
|
---|
| 4821 |
|
---|
| 4822 | // Generate a unique integer id (unique within the entire client session).
|
---|
| 4823 | // Useful for temporary DOM ids.
|
---|
| 4824 | var idCounter = 0;
|
---|
| 4825 | _.uniqueId = function(prefix) {
|
---|
| 4826 | var id = ++idCounter + '';
|
---|
| 4827 | return prefix ? prefix + id : id;
|
---|
| 4828 | };
|
---|
| 4829 |
|
---|
| 4830 | // By default, Underscore uses ERB-style template delimiters, change the
|
---|
| 4831 | // following template settings to use alternative delimiters.
|
---|
| 4832 | _.templateSettings = {
|
---|
| 4833 | evaluate : /<%([\s\S]+?)%>/g,
|
---|
| 4834 | interpolate : /<%=([\s\S]+?)%>/g,
|
---|
| 4835 | escape : /<%-([\s\S]+?)%>/g
|
---|
| 4836 | };
|
---|
| 4837 |
|
---|
| 4838 | // When customizing `templateSettings`, if you don't want to define an
|
---|
| 4839 | // interpolation, evaluation or escaping regex, we need one that is
|
---|
| 4840 | // guaranteed not to match.
|
---|
| 4841 | var noMatch = /(.)^/;
|
---|
| 4842 |
|
---|
| 4843 | // Certain characters need to be escaped so that they can be put into a
|
---|
| 4844 | // string literal.
|
---|
| 4845 | var escapes = {
|
---|
| 4846 | "'": "'",
|
---|
| 4847 | '\\': '\\',
|
---|
| 4848 | '\r': 'r',
|
---|
| 4849 | '\n': 'n',
|
---|
| 4850 | '\u2028': 'u2028',
|
---|
| 4851 | '\u2029': 'u2029'
|
---|
| 4852 | };
|
---|
| 4853 |
|
---|
| 4854 | var escaper = /\\|'|\r|\n|\u2028|\u2029/g;
|
---|
| 4855 |
|
---|
| 4856 | var escapeChar = function(match) {
|
---|
| 4857 | return '\\' + escapes[match];
|
---|
| 4858 | };
|
---|
| 4859 |
|
---|
| 4860 | // JavaScript micro-templating, similar to John Resig's implementation.
|
---|
| 4861 | // Underscore templating handles arbitrary delimiters, preserves whitespace,
|
---|
| 4862 | // and correctly escapes quotes within interpolated code.
|
---|
| 4863 | // NB: `oldSettings` only exists for backwards compatibility.
|
---|
| 4864 | _.template = function(text, settings, oldSettings) {
|
---|
| 4865 | if (!settings && oldSettings) settings = oldSettings;
|
---|
| 4866 | settings = _.defaults({}, settings, _.templateSettings);
|
---|
| 4867 |
|
---|
| 4868 | // Combine delimiters into one regular expression via alternation.
|
---|
| 4869 | var matcher = RegExp([
|
---|
| 4870 | (settings.escape || noMatch).source,
|
---|
| 4871 | (settings.interpolate || noMatch).source,
|
---|
| 4872 | (settings.evaluate || noMatch).source
|
---|
| 4873 | ].join('|') + '|$', 'g');
|
---|
| 4874 |
|
---|
| 4875 | // Compile the template source, escaping string literals appropriately.
|
---|
| 4876 | var index = 0;
|
---|
| 4877 | var source = "__p+='";
|
---|
| 4878 | text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
|
---|
| 4879 | source += text.slice(index, offset).replace(escaper, escapeChar);
|
---|
| 4880 | index = offset + match.length;
|
---|
| 4881 |
|
---|
| 4882 | if (escape) {
|
---|
| 4883 | source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
|
---|
| 4884 | } else if (interpolate) {
|
---|
| 4885 | source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
|
---|
| 4886 | } else if (evaluate) {
|
---|
| 4887 | source += "';\n" + evaluate + "\n__p+='";
|
---|
| 4888 | }
|
---|
| 4889 |
|
---|
| 4890 | // Adobe VMs need the match returned to produce the correct offest.
|
---|
| 4891 | return match;
|
---|
| 4892 | });
|
---|
| 4893 | source += "';\n";
|
---|
| 4894 |
|
---|
| 4895 | // If a variable is not specified, place data values in local scope.
|
---|
| 4896 | if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';
|
---|
| 4897 |
|
---|
| 4898 | source = "var __t,__p='',__j=Array.prototype.join," +
|
---|
| 4899 | "print=function(){__p+=__j.call(arguments,'');};\n" +
|
---|
| 4900 | source + 'return __p;\n';
|
---|
| 4901 |
|
---|
| 4902 | try {
|
---|
| 4903 | var render = new Function(settings.variable || 'obj', '_', source);
|
---|
| 4904 | } catch (e) {
|
---|
| 4905 | e.source = source;
|
---|
| 4906 | throw e;
|
---|
| 4907 | }
|
---|
| 4908 |
|
---|
| 4909 | var template = function(data) {
|
---|
| 4910 | return render.call(this, data, _);
|
---|
| 4911 | };
|
---|
| 4912 |
|
---|
| 4913 | // Provide the compiled source as a convenience for precompilation.
|
---|
| 4914 | var argument = settings.variable || 'obj';
|
---|
| 4915 | template.source = 'function(' + argument + '){\n' + source + '}';
|
---|
| 4916 |
|
---|
| 4917 | return template;
|
---|
| 4918 | };
|
---|
| 4919 |
|
---|
| 4920 | // Add a "chain" function. Start chaining a wrapped Underscore object.
|
---|
| 4921 | _.chain = function(obj) {
|
---|
| 4922 | var instance = _(obj);
|
---|
| 4923 | instance._chain = true;
|
---|
| 4924 | return instance;
|
---|
| 4925 | };
|
---|
| 4926 |
|
---|
| 4927 | // OOP
|
---|
| 4928 | // ---------------
|
---|
| 4929 | // If Underscore is called as a function, it returns a wrapped object that
|
---|
| 4930 | // can be used OO-style. This wrapper holds altered versions of all the
|
---|
| 4931 | // underscore functions. Wrapped objects may be chained.
|
---|
| 4932 |
|
---|
| 4933 | // Helper function to continue chaining intermediate results.
|
---|
| 4934 | var result = function(obj) {
|
---|
| 4935 | return this._chain ? _(obj).chain() : obj;
|
---|
| 4936 | };
|
---|
| 4937 |
|
---|
| 4938 | // Add your own custom functions to the Underscore object.
|
---|
| 4939 | _.mixin = function(obj) {
|
---|
| 4940 | _.each(_.functions(obj), function(name) {
|
---|
| 4941 | var func = _[name] = obj[name];
|
---|
| 4942 | _.prototype[name] = function() {
|
---|
| 4943 | var args = [this._wrapped];
|
---|
| 4944 | push.apply(args, arguments);
|
---|
| 4945 | return result.call(this, func.apply(_, args));
|
---|
| 4946 | };
|
---|
| 4947 | });
|
---|
| 4948 | };
|
---|
| 4949 |
|
---|
| 4950 | // Add all of the Underscore functions to the wrapper object.
|
---|
| 4951 | _.mixin(_);
|
---|
| 4952 |
|
---|
| 4953 | // Add all mutator Array functions to the wrapper.
|
---|
| 4954 | _.each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
|
---|
| 4955 | var method = ArrayProto[name];
|
---|
| 4956 | _.prototype[name] = function() {
|
---|
| 4957 | var obj = this._wrapped;
|
---|
| 4958 | method.apply(obj, arguments);
|
---|
| 4959 | if ((name === 'shift' || name === 'splice') && obj.length === 0) delete obj[0];
|
---|
| 4960 | return result.call(this, obj);
|
---|
| 4961 | };
|
---|
| 4962 | });
|
---|
| 4963 |
|
---|
| 4964 | // Add all accessor Array functions to the wrapper.
|
---|
| 4965 | _.each(['concat', 'join', 'slice'], function(name) {
|
---|
| 4966 | var method = ArrayProto[name];
|
---|
| 4967 | _.prototype[name] = function() {
|
---|
| 4968 | return result.call(this, method.apply(this._wrapped, arguments));
|
---|
| 4969 | };
|
---|
| 4970 | });
|
---|
| 4971 |
|
---|
| 4972 | // Extracts the result from a wrapped and chained object.
|
---|
| 4973 | _.prototype.value = function() {
|
---|
| 4974 | return this._wrapped;
|
---|
| 4975 | };
|
---|
| 4976 |
|
---|
| 4977 | // AMD registration happens at the end for compatibility with AMD loaders
|
---|
| 4978 | // that may not enforce next-turn semantics on modules. Even though general
|
---|
| 4979 | // practice for AMD registration is to be anonymous, underscore registers
|
---|
| 4980 | // as a named module because, like jQuery, it is a base library that is
|
---|
| 4981 | // popular enough to be bundled in a third party lib, but not be part of
|
---|
| 4982 | // an AMD load request. Those cases could generate an error when an
|
---|
| 4983 | // anonymous define() is called outside of a loader request.
|
---|
| 4984 | if (typeof define === 'function' && define.amd) {
|
---|
| 4985 | define('underscore', [], function() {
|
---|
| 4986 | return _;
|
---|
| 4987 | });
|
---|
| 4988 | }
|
---|
| 4989 | }.call(this));
|
---|
| 4990 |
|
---|
| 4991 | },{}],17:[function(require,module,exports){
|
---|
| 4992 | // calc.js
|
---|
| 4993 | // measure calculations
|
---|
| 4994 |
|
---|
| 4995 | var _ = require('underscore');
|
---|
| 4996 | var geocrunch = require('geocrunch');
|
---|
| 4997 |
|
---|
| 4998 | var pad = function (num) {
|
---|
| 4999 | return num < 10 ? '0' + num.toString() : num.toString();
|
---|
| 5000 | };
|
---|
| 5001 |
|
---|
| 5002 | var ddToDms = function (coordinate, posSymbol, negSymbol) {
|
---|
| 5003 | var dd = Math.abs(coordinate),
|
---|
| 5004 | d = Math.floor(dd),
|
---|
| 5005 | m = Math.floor((dd - d) * 60),
|
---|
| 5006 | s = Math.round((dd - d - (m/60)) * 3600 * 100)/100,
|
---|
| 5007 | directionSymbol = dd === coordinate ? posSymbol : negSymbol;
|
---|
| 5008 | return pad(d) + '° ' + pad(m) + '\' ' + pad(s) + '" ' + directionSymbol;
|
---|
| 5009 | };
|
---|
| 5010 |
|
---|
| 5011 | var measure = function (latlngs) {
|
---|
| 5012 | var last = _.last(latlngs), feet, meters, miles, kilometers, sqMeters, acres, hectares, sqMiles;
|
---|
| 5013 | var path = geocrunch.path(_.map(latlngs, function (latlng) {
|
---|
| 5014 | return [latlng.lng, latlng.lat];
|
---|
| 5015 | }));
|
---|
| 5016 |
|
---|
| 5017 | feet = path.distance({
|
---|
| 5018 | units: 'feet'
|
---|
| 5019 | });
|
---|
| 5020 | meters = feet / 3.2808;
|
---|
| 5021 | miles = feet / 5280;
|
---|
| 5022 | kilometers = meters / 1000;
|
---|
| 5023 | sqMeters = path.area({
|
---|
| 5024 | units: 'sqmeters'
|
---|
| 5025 | });
|
---|
| 5026 | acres = sqMeters * 0.00024711;
|
---|
| 5027 | hectares = sqMeters / 10000;
|
---|
| 5028 | sqMiles = acres * 0.0015625;
|
---|
| 5029 |
|
---|
| 5030 | return {
|
---|
| 5031 | lastCoord: {
|
---|
| 5032 | dd: {
|
---|
| 5033 | x: last.lng,
|
---|
| 5034 | y: last.lat
|
---|
| 5035 | },
|
---|
| 5036 | dms: {
|
---|
| 5037 | x: ddToDms(last.lng, 'E', 'W'),
|
---|
| 5038 | y: ddToDms(last.lat, 'N', 'S')
|
---|
| 5039 | }
|
---|
| 5040 | },
|
---|
| 5041 | length: {
|
---|
| 5042 | feet: feet,
|
---|
| 5043 | meters: meters,
|
---|
| 5044 | miles: miles,
|
---|
| 5045 | kilometers: kilometers
|
---|
| 5046 | },
|
---|
| 5047 | area: {
|
---|
| 5048 | acres: acres,
|
---|
| 5049 | hectares: hectares,
|
---|
| 5050 | sqmeters: sqMeters,
|
---|
| 5051 | sqmiles: sqMiles
|
---|
| 5052 | }
|
---|
| 5053 | };
|
---|
| 5054 | };
|
---|
| 5055 |
|
---|
| 5056 | module.exports = {
|
---|
| 5057 | measure: measure // `measure(latLngArray)` - returns object with calced measurements for passed points
|
---|
| 5058 | };
|
---|
| 5059 | },{"geocrunch":6,"underscore":16}],18:[function(require,module,exports){
|
---|
| 5060 | // dom.js
|
---|
| 5061 | // utility functions for managing DOM elements
|
---|
| 5062 |
|
---|
| 5063 | var selectOne = function (selector, el) {
|
---|
| 5064 | if (!el) {
|
---|
| 5065 | el = document;
|
---|
| 5066 | }
|
---|
| 5067 | return el.querySelector(selector);
|
---|
| 5068 | };
|
---|
| 5069 |
|
---|
| 5070 | var selectAll = function (selector, el) {
|
---|
| 5071 | if (!el) {
|
---|
| 5072 | el = document;
|
---|
| 5073 | }
|
---|
| 5074 | return Array.prototype.slice.call(el.querySelectorAll(selector));
|
---|
| 5075 | };
|
---|
| 5076 |
|
---|
| 5077 | var hide = function (el) {
|
---|
| 5078 | if (el) {
|
---|
| 5079 | el.setAttribute('style', 'display:none;');
|
---|
| 5080 | return el;
|
---|
| 5081 | }
|
---|
| 5082 | };
|
---|
| 5083 |
|
---|
| 5084 | var show = function (el) {
|
---|
| 5085 | if (el) {
|
---|
| 5086 | el.removeAttribute('style');
|
---|
| 5087 | return el;
|
---|
| 5088 | }
|
---|
| 5089 | };
|
---|
| 5090 |
|
---|
| 5091 | module.exports = {
|
---|
| 5092 | $: selectOne, // `$('.myclass', baseElement)` - returns selected element or undefined
|
---|
| 5093 | $$: selectAll, // `$$('.myclass', baseElement)` - returns array of selected elements
|
---|
| 5094 | hide: hide, // `hide(someElement)` - hide passed dom element
|
---|
| 5095 | show: show // `show(someElement)` - show passed dom element
|
---|
| 5096 | };
|
---|
| 5097 | },{}],19:[function(require,module,exports){
|
---|
| 5098 | (function (global){
|
---|
| 5099 | // leaflet-measure.js
|
---|
| 5100 |
|
---|
| 5101 | var _ = require('underscore');
|
---|
| 5102 | var L = (typeof window !== "undefined" ? window.L : typeof global !== "undefined" ? global.L : null);
|
---|
| 5103 | var humanize = require('humanize');
|
---|
| 5104 |
|
---|
| 5105 | var units = require('./units');
|
---|
| 5106 | var calc = require('./calc');
|
---|
| 5107 | var dom = require('./dom');
|
---|
| 5108 | var $ = dom.$;
|
---|
| 5109 |
|
---|
| 5110 | var Symbology = require('./mapsymbology');
|
---|
| 5111 |
|
---|
| 5112 |
|
---|
| 5113 | var controlTemplate = _.template("<a class=\"<%= model.className %>-toggle js-toggle\" href=\"#\" title=\"Measure distances and areas\">Measure</a>\n<div class=\"<%= model.className %>-interaction js-interaction\">\n <div class=\"js-startprompt startprompt\">\n <h3>Measure Distances and Areas</h3>\n <ul class=\"tasks\">\n <a href=\"#\" class=\"js-start start\">Create a new measurement</a>\n </ul>\n </div>\n <div class=\"js-measuringprompt\">\n <h3>Measure Distances and Areas</h3>\n <p class=\"js-starthelp\">Start creating a measurement by adding points to the map</h3>\n <div class=\"js-results results\"></div>\n <ul class=\"js-measuretasks tasks\">\n <li><a href=\"#\" class=\"js-cancel cancel\">Cancel</a></li>\n <li><a href=\"#\" class=\"js-finish finish\">Finish Measurement</a></li>\n </ul>\n </div>\n</div>");
|
---|
| 5114 | var resultsTemplate = _.template("<div class=\"group\">\n<p class=\"lastpoint heading\">Last Point</p>\n<p><%= model.lastCoord.dms.y %> <span class=\"coorddivider\">/</span> <%= model.lastCoord.dms.x %></p>\n<p><%= humanize.numberFormat(model.lastCoord.dd.y, 6) %> <span class=\"coorddivider\">/</span> <%= humanize.numberFormat(model.lastCoord.dd.x, 6) %></p>\n</div>\n<% if (model.pointCount > 1) { %>\n<div class=\"group\">\n<p><span class=\"heading\">Path Distance</span> <%= model.lengthDisplay %></p>\n</div>\n<% } %>\n<% if (model.pointCount > 2) { %>\n<div class=\"group\">\n<p><span class=\"heading\">Area</span> <%= model.areaDisplay %></p>\n</div>\n<% } %>");
|
---|
| 5115 | var pointPopupTemplate = _.template("<h3>Point Location</h3>\n<p><%= model.lastCoord.dms.y %> <span class=\"coorddivider\">/</span> <%= model.lastCoord.dms.x %></p>\n<p><%= humanize.numberFormat(model.lastCoord.dd.y, 6) %> <span class=\"coorddivider\">/</span> <%= humanize.numberFormat(model.lastCoord.dd.x, 6) %></p>\n<ul class=\"tasks\">\n <li><a href=\"#\" class=\"js-zoomto zoomto\">Center on this Location</a></li>\n <li><a href=\"#\" class=\"js-deletemarkup deletemarkup\">Delete</a></li>\n</ul>");
|
---|
| 5116 | var linePopupTemplate = _.template("<h3>Linear Measurement</h3>\n<p><%= model.lengthDisplay %></p>\n<ul class=\"tasks\">\n <li><a href=\"#\" class=\"js-zoomto zoomto\">Center on this Line</a></li>\n <li><a href=\"#\" class=\"js-deletemarkup deletemarkup\">Delete</a></li>\n</ul>");
|
---|
| 5117 | var areaPopupTemplate = _.template("<h3>Area Measurement</h3>\n<p><%= model.areaDisplay %></p>\n<p><%= model.lengthDisplay %> Perimeter</p>\n<ul class=\"tasks\">\n <li><a href=\"#\" class=\"js-zoomto zoomto\">Center on this Area</a></li>\n <li><a href=\"#\" class=\"js-deletemarkup deletemarkup\">Delete</a></li>\n</ul>");
|
---|
| 5118 |
|
---|
| 5119 | L.Control.Measure = L.Control.extend({
|
---|
| 5120 | _className: 'leaflet-control-measure',
|
---|
| 5121 | options: {
|
---|
| 5122 | position: 'topright',
|
---|
| 5123 | primaryLengthUnit: 'feet',
|
---|
| 5124 | secondaryLengthUnit: 'miles',
|
---|
| 5125 | primaryAreaUnit: 'acres',
|
---|
| 5126 | activeColor: '#ABE67E', // base color for map features while actively measuring
|
---|
| 5127 | completedColor: '#C8F2BE', // base color for permenant features generated from completed measure
|
---|
| 5128 | popupOptions: { // standard leaflet popup options http://leafletjs.com/reference.html#popup-options
|
---|
| 5129 | className: 'leaflet-measure-resultpopup',
|
---|
| 5130 | autoPanPadding: [10, 10]
|
---|
| 5131 | }
|
---|
| 5132 | },
|
---|
| 5133 | initialize: function (options) {
|
---|
| 5134 | L.setOptions(this, options);
|
---|
| 5135 | this._symbols = new Symbology(_.pick(this.options, 'activeColor', 'completedColor'));
|
---|
| 5136 | },
|
---|
| 5137 | onAdd: function (map) {
|
---|
| 5138 | this._map = map;
|
---|
| 5139 | this._latlngs = [];
|
---|
| 5140 | this._initLayout();
|
---|
| 5141 | map.on('click', this._collapse, this);
|
---|
| 5142 | this._layer = L.layerGroup().addTo(map);
|
---|
| 5143 | return this._container;
|
---|
| 5144 | },
|
---|
| 5145 | onRemove: function (map) {
|
---|
| 5146 | map.off('click', this._collapse, this);
|
---|
| 5147 | map.removeLayer(this._layer);
|
---|
| 5148 | },
|
---|
| 5149 | _initLayout: function () {
|
---|
| 5150 | var className = this._className, container = this._container = L.DomUtil.create('div', className);
|
---|
| 5151 | var $toggle, $start, $cancel, $finish;
|
---|
| 5152 |
|
---|
| 5153 | container.innerHTML = controlTemplate({
|
---|
| 5154 | model: {
|
---|
| 5155 | className: className
|
---|
| 5156 | }
|
---|
| 5157 | });
|
---|
| 5158 |
|
---|
| 5159 | // copied from leaflet
|
---|
| 5160 | // https://bitbucket.org/ljagis/js-mapbootstrap/src/4ab1e9e896c08bdbc8164d4053b2f945143f4f3a/app/components/measure/leaflet-measure-control.js?at=master#cl-30
|
---|
| 5161 | container.setAttribute('aria-haspopup', true);
|
---|
| 5162 | if (!L.Browser.touch) {
|
---|
| 5163 | L.DomEvent.disableClickPropagation(container);
|
---|
| 5164 | L.DomEvent.disableScrollPropagation(container);
|
---|
| 5165 | } else {
|
---|
| 5166 | L.DomEvent.on(container, 'click', L.DomEvent.stopPropagation);
|
---|
| 5167 | }
|
---|
| 5168 |
|
---|
| 5169 | $toggle = this.$toggle = $('.js-toggle', container); // collapsed content
|
---|
| 5170 | this.$interaction = $('.js-interaction', container); // expanded content
|
---|
| 5171 | $start = $('.js-start', container); // start button
|
---|
| 5172 | $cancel = $('.js-cancel', container); // cancel button
|
---|
| 5173 | $finish = $('.js-finish', container); // finish button
|
---|
| 5174 | this.$startPrompt = $('.js-startprompt', container); // full area with button to start measurment
|
---|
| 5175 | this.$measuringPrompt = $('.js-measuringprompt', container); // full area with all stuff for active measurement
|
---|
| 5176 | this.$startHelp = $('.js-starthelp', container); // "Start creating a measurement by adding points"
|
---|
| 5177 | this.$results = $('.js-results', container); // div with coordinate, linear, area results
|
---|
| 5178 | this.$measureTasks = $('.js-measuretasks', container); // active measure buttons container
|
---|
| 5179 |
|
---|
| 5180 | this._collapse();
|
---|
| 5181 | this._updateMeasureNotStarted();
|
---|
| 5182 |
|
---|
| 5183 | if (!L.Browser.android) {
|
---|
| 5184 | L.DomEvent.on(container, 'mouseenter', this._expand, this);
|
---|
| 5185 | L.DomEvent.on(container, 'mouseleave', this._collapse, this);
|
---|
| 5186 | }
|
---|
| 5187 | L.DomEvent.on($toggle, 'click', L.DomEvent.stop);
|
---|
| 5188 | if (L.Browser.touch) {
|
---|
| 5189 | L.DomEvent.on($toggle, 'click', this._expand, this);
|
---|
| 5190 | } else {
|
---|
| 5191 | L.DomEvent.on($toggle, 'focus', this._expand, this);
|
---|
| 5192 | }
|
---|
| 5193 | L.DomEvent.on($start, 'click', L.DomEvent.stop);
|
---|
| 5194 | L.DomEvent.on($start, 'click', this._startMeasure, this);
|
---|
| 5195 | L.DomEvent.on($cancel, 'click', L.DomEvent.stop);
|
---|
| 5196 | L.DomEvent.on($cancel, 'click', this._finishMeasure, this);
|
---|
| 5197 | L.DomEvent.on($finish, 'click', L.DomEvent.stop);
|
---|
| 5198 | L.DomEvent.on($finish, 'click', this._handleMeasureDoubleClick, this);
|
---|
| 5199 | },
|
---|
| 5200 | _expand: function () {
|
---|
| 5201 | dom.hide(this.$toggle);
|
---|
| 5202 | dom.show(this.$interaction);
|
---|
| 5203 | },
|
---|
| 5204 | _collapse: function () {
|
---|
| 5205 | if (!this._locked) {
|
---|
| 5206 | dom.hide(this.$interaction);
|
---|
| 5207 | dom.show(this.$toggle);
|
---|
| 5208 | }
|
---|
| 5209 | },
|
---|
| 5210 | // move between basic states:
|
---|
| 5211 | // measure not started, started/in progress but no points added, in progress and with points
|
---|
| 5212 | _updateMeasureNotStarted: function () {
|
---|
| 5213 | dom.hide(this.$startHelp);
|
---|
| 5214 | dom.hide(this.$results);
|
---|
| 5215 | dom.hide(this.$measureTasks);
|
---|
| 5216 | dom.hide(this.$measuringPrompt);
|
---|
| 5217 | dom.show(this.$startPrompt);
|
---|
| 5218 | },
|
---|
| 5219 | _updateMeasureStartedNoPoints: function () {
|
---|
| 5220 | dom.hide(this.$results);
|
---|
| 5221 | dom.show(this.$startHelp);
|
---|
| 5222 | dom.show(this.$measureTasks);
|
---|
| 5223 | dom.hide(this.$startPrompt);
|
---|
| 5224 | dom.show(this.$measuringPrompt);
|
---|
| 5225 | },
|
---|
| 5226 | _updateMeasureStartedWithPoints: function () {
|
---|
| 5227 | dom.hide(this.$startHelp);
|
---|
| 5228 | dom.show(this.$results);
|
---|
| 5229 | dom.show(this.$measureTasks);
|
---|
| 5230 | dom.hide(this.$startPrompt);
|
---|
| 5231 | dom.show(this.$measuringPrompt);
|
---|
| 5232 | },
|
---|
| 5233 | // get state vars and interface ready for measure
|
---|
| 5234 | _startMeasure: function () {
|
---|
| 5235 | this._locked = true;
|
---|
| 5236 |
|
---|
| 5237 | this._map.doubleClickZoom.disable(); // double click now finishes measure
|
---|
| 5238 | this._map.on('mouseout', this._handleMapMouseOut, this);
|
---|
| 5239 |
|
---|
| 5240 | L.DomEvent.on(this._container, 'mouseenter', this._handleMapMouseOut, this);
|
---|
| 5241 |
|
---|
| 5242 | if (!this._measureCollector) {
|
---|
| 5243 | // polygon to cover all other layers and collection measure move and click events
|
---|
| 5244 | this._measureCollector = L.polygon([[90, -180], [90, 180], [-90, 180], [-90, -180]], this._symbols.getSymbol('measureCollector')).addTo(this._layer);
|
---|
| 5245 | this._measureCollector.on('mousemove', this._handleMeasureMove, this);
|
---|
| 5246 | this._measureCollector.on('dblclick', this._handleMeasureDoubleClick, this);
|
---|
| 5247 | this._measureCollector.on('click', this._handleMeasureClick, this);
|
---|
| 5248 | }
|
---|
| 5249 | this._measureCollector.bringToFront();
|
---|
| 5250 |
|
---|
| 5251 | this._measureVertexes = L.featureGroup().addTo(this._layer);
|
---|
| 5252 |
|
---|
| 5253 | this._updateMeasureStartedNoPoints();
|
---|
| 5254 | },
|
---|
| 5255 | // return to state with no measure in progress, undo `this._startMeasure`
|
---|
| 5256 | _finishMeasure: function () {
|
---|
| 5257 | this._locked = false;
|
---|
| 5258 |
|
---|
| 5259 | this._map.doubleClickZoom.enable();
|
---|
| 5260 | this._map.off('mouseout', this._handleMapMouseOut, this);
|
---|
| 5261 |
|
---|
| 5262 | L.DomEvent.off(this._container, 'mouseover', this._handleMapMouseOut, this);
|
---|
| 5263 |
|
---|
| 5264 | this._clearMeasure();
|
---|
| 5265 |
|
---|
| 5266 | this._measureCollector.off();
|
---|
| 5267 | this._layer.removeLayer(this._measureCollector);
|
---|
| 5268 | this._measureCollector = null;
|
---|
| 5269 |
|
---|
| 5270 | this._layer.removeLayer(this._measureVertexes);
|
---|
| 5271 | this._measureVertexes = null;
|
---|
| 5272 |
|
---|
| 5273 | this._updateMeasureNotStarted();
|
---|
| 5274 | this._collapse();
|
---|
| 5275 | },
|
---|
| 5276 | // clear all running measure data
|
---|
| 5277 | _clearMeasure: function () {
|
---|
| 5278 | this._latlngs = [];
|
---|
| 5279 | this._measureVertexes.clearLayers();
|
---|
| 5280 | if (this._measureDrag) {
|
---|
| 5281 | this._layer.removeLayer(this._measureDrag);
|
---|
| 5282 | }
|
---|
| 5283 | if (this._measureArea) {
|
---|
| 5284 | this._layer.removeLayer(this._measureArea);
|
---|
| 5285 | }
|
---|
| 5286 | if (this._measureBoundary) {
|
---|
| 5287 | this._layer.removeLayer(this._measureBoundary);
|
---|
| 5288 | }
|
---|
| 5289 | this._measureDrag = null;
|
---|
| 5290 | this._measureArea = null;
|
---|
| 5291 | this._measureBoundary = null;
|
---|
| 5292 | },
|
---|
| 5293 | // format measurements to nice display string based on units in options. `{ lengthDisplay: '100 Feet (0.02 Miles)', areaDisplay: ... }`
|
---|
| 5294 | _getMeasurementDisplayStrings: function (measurement) {
|
---|
| 5295 | var result = {};
|
---|
| 5296 | if (this.options.primaryLengthUnit && units[this.options.primaryLengthUnit]) {
|
---|
| 5297 | result.lengthDisplay = humanize.numberFormat(measurement.length[this.options.primaryLengthUnit], units[this.options.primaryLengthUnit].decimals) + ' ' + units[this.options.primaryLengthUnit].display;
|
---|
| 5298 | if (this.options.secondaryLengthUnit && units[this.options.secondaryLengthUnit]) {
|
---|
| 5299 | result.lengthDisplay = result.lengthDisplay + ' (' + humanize.numberFormat(measurement.length[this.options.secondaryLengthUnit], units[this.options.secondaryLengthUnit].decimals) + ' ' + units[this.options.secondaryLengthUnit].display + ')';
|
---|
| 5300 | }
|
---|
| 5301 | }
|
---|
| 5302 | if (this.options.primaryAreaUnit && units[this.options.primaryAreaUnit]) {
|
---|
| 5303 | result.areaDisplay = humanize.numberFormat(measurement.area[this.options.primaryAreaUnit], units[this.options.primaryAreaUnit].decimals) + ' ' + units[this.options.primaryAreaUnit].display;
|
---|
| 5304 | if (this.options.secondaryAreaUnit && units[this.options.secondaryAreaUnit]) {
|
---|
| 5305 | result.areaDisplay = result.areaDisplay + ' (' + humanize.numberFormat(measurement.area[this.options.secondaryAreaUnit], units[this.options.secondaryAreaUnit].decimals) + ' ' + units[this.options.secondaryAreaUnit].display + ')';
|
---|
| 5306 | }
|
---|
| 5307 | }
|
---|
| 5308 | return result;
|
---|
| 5309 | },
|
---|
| 5310 | // update results area of dom with calced measure from `this._latlngs`
|
---|
| 5311 | _updateResults: function () {
|
---|
| 5312 | var calced = calc.measure(this._latlngs);
|
---|
| 5313 | this.$results.innerHTML = resultsTemplate({
|
---|
| 5314 | model: _.extend({}, calced, this._getMeasurementDisplayStrings(calced), {
|
---|
| 5315 | pointCount: this._latlngs.length
|
---|
| 5316 | }),
|
---|
| 5317 | humanize: humanize
|
---|
| 5318 | });
|
---|
| 5319 | },
|
---|
| 5320 | // mouse move handler while measure in progress
|
---|
| 5321 | // adds floating measure marker under cursor
|
---|
| 5322 | _handleMeasureMove: function (evt) {
|
---|
| 5323 | if (!this._measureDrag) {
|
---|
| 5324 | this._measureDrag = L.circleMarker(evt.latlng, this._symbols.getSymbol('measureDrag')).addTo(this._layer);
|
---|
| 5325 | } else {
|
---|
| 5326 | this._measureDrag.setLatLng(evt.latlng);
|
---|
| 5327 | }
|
---|
| 5328 | this._measureDrag.bringToFront();
|
---|
| 5329 | },
|
---|
| 5330 | // handler for both double click and clicking finish button
|
---|
| 5331 | // do final calc and finish out current measure, clear dom and internal state, add permanent map features
|
---|
| 5332 | _handleMeasureDoubleClick: function () {
|
---|
| 5333 | var latlngs = this._latlngs, calced, resultFeature, popupContainer, popupContent, zoomLink, deleteLink;
|
---|
| 5334 |
|
---|
| 5335 | this._finishMeasure();
|
---|
| 5336 |
|
---|
| 5337 | if (!latlngs.length) {
|
---|
| 5338 | return;
|
---|
| 5339 | }
|
---|
| 5340 |
|
---|
| 5341 | if (latlngs.length > 2) {
|
---|
| 5342 | latlngs.push(_.first(latlngs)); // close path to get full perimeter measurement for areas
|
---|
| 5343 | }
|
---|
| 5344 |
|
---|
| 5345 | calced = calc.measure(latlngs);
|
---|
| 5346 |
|
---|
| 5347 | if (latlngs.length === 1) {
|
---|
| 5348 | resultFeature = L.circleMarker(latlngs[0], this._symbols.getSymbol('resultPoint'));
|
---|
| 5349 | popupContent = pointPopupTemplate({
|
---|
| 5350 | model: calced,
|
---|
| 5351 | humanize: humanize
|
---|
| 5352 | });
|
---|
| 5353 | } else if (latlngs.length === 2) {
|
---|
| 5354 | resultFeature = L.polyline(latlngs, this._symbols.getSymbol('resultLine')).addTo(this._map);
|
---|
| 5355 | popupContent = linePopupTemplate({
|
---|
| 5356 | model: _.extend({}, calced, this._getMeasurementDisplayStrings(calced)),
|
---|
| 5357 | humanize: humanize
|
---|
| 5358 | });
|
---|
| 5359 | } else {
|
---|
| 5360 | resultFeature = L.polygon(latlngs, this._symbols.getSymbol('resultArea'));
|
---|
| 5361 | popupContent = areaPopupTemplate({
|
---|
| 5362 | model: _.extend({}, calced, this._getMeasurementDisplayStrings(calced)),
|
---|
| 5363 | humanize: humanize,
|
---|
| 5364 | units: this._units
|
---|
| 5365 | });
|
---|
| 5366 | }
|
---|
| 5367 |
|
---|
| 5368 | popupContainer = L.DomUtil.create('div', '');
|
---|
| 5369 | popupContainer.innerHTML = popupContent;
|
---|
| 5370 |
|
---|
| 5371 | zoomLink = $('.js-zoomto', popupContainer);
|
---|
| 5372 | if (zoomLink) {
|
---|
| 5373 | L.DomEvent.on(zoomLink, 'click', L.DomEvent.stop);
|
---|
| 5374 | L.DomEvent.on(zoomLink, 'click', function () {
|
---|
| 5375 | this._map.fitBounds(resultFeature.getBounds(), {
|
---|
| 5376 | padding: [20, 20],
|
---|
| 5377 | maxZoom: 17
|
---|
| 5378 | });
|
---|
| 5379 | }, this);
|
---|
| 5380 | }
|
---|
| 5381 |
|
---|
| 5382 | deleteLink = $('.js-deletemarkup', popupContainer);
|
---|
| 5383 | if (deleteLink) {
|
---|
| 5384 | L.DomEvent.on(deleteLink, 'click', L.DomEvent.stop);
|
---|
| 5385 | L.DomEvent.on(deleteLink, 'click', function () {
|
---|
| 5386 | // TODO. maybe remove any event handlers on zoom and delete buttons?
|
---|
| 5387 | this._map.removeLayer(resultFeature);
|
---|
| 5388 | }, this);
|
---|
| 5389 | }
|
---|
| 5390 |
|
---|
| 5391 | resultFeature.addTo(this._map);
|
---|
| 5392 | resultFeature.bindPopup(popupContainer, this.options.popupOptions);
|
---|
| 5393 | resultFeature.openPopup(resultFeature.getBounds().getCenter());
|
---|
| 5394 | },
|
---|
| 5395 | // handle map click during ongoing measurement
|
---|
| 5396 | // add new clicked point, update measure layers and results ui
|
---|
| 5397 | _handleMeasureClick: function (evt) {
|
---|
| 5398 | var latlng = evt.latlng, lastClick = _.last(this._latlngs), vertexSymbol = this._symbols.getSymbol('measureVertex');
|
---|
| 5399 |
|
---|
| 5400 | this._map.closePopup(); // open popups aren't closed on click. may be bug. close popup manually just in case.
|
---|
| 5401 |
|
---|
| 5402 | if (!lastClick || !latlng.equals(lastClick)) { // skip if same point as last click, happens on `dblclick`
|
---|
| 5403 | this._latlngs.push(latlng);
|
---|
| 5404 | this._addMeasureArea(this._latlngs);
|
---|
| 5405 | this._addMeasureBoundary(this._latlngs);
|
---|
| 5406 |
|
---|
| 5407 | this._measureVertexes.eachLayer(function (layer) {
|
---|
| 5408 | layer.setStyle(vertexSymbol);
|
---|
| 5409 | // reset all vertexes to non-active class - only last vertex is active
|
---|
| 5410 | // `layer.setStyle({ className: 'layer-measurevertex'})` doesn't work. https://github.com/leaflet/leaflet/issues/2662
|
---|
| 5411 | // set attribute on path directly
|
---|
| 5412 | layer._path.setAttribute('class', vertexSymbol.className);
|
---|
| 5413 | });
|
---|
| 5414 |
|
---|
| 5415 | this._addNewVertex(latlng);
|
---|
| 5416 |
|
---|
| 5417 | if (this._measureBoundary) {
|
---|
| 5418 | this._measureBoundary.bringToFront();
|
---|
| 5419 | }
|
---|
| 5420 | this._measureVertexes.bringToFront();
|
---|
| 5421 | }
|
---|
| 5422 |
|
---|
| 5423 | this._updateResults();
|
---|
| 5424 | this._updateMeasureStartedWithPoints();
|
---|
| 5425 | },
|
---|
| 5426 | // handle map mouse out during ongoing measure
|
---|
| 5427 | // remove floating cursor vertex from map
|
---|
| 5428 | _handleMapMouseOut: function () {
|
---|
| 5429 | if (this._measureDrag) {
|
---|
| 5430 | this._layer.removeLayer(this._measureDrag);
|
---|
| 5431 | this._measureDrag = null;
|
---|
| 5432 | }
|
---|
| 5433 | },
|
---|
| 5434 | // add various measure graphics to map - vertex, area, boundary
|
---|
| 5435 | _addNewVertex: function (latlng) {
|
---|
| 5436 | L.circleMarker(latlng, this._symbols.getSymbol('measureVertexActive')).addTo(this._measureVertexes);
|
---|
| 5437 | },
|
---|
| 5438 | _addMeasureArea: function (latlngs) {
|
---|
| 5439 | if (latlngs.length < 3) {
|
---|
| 5440 | if (this._measureArea) {
|
---|
| 5441 | this._layer.removeLayer(this._measureArea);
|
---|
| 5442 | this._measureArea = null;
|
---|
| 5443 | }
|
---|
| 5444 | return;
|
---|
| 5445 | }
|
---|
| 5446 | if (!this._measureArea) {
|
---|
| 5447 | this._measureArea = L.polygon(latlngs, this._symbols.getSymbol('measureArea')).addTo(this._layer);
|
---|
| 5448 | } else {
|
---|
| 5449 | this._measureArea.setLatLngs(latlngs);
|
---|
| 5450 | }
|
---|
| 5451 | },
|
---|
| 5452 | _addMeasureBoundary: function (latlngs) {
|
---|
| 5453 | if (latlngs.length < 2) {
|
---|
| 5454 | if (this._measureBoundary) {
|
---|
| 5455 | this._layer.removeLayer(this._measureBoundary);
|
---|
| 5456 | this._measureBoundary = null;
|
---|
| 5457 | }
|
---|
| 5458 | return;
|
---|
| 5459 | }
|
---|
| 5460 | if (!this._measureBoundary) {
|
---|
| 5461 | this._measureBoundary = L.polyline(latlngs, this._symbols.getSymbol('measureBoundary')).addTo(this._layer);
|
---|
| 5462 | } else {
|
---|
| 5463 | this._measureBoundary.setLatLngs(latlngs);
|
---|
| 5464 | }
|
---|
| 5465 | }
|
---|
| 5466 | });
|
---|
| 5467 |
|
---|
| 5468 | L.Map.mergeOptions({
|
---|
| 5469 | measureControl: false
|
---|
| 5470 | });
|
---|
| 5471 |
|
---|
| 5472 | L.Map.addInitHook(function () {
|
---|
| 5473 | if (this.options.measureControl) {
|
---|
| 5474 | this.measureControl = (new L.Control.Measure()).addTo(this);
|
---|
| 5475 | }
|
---|
| 5476 | });
|
---|
| 5477 |
|
---|
| 5478 | L.control.measure = function (options) {
|
---|
| 5479 | return new L.Control.Measure(options);
|
---|
| 5480 | };
|
---|
| 5481 | }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
|
---|
| 5482 | },{"./calc":17,"./dom":18,"./mapsymbology":20,"./units":21,"humanize":15,"underscore":16}],20:[function(require,module,exports){
|
---|
| 5483 | // mapsymbology.js
|
---|
| 5484 |
|
---|
| 5485 | var _ = require('underscore');
|
---|
| 5486 |
|
---|
| 5487 | var color = require('color');
|
---|
| 5488 |
|
---|
| 5489 | var Symbology = function (options) {
|
---|
| 5490 | this.setOptions(options);
|
---|
| 5491 | };
|
---|
| 5492 |
|
---|
| 5493 | Symbology.DEFAULTS = {
|
---|
| 5494 | activeColor: '#ABE67E', // base color for map features while actively measuring
|
---|
| 5495 | completedColor: '#C8F2BE' // base color for permenant features generated from completed measure
|
---|
| 5496 | };
|
---|
| 5497 |
|
---|
| 5498 | _.extend(Symbology.prototype, {
|
---|
| 5499 | setOptions: function (options) {
|
---|
| 5500 | this._options = _.extend({}, Symbology.DEFAULTS, this._options, options);
|
---|
| 5501 | return this;
|
---|
| 5502 | },
|
---|
| 5503 | getSymbol: function (name) {
|
---|
| 5504 | var symbols = {
|
---|
| 5505 | measureCollector: {
|
---|
| 5506 | clickable: true,
|
---|
| 5507 | stroke: false,
|
---|
| 5508 | fillOpacity: 0.0,
|
---|
| 5509 | className: 'layer-measurecollector'
|
---|
| 5510 | },
|
---|
| 5511 | measureDrag: {
|
---|
| 5512 | clickable: false,
|
---|
| 5513 | radius: 4,
|
---|
| 5514 | color: this._options.activeColor,
|
---|
| 5515 | weight: 2,
|
---|
| 5516 | opacity: 0.7,
|
---|
| 5517 | fillColor: this._options.activeColor,
|
---|
| 5518 | fillOpacity: 0.5,
|
---|
| 5519 | className: 'layer-measuredrag'
|
---|
| 5520 | },
|
---|
| 5521 | measureArea: {
|
---|
| 5522 | clickable: false,
|
---|
| 5523 | stroke: false,
|
---|
| 5524 | fillColor: this._options.activeColor,
|
---|
| 5525 | fillOpacity: 0.2,
|
---|
| 5526 | className: 'layer-measurearea'
|
---|
| 5527 | },
|
---|
| 5528 | measureBoundary: {
|
---|
| 5529 | clickable: false,
|
---|
| 5530 | color: this._options.activeColor,
|
---|
| 5531 | weight: 2,
|
---|
| 5532 | opacity: 0.9,
|
---|
| 5533 | fill: false,
|
---|
| 5534 | className: 'layer-measureboundary'
|
---|
| 5535 | },
|
---|
| 5536 | measureVertex: {
|
---|
| 5537 | clickable: false,
|
---|
| 5538 | radius: 4,
|
---|
| 5539 | color: this._options.activeColor,
|
---|
| 5540 | weight: 2,
|
---|
| 5541 | opacity: 1,
|
---|
| 5542 | fillColor: this._options.activeColor,
|
---|
| 5543 | fillOpacity: 0.7,
|
---|
| 5544 | className: 'layer-measurevertex'
|
---|
| 5545 | },
|
---|
| 5546 | measureVertexActive: {
|
---|
| 5547 | clickable: false,
|
---|
| 5548 | radius: 4,
|
---|
| 5549 | color: this._options.activeColor,
|
---|
| 5550 | weight: 2,
|
---|
| 5551 | opacity: 1,
|
---|
| 5552 | fillColor: color(this._options.activeColor).darken(0.15),
|
---|
| 5553 | fillOpacity: 0.7,
|
---|
| 5554 | className: 'layer-measurevertex active'
|
---|
| 5555 | },
|
---|
| 5556 | resultArea: {
|
---|
| 5557 | clickable: true,
|
---|
| 5558 | color: this._options.completedColor,
|
---|
| 5559 | weight: 2,
|
---|
| 5560 | opacity: 0.9,
|
---|
| 5561 | fillColor: this._options.completedColor,
|
---|
| 5562 | fillOpacity: 0.2,
|
---|
| 5563 | className: 'layer-measure-resultarea'
|
---|
| 5564 | },
|
---|
| 5565 | resultLine: {
|
---|
| 5566 | clickable: true,
|
---|
| 5567 | color: this._options.completedColor,
|
---|
| 5568 | weight: 3,
|
---|
| 5569 | opacity: 0.9,
|
---|
| 5570 | fill: false,
|
---|
| 5571 | className: 'layer-measure-resultline'
|
---|
| 5572 | },
|
---|
| 5573 | resultPoint: {
|
---|
| 5574 | clickable: true,
|
---|
| 5575 | radius: 4,
|
---|
| 5576 | color: this._options.completedColor,
|
---|
| 5577 | weight: 2,
|
---|
| 5578 | opacity: 1,
|
---|
| 5579 | fillColor: this._options.completedColor,
|
---|
| 5580 | fillOpacity: 0.7,
|
---|
| 5581 | className: 'layer-measure-resultpoint'
|
---|
| 5582 | }
|
---|
| 5583 | };
|
---|
| 5584 | return symbols[name];
|
---|
| 5585 | }
|
---|
| 5586 | });
|
---|
| 5587 |
|
---|
| 5588 | module.exports = Symbology;
|
---|
| 5589 | },{"color":1,"underscore":16}],21:[function(require,module,exports){
|
---|
| 5590 | // units.js
|
---|
| 5591 | // Unit configurations
|
---|
| 5592 |
|
---|
| 5593 | module.exports = {
|
---|
| 5594 | acres: {
|
---|
| 5595 | display: 'Acres',
|
---|
| 5596 | decimals: 2
|
---|
| 5597 | },
|
---|
| 5598 | feet: {
|
---|
| 5599 | display: 'Feet',
|
---|
| 5600 | decimals: 0
|
---|
| 5601 | },
|
---|
| 5602 | kilometers: {
|
---|
| 5603 | display: 'Kilometers',
|
---|
| 5604 | decimals: 2
|
---|
| 5605 | },
|
---|
| 5606 | hectares: {
|
---|
| 5607 | display: 'Hectares',
|
---|
| 5608 | decimals: 2
|
---|
| 5609 | },
|
---|
| 5610 | meters: {
|
---|
| 5611 | display: 'Meters',
|
---|
| 5612 | decimals: 0
|
---|
| 5613 | },
|
---|
| 5614 | miles: {
|
---|
| 5615 | display: 'Miles',
|
---|
| 5616 | decimals: 2
|
---|
| 5617 | },
|
---|
| 5618 | sqmeters: {
|
---|
| 5619 | display: 'Sq Meters',
|
---|
| 5620 | decimals: 0
|
---|
| 5621 | },
|
---|
| 5622 | sqmiles: {
|
---|
| 5623 | display: 'Sq Miles',
|
---|
| 5624 | decimals: 2
|
---|
| 5625 | }
|
---|
| 5626 | };
|
---|
| 5627 | },{}]},{},[19]);
|
---|