comparison static/js/typeface.js @ 303:59e0087c784a

Move javascript directory to js directory We have a nameclash on the server as a common javascript directory is mapped to /javascript. So that we do not clash we use our own one named js.
author David Soria Parra <dsp@php.net>
date Tue, 09 Mar 2010 02:24:24 +0100
parents static/javascript/typeface.js@b9105ed958a4
children
comparison
equal deleted inserted replaced
302:dc2f9b48714e 303:59e0087c784a
1 /*****************************************************************
2
3 typeface.js, version 0.13 | typefacejs.neocracy.org
4
5 Copyright (c) 2008 - 2009, David Chester davidchester@gmx.net
6
7 Permission is hereby granted, free of charge, to any person
8 obtaining a copy of this software and associated documentation
9 files (the "Software"), to deal in the Software without
10 restriction, including without limitation the rights to use,
11 copy, modify, merge, publish, distribute, sublicense, and/or sell
12 copies of the Software, and to permit persons to whom the
13 Software is furnished to do so, subject to the following
14 conditions:
15
16 The above copyright notice and this permission notice shall be
17 included in all copies or substantial portions of the Software.
18
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
21 OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
23 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
24 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26 OTHER DEALINGS IN THE SOFTWARE.
27
28 *****************************************************************/
29 if (/MSIE/i.test(navigator.userAgent) && /x64/i.test(navigator.userAgent)) {
30 var _typeface_js = {};
31 window._typeface_js = _typeface_js;
32 } else {
33
34 (function() {
35
36 var _typeface_js = {
37
38 faces: {},
39
40 loadFace: function(typefaceData) {
41
42 var familyName = typefaceData.familyName.toLowerCase();
43
44 if (!this.faces[familyName]) {
45 this.faces[familyName] = {};
46 }
47 if (!this.faces[familyName][typefaceData.cssFontWeight]) {
48 this.faces[familyName][typefaceData.cssFontWeight] = {};
49 }
50
51 var face = this.faces[familyName][typefaceData.cssFontWeight][typefaceData.cssFontStyle] = typefaceData;
52 face.loaded = true;
53 },
54
55 log: function(message) {
56
57 if (this.quiet) {
58 return;
59 }
60
61 message = "typeface.js: " + message;
62
63 if (this.customLogFn) {
64 this.customLogFn(message);
65
66 } else if (window.console && window.console.log) {
67 window.console.log(message);
68 }
69
70 },
71
72 pixelsFromPoints: function(face, style, points, dimension) {
73 var pixels = points * parseInt(style.fontSize) * 72 / (face.resolution * 100);
74 if (dimension == 'horizontal' && style.fontStretchPercent) {
75 pixels *= style.fontStretchPercent;
76 }
77 return pixels;
78 },
79
80 pointsFromPixels: function(face, style, pixels, dimension) {
81 var points = pixels * face.resolution / (parseInt(style.fontSize) * 72 / 100);
82 if (dimension == 'horizontal' && style.fontStretchPrecent) {
83 points *= style.fontStretchPercent;
84 }
85 return points;
86 },
87
88 cssFontWeightMap: {
89 normal: 'normal',
90 bold: 'bold',
91 400: 'normal',
92 700: 'bold'
93 },
94
95 cssFontStretchMap: {
96 'ultra-condensed': 0.55,
97 'extra-condensed': 0.77,
98 'condensed': 0.85,
99 'semi-condensed': 0.93,
100 'normal': 1,
101 'semi-expanded': 1.07,
102 'expanded': 1.15,
103 'extra-expanded': 1.23,
104 'ultra-expanded': 1.45,
105 'default': 1
106 },
107
108 fallbackCharacter: '.',
109
110 configure: function(args) {
111 var configurableOptionNames = [ 'customLogFn', 'customClassNameRegex', 'customTypefaceElementsList', 'quiet', 'verbose', 'disableSelection' ];
112
113 for (var i = 0; i < configurableOptionNames.length; i++) {
114 var optionName = configurableOptionNames[i];
115 if (args[optionName]) {
116 if (optionName == 'customLogFn') {
117 if (typeof args[optionName] != 'function') {
118 throw "customLogFn is not a function";
119 } else {
120 this.customLogFn = args.customLogFn;
121 }
122 } else {
123 this[optionName] = args[optionName];
124 }
125 }
126 }
127 },
128
129 getTextExtents: function(face, style, text) {
130 var extentX = 0;
131 var extentY = 0;
132 var horizontalAdvance;
133
134 var textLength = text.length;
135 for (var i = 0; i < textLength; i++) {
136 var glyph = face.glyphs[text.charAt(i)] ? face.glyphs[text.charAt(i)] : face.glyphs[this.fallbackCharacter];
137 var letterSpacingAdjustment = this.pointsFromPixels(face, style, style.letterSpacing);
138 extentX += Math.max(glyph.ha, glyph.x_max) + letterSpacingAdjustment;
139 horizontalAdvance += glyph.ha + letterSpacingAdjustment;
140 }
141 return {
142 x: extentX,
143 y: extentY,
144 ha: horizontalAdvance
145
146 };
147 },
148
149 pixelsFromCssAmount: function(cssAmount, defaultValue, element) {
150
151 var matches = undefined;
152
153 if (cssAmount == 'normal') {
154 return defaultValue;
155
156 } else if (matches = cssAmount.match(/([\-\d+\.]+)px/)) {
157 return matches[1];
158
159 } else {
160 // thanks to Dean Edwards for this very sneaky way to get IE to convert
161 // relative values to pixel values
162
163 var pixelAmount;
164
165 var leftInlineStyle = element.style.left;
166 var leftRuntimeStyle = element.runtimeStyle.left;
167
168 element.runtimeStyle.left = element.currentStyle.left;
169
170 if (!cssAmount.match(/\d(px|pt)$/)) {
171 element.style.left = '1em';
172 } else {
173 element.style.left = cssAmount || 0;
174 }
175
176 pixelAmount = element.style.pixelLeft;
177
178 element.style.left = leftInlineStyle;
179 element.runtimeStyle.left = leftRuntimeStyle;
180
181 return pixelAmount || defaultValue;
182 }
183 },
184
185 capitalizeText: function(text) {
186 return text.replace(/(^|\s)[a-z]/g, function(match) { return match.toUpperCase() } );
187 },
188
189 getElementStyle: function(e) {
190 if (window.getComputedStyle) {
191 return window.getComputedStyle(e, '');
192
193 } else if (e.currentStyle) {
194 return e.currentStyle;
195 }
196 },
197
198 getRenderedText: function(e) {
199
200 var browserStyle = this.getElementStyle(e.parentNode);
201
202 var inlineStyleAttribute = e.parentNode.getAttribute('style');
203 if (inlineStyleAttribute && typeof(inlineStyleAttribute) == 'object') {
204 inlineStyleAttribute = inlineStyleAttribute.cssText;
205 }
206
207 if (inlineStyleAttribute) {
208
209 var inlineStyleDeclarations = inlineStyleAttribute.split(/\s*\;\s*/);
210
211 var inlineStyle = {};
212 for (var i = 0; i < inlineStyleDeclarations.length; i++) {
213 var declaration = inlineStyleDeclarations[i];
214 var declarationOperands = declaration.split(/\s*\:\s*/);
215 inlineStyle[declarationOperands[0]] = declarationOperands[1];
216 }
217 }
218
219 var style = {
220 color: browserStyle.color,
221 fontFamily: browserStyle.fontFamily.split(/\s*,\s*/)[0].replace(/(^"|^'|'$|"$)/g, '').toLowerCase(),
222 fontSize: this.pixelsFromCssAmount(browserStyle.fontSize, 12, e.parentNode),
223 fontWeight: this.cssFontWeightMap[browserStyle.fontWeight],
224 fontStyle: browserStyle.fontStyle ? browserStyle.fontStyle : 'normal',
225 fontStretchPercent: this.cssFontStretchMap[inlineStyle && inlineStyle['font-stretch'] ? inlineStyle['font-stretch'] : 'default'],
226 textDecoration: browserStyle.textDecoration,
227 lineHeight: this.pixelsFromCssAmount(browserStyle.lineHeight, 'normal', e.parentNode),
228 letterSpacing: this.pixelsFromCssAmount(browserStyle.letterSpacing, 0, e.parentNode),
229 textTransform: browserStyle.textTransform
230 };
231
232 var face;
233 if (
234 this.faces[style.fontFamily]
235 && this.faces[style.fontFamily][style.fontWeight]
236 ) {
237 face = this.faces[style.fontFamily][style.fontWeight][style.fontStyle];
238 }
239
240 var text = e.nodeValue;
241
242 if (
243 e.previousSibling
244 && e.previousSibling.nodeType == 1
245 && e.previousSibling.tagName != 'BR'
246 && this.getElementStyle(e.previousSibling).display.match(/inline/)
247 ) {
248 text = text.replace(/^\s+/, ' ');
249 } else {
250 text = text.replace(/^\s+/, '');
251 }
252
253 if (
254 e.nextSibling
255 && e.nextSibling.nodeType == 1
256 && e.nextSibling.tagName != 'BR'
257 && this.getElementStyle(e.nextSibling).display.match(/inline/)
258 ) {
259 text = text.replace(/\s+$/, ' ');
260 } else {
261 text = text.replace(/\s+$/, '');
262 }
263
264 text = text.replace(/\s+/g, ' ');
265
266 if (style.textTransform && style.textTransform != 'none') {
267 switch (style.textTransform) {
268 case 'capitalize':
269 text = this.capitalizeText(text);
270 break;
271 case 'uppercase':
272 text = text.toUpperCase();
273 break;
274 case 'lowercase':
275 text = text.toLowerCase();
276 break;
277 }
278 }
279
280 if (!face) {
281 var excerptLength = 12;
282 var textExcerpt = text.substring(0, excerptLength);
283 if (text.length > excerptLength) {
284 textExcerpt += '...';
285 }
286
287 var fontDescription = style.fontFamily;
288 if (style.fontWeight != 'normal') fontDescription += ' ' + style.fontWeight;
289 if (style.fontStyle != 'normal') fontDescription += ' ' + style.fontStyle;
290
291 this.log("couldn't find typeface font: " + fontDescription + ' for text "' + textExcerpt + '"');
292 return;
293 }
294
295 var words = text.split(/\b(?=\w)/);
296
297 var containerSpan = document.createElement('span');
298 containerSpan.className = 'typeface-js-vector-container';
299
300 var wordsLength = words.length
301 for (var i = 0; i < wordsLength; i++) {
302 var word = words[i];
303
304 var vector = this.renderWord(face, style, word);
305
306 if (vector) {
307 containerSpan.appendChild(vector.element);
308
309 if (!this.disableSelection) {
310 var selectableSpan = document.createElement('span');
311 selectableSpan.className = 'typeface-js-selected-text';
312
313 var wordNode = document.createTextNode(word);
314 selectableSpan.appendChild(wordNode);
315
316 if (this.vectorBackend != 'vml') {
317 selectableSpan.style.marginLeft = -1 * (vector.width + 1) + 'px';
318 }
319 selectableSpan.targetWidth = vector.width;
320 //selectableSpan.style.lineHeight = 1 + 'px';
321
322 if (this.vectorBackend == 'vml') {
323 vector.element.appendChild(selectableSpan);
324 } else {
325 containerSpan.appendChild(selectableSpan);
326 }
327 }
328 }
329 }
330
331 return containerSpan;
332 },
333
334 renderDocument: function(callback) {
335
336 if (!callback)
337 callback = function(e) { e.style.visibility = 'visible' };
338
339 var elements = document.getElementsByTagName('*');
340
341 var elementsLength = elements.length;
342 for (var i = 0; i < elements.length; i++) {
343 if (elements[i].className.match(/(^|\s)typeface-js(\s|$)/) || elements[i].tagName.match(/^(H1|H2|H3|H4|H5|H6)$/)) {
344 this.replaceText(elements[i]);
345 if (typeof callback == 'function') {
346 callback(elements[i]);
347 }
348 }
349 }
350
351 if (this.vectorBackend == 'vml') {
352 // lamely work around IE's quirky leaving off final dynamic shapes
353 var dummyShape = document.createElement('v:shape');
354 dummyShape.style.display = 'none';
355 document.body.appendChild(dummyShape);
356 }
357 },
358
359 replaceText: function(e) {
360
361 var childNodes = [];
362 var childNodesLength = e.childNodes.length;
363
364 for (var i = 0; i < childNodesLength; i++) {
365 this.replaceText(e.childNodes[i]);
366 }
367
368 if (e.nodeType == 3 && e.nodeValue.match(/\S/)) {
369 var parentNode = e.parentNode;
370
371 if (parentNode.className == 'typeface-js-selected-text') {
372 return;
373 }
374
375 var renderedText = this.getRenderedText(e);
376
377 if (
378 parentNode.tagName == 'A'
379 && this.vectorBackend == 'vml'
380 && this.getElementStyle(parentNode).display == 'inline'
381 ) {
382 // something of a hack, use inline-block to get IE to accept clicks in whitespace regions
383 parentNode.style.display = 'inline-block';
384 parentNode.style.cursor = 'pointer';
385 }
386
387 if (this.getElementStyle(parentNode).display == 'inline') {
388 parentNode.style.display = 'inline-block';
389 }
390
391 if (renderedText) {
392 if (parentNode.replaceChild) {
393 parentNode.replaceChild(renderedText, e);
394 } else {
395 parentNode.insertBefore(renderedText, e);
396 parentNode.removeChild(e);
397 }
398 if (this.vectorBackend == 'vml') {
399 renderedText.innerHTML = renderedText.innerHTML;
400 }
401
402 var childNodesLength = renderedText.childNodes.length
403 for (var i; i < childNodesLength; i++) {
404
405 // do our best to line up selectable text with rendered text
406
407 var e = renderedText.childNodes[i];
408 if (e.hasChildNodes() && !e.targetWidth) {
409 e = e.childNodes[0];
410 }
411
412 if (e && e.targetWidth) {
413 var letterSpacingCount = e.innerHTML.length;
414 var wordSpaceDelta = e.targetWidth - e.offsetWidth;
415 var letterSpacing = wordSpaceDelta / (letterSpacingCount || 1);
416
417 if (this.vectorBackend == 'vml') {
418 letterSpacing = Math.ceil(letterSpacing);
419 }
420
421 e.style.letterSpacing = letterSpacing + 'px';
422 e.style.width = e.targetWidth + 'px';
423 }
424 }
425 }
426 }
427 },
428
429 applyElementVerticalMetrics: function(face, style, e) {
430
431 if (style.lineHeight == 'normal') {
432 style.lineHeight = this.pixelsFromPoints(face, style, face.lineHeight);
433 }
434
435 var cssLineHeightAdjustment = style.lineHeight - this.pixelsFromPoints(face, style, face.lineHeight);
436
437 e.style.marginTop = Math.round( cssLineHeightAdjustment / 2 ) + 'px';
438 e.style.marginBottom = Math.round( cssLineHeightAdjustment / 2) + 'px';
439
440 },
441
442 vectorBackends: {
443
444 canvas: {
445
446 _initializeSurface: function(face, style, text) {
447
448 var extents = this.getTextExtents(face, style, text);
449
450 var canvas = document.createElement('canvas');
451 if (this.disableSelection) {
452 canvas.innerHTML = text;
453 }
454
455 canvas.height = Math.round(this.pixelsFromPoints(face, style, face.lineHeight));
456 canvas.width = Math.round(this.pixelsFromPoints(face, style, extents.x, 'horizontal'));
457
458 this.applyElementVerticalMetrics(face, style, canvas);
459
460 if (extents.x > extents.ha)
461 canvas.style.marginRight = Math.round(this.pixelsFromPoints(face, style, extents.x - extents.ha, 'horizontal')) + 'px';
462
463 var ctx = canvas.getContext('2d');
464
465 var pointScale = this.pixelsFromPoints(face, style, 1);
466 ctx.scale(pointScale * style.fontStretchPercent, -1 * pointScale);
467 ctx.translate(0, -1 * face.ascender);
468 ctx.fillStyle = style.color;
469
470 return { context: ctx, canvas: canvas };
471 },
472
473 _renderGlyph: function(ctx, face, char, style) {
474
475 var glyph = face.glyphs[char];
476
477 if (!glyph) {
478 //this.log.error("glyph not defined: " + char);
479 return this.renderGlyph(ctx, face, this.fallbackCharacter, style);
480 }
481
482 if (glyph.o) {
483
484 var outline;
485 if (glyph.cached_outline) {
486 outline = glyph.cached_outline;
487 } else {
488 outline = glyph.o.split(' ');
489 glyph.cached_outline = outline;
490 }
491
492 var outlineLength = outline.length;
493 for (var i = 0; i < outlineLength; ) {
494
495 var action = outline[i++];
496
497 switch(action) {
498 case 'm':
499 ctx.moveTo(outline[i++], outline[i++]);
500 break;
501 case 'l':
502 ctx.lineTo(outline[i++], outline[i++]);
503 break;
504
505 case 'q':
506 var cpx = outline[i++];
507 var cpy = outline[i++];
508 ctx.quadraticCurveTo(outline[i++], outline[i++], cpx, cpy);
509 break;
510 }
511 }
512 }
513 if (glyph.ha) {
514 var letterSpacingPoints =
515 style.letterSpacing && style.letterSpacing != 'normal' ?
516 this.pointsFromPixels(face, style, style.letterSpacing) :
517 0;
518
519 ctx.translate(glyph.ha + letterSpacingPoints, 0);
520 }
521 },
522
523 _renderWord: function(face, style, text) {
524 var surface = this.initializeSurface(face, style, text);
525 var ctx = surface.context;
526 var canvas = surface.canvas;
527 ctx.beginPath();
528 ctx.save();
529
530 var chars = text.split('');
531 var charsLength = chars.length;
532 for (var i = 0; i < charsLength; i++) {
533 this.renderGlyph(ctx, face, chars[i], style);
534 }
535
536 ctx.fill();
537
538 if (style.textDecoration == 'underline') {
539
540 ctx.beginPath();
541 ctx.moveTo(0, face.underlinePosition);
542 ctx.restore();
543 ctx.lineTo(0, face.underlinePosition);
544 ctx.strokeStyle = style.color;
545 ctx.lineWidth = face.underlineThickness;
546 ctx.stroke();
547 }
548
549 return { element: ctx.canvas, width: Math.floor(canvas.width) };
550
551 }
552 },
553
554 vml: {
555
556 _initializeSurface: function(face, style, text) {
557
558 var shape = document.createElement('v:shape');
559
560 var extents = this.getTextExtents(face, style, text);
561
562 shape.style.width = shape.style.height = style.fontSize + 'px';
563 shape.style.marginLeft = '-1px'; // this seems suspect...
564
565 if (extents.x > extents.ha) {
566 shape.style.marginRight = this.pixelsFromPoints(face, style, extents.x - extents.ha, 'horizontal') + 'px';
567 }
568
569 this.applyElementVerticalMetrics(face, style, shape);
570
571 var resolutionScale = face.resolution * 100 / 72;
572 shape.coordsize = (resolutionScale / style.fontStretchPercent) + "," + resolutionScale;
573
574 shape.coordorigin = '0,' + face.ascender;
575 shape.style.flip = 'y';
576
577 shape.fillColor = style.color;
578 shape.stroked = false;
579
580 shape.path = 'hh m 0,' + face.ascender + ' l 0,' + face.descender + ' ';
581
582 return shape;
583 },
584
585 _renderGlyph: function(shape, face, char, offsetX, style, vmlSegments) {
586
587 var glyph = face.glyphs[char];
588
589 if (!glyph) {
590 this.log("glyph not defined: " + char);
591 this.renderGlyph(shape, face, this.fallbackCharacter, offsetX, style);
592 return;
593 }
594
595 vmlSegments.push('m');
596
597 if (glyph.o) {
598
599 var outline, outlineLength;
600
601 if (glyph.cached_outline) {
602 outline = glyph.cached_outline;
603 outlineLength = outline.length;
604 } else {
605 outline = glyph.o.split(' ');
606 outlineLength = outline.length;
607
608 for (var i = 0; i < outlineLength;) {
609
610 switch(outline[i++]) {
611 case 'q':
612 outline[i] = Math.round(outline[i++]);
613 outline[i] = Math.round(outline[i++]);
614 case 'm':
615 case 'l':
616 outline[i] = Math.round(outline[i++]);
617 outline[i] = Math.round(outline[i++]);
618 break;
619 }
620 }
621
622 glyph.cached_outline = outline;
623 }
624
625 var prevX, prevY;
626
627 for (var i = 0; i < outlineLength;) {
628
629 var action = outline[i++];
630
631 var x = outline[i++] + offsetX;
632 var y = outline[i++];
633
634 switch(action) {
635 case 'm':
636 vmlSegments.push('xm ', x, ',', y);
637 break;
638
639 case 'l':
640 vmlSegments.push('l ', x, ',', y);
641 break;
642
643 case 'q':
644 var cpx = outline[i++] + offsetX;
645 var cpy = outline[i++];
646
647 var cp1x = Math.round(prevX + 2.0 / 3.0 * (cpx - prevX));
648 var cp1y = Math.round(prevY + 2.0 / 3.0 * (cpy - prevY));
649
650 var cp2x = Math.round(cp1x + (x - prevX) / 3.0);
651 var cp2y = Math.round(cp1y + (y - prevY) / 3.0);
652
653 vmlSegments.push('c ', cp1x, ',', cp1y, ',', cp2x, ',', cp2y, ',', x, ',', y);
654 break;
655 }
656
657 prevX = x;
658 prevY = y;
659 }
660 }
661
662 vmlSegments.push('x e');
663 return vmlSegments;
664 },
665
666 _renderWord: function(face, style, text) {
667 var offsetX = 0;
668 var shape = this.initializeSurface(face, style, text);
669
670 var letterSpacingPoints =
671 style.letterSpacing && style.letterSpacing != 'normal' ?
672 this.pointsFromPixels(face, style, style.letterSpacing) :
673 0;
674
675 letterSpacingPoints = Math.round(letterSpacingPoints);
676 var chars = text.split('');
677 var vmlSegments = [];
678 for (var i = 0; i < chars.length; i++) {
679 var char = chars[i];
680 vmlSegments = this.renderGlyph(shape, face, char, offsetX, style, vmlSegments);
681 offsetX += face.glyphs[char].ha + letterSpacingPoints ;
682 }
683
684 // make sure to preserve trailing whitespace
685 shape.path += vmlSegments.join('') + 'm ' + offsetX + ' 0 l ' + offsetX + ' ' + face.ascender;
686
687 return {
688 element: shape,
689 width: Math.floor(this.pixelsFromPoints(face, style, offsetX, 'horizontal'))
690 };
691 }
692
693 }
694
695 },
696
697 setVectorBackend: function(backend) {
698
699 this.vectorBackend = backend;
700 var backendFunctions = ['renderWord', 'initializeSurface', 'renderGlyph'];
701
702 for (var i = 0; i < backendFunctions.length; i++) {
703 var backendFunction = backendFunctions[i];
704 this[backendFunction] = this.vectorBackends[backend]['_' + backendFunction];
705 }
706 },
707
708 initialize: function() {
709
710 // quit if this function has already been called
711 if (arguments.callee.done) return;
712
713 // flag this function so we don't do the same thing twice
714 arguments.callee.done = true;
715
716 // kill the timer
717 if (window._typefaceTimer) clearInterval(_typefaceTimer);
718
719 this.renderDocument( function(e) { e.style.visibility = 'visible' } );
720
721 }
722
723 };
724
725 // IE won't accept real selectors...
726 var typefaceSelectors = ['.typeface-js', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'];
727
728 if (document.createStyleSheet) {
729
730 var styleSheet = document.createStyleSheet();
731 for (var i = 0; i < typefaceSelectors.length; i++) {
732 var selector = typefaceSelectors[i];
733 styleSheet.addRule(selector, 'visibility: hidden');
734 }
735
736 styleSheet.addRule(
737 '.typeface-js-selected-text',
738 '-ms-filter: \
739 "Chroma(color=black) \
740 progid:DXImageTransform.Microsoft.MaskFilter(Color=white) \
741 progid:DXImageTransform.Microsoft.MaskFilter(Color=blue) \
742 alpha(opacity=30)" !important; \
743 color: black; \
744 font-family: Modern; \
745 position: absolute; \
746 white-space: pre; \
747 filter: alpha(opacity=0);'
748 );
749
750 styleSheet.addRule(
751 '.typeface-js-vector-container',
752 'position: relative'
753 );
754
755 } else if (document.styleSheets && document.styleSheets.length) {
756
757 var styleSheet = document.styleSheets[0];
758 document.styleSheets[0].insertRule(typefaceSelectors.join(',') + ' { visibility: hidden; }', styleSheet.cssRules.length);
759
760 document.styleSheets[0].insertRule(
761 '.typeface-js-selected-text { \
762 color: rgba(128, 128, 128, 0); \
763 opacity: 0.30; \
764 position: absolute; \
765 font-family: Arial, sans-serif; \
766 white-space: pre \
767 }',
768 styleSheet.cssRules.length
769 );
770
771 try {
772 // set selection style for Mozilla / Firefox
773 document.styleSheets[0].insertRule(
774 '.typeface-js-selected-text::-moz-selection { background: blue; }',
775 styleSheet.cssRules.length
776 );
777
778 } catch(e) {};
779
780 try {
781 // set styles for browsers with CSS3 selectors (Safari, Chrome)
782 document.styleSheets[0].insertRule(
783 '.typeface-js-selected-text::selection { background: blue; }',
784 styleSheet.cssRules.length
785 );
786
787 } catch(e) {};
788
789 // most unfortunately, sniff for WebKit's quirky selection behavior
790 if (/WebKit/i.test(navigator.userAgent)) {
791 document.styleSheets[0].insertRule(
792 '.typeface-js-vector-container { position: relative }',
793 styleSheet.cssRules.length
794 );
795 }
796
797 }
798
799 var backend = !!(window.attachEvent && !window.opera) ? 'vml' : window.CanvasRenderingContext2D || document.createElement('canvas').getContext ? 'canvas' : null;
800
801 if (backend == 'vml') {
802
803 document.namespaces.add("v","urn:schemas-microsoft-com:vml","#default#VML");
804
805 var styleSheet = document.createStyleSheet();
806 styleSheet.addRule('v\\:shape', "display: inline-block;");
807 }
808
809 _typeface_js.setVectorBackend(backend);
810 window._typeface_js = _typeface_js;
811
812 if (/WebKit/i.test(navigator.userAgent)) {
813
814 var _typefaceTimer = setInterval(function() {
815 if (/loaded|complete/.test(document.readyState)) {
816 _typeface_js.initialize();
817 }
818 }, 10);
819 }
820
821 if (document.addEventListener) {
822 window.addEventListener('DOMContentLoaded', function() { _typeface_js.initialize() }, false);
823 }
824
825 /*@cc_on @*/
826 /*@if (@_win32)
827
828 document.write("<script id=__ie_onload_typeface defer src=//:><\/script>");
829 var script = document.getElementById("__ie_onload_typeface");
830 script.onreadystatechange = function() {
831 if (this.readyState == "complete") {
832 _typeface_js.initialize();
833 }
834 };
835
836 /*@end @*/
837
838 try { console.log('initializing typeface.js') } catch(e) {};
839
840 })();
841 }