summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README4
-rw-r--r--bookmarklet/ffffallback-logo.pngbin0 -> 1742 bytes
-rw-r--r--bookmarklet/ffffallback.css228
-rw-r--r--bookmarklet/ffffallback.js311
-rw-r--r--index.html21
5 files changed, 564 insertions, 0 deletions
diff --git a/README b/README
index e69de29..09ab363 100644
--- a/README
+++ b/README
@@ -0,0 +1,4 @@
+README
+
+Props to Mark. He is amazeballs.
+Props to webkit scrollbar stuff from http://beautifulpixels.com/goodies/create-custom-webkit-scrollbar/ \ No newline at end of file
diff --git a/bookmarklet/ffffallback-logo.png b/bookmarklet/ffffallback-logo.png
new file mode 100644
index 0000000..0181fd2
--- /dev/null
+++ b/bookmarklet/ffffallback-logo.png
Binary files differ
diff --git a/bookmarklet/ffffallback.css b/bookmarklet/ffffallback.css
new file mode 100644
index 0000000..9659c2f
--- /dev/null
+++ b/bookmarklet/ffffallback.css
@@ -0,0 +1,228 @@
+#ffffallback-fontclass-inherit-parent {
+ font-family: inherit !important;
+}
+
+#ffffallback-content-container {
+ opacity:0.5;
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 100%;
+ z-index: 999999;
+}
+
+#ffffallback-content-container * {
+ color:rgb(255,0,255) !important;
+}
+
+body.ffffallback-hide-fallback #ffffallback-content-container {
+ display: none;
+}
+
+body.ffffallback-hide-original > * {
+ display: none;
+}
+
+body.ffffallback-hide-original #ffffallback-content-container {
+ display: block;
+ opacity: 1;
+}
+
+/* webkit scrollbar stuff from http://beautifulpixels.com/goodies/create-custom-webkit-scrollbar/ */
+#ffffallback-controller {
+ display: block;
+ position: fixed;
+ right: 0px;
+ top: 0px;
+ background:rgba(0,0,0,0.8);
+ -webkit-box-shadow: rgba(0,0,0,0.5) 0 2px 5px;
+ color:rgba(255,255,255,0.9);
+ font: 13px/1em normal helvetica, arial, sans-serif !important;
+ width: 220px;
+ height: 100%;
+ text-align:left !important;
+ z-index: 9999999;
+}
+
+#ffffallback-controller * {
+ font: inherit;
+ margin: 0;
+}
+
+#ffffallback-controller h1 {
+ color:#313131;
+ background-image: -webkit-gradient(linear, 0 top, 0 bottom, from( #cecece ), to( #b3b3b3 ));
+ border-bottom:1px solid rgba(0,0,0,0.2);
+ text-shadow:rgba(255,255,255,0.6) 0 1px 0;
+ font-weight: bold;
+ margin:0 !important;
+ padding: 0.5em 1em;
+}
+#ffffallback-controller h1 abbr {
+ background:url(ffffallback-logo.png) no-repeat 0 0;
+ border:0;
+ display:inline-block;
+ height:16px;
+ margin-left:-9px;
+ width:116px;
+ text-indent:-99999em;
+}
+#ffffallback-controller ul {
+ padding:0;
+}
+#ffffallback-controller #fb-font {
+ margin:0 0 0 1em;
+ padding:2px;
+}
+#ffffallback-controller li {
+ list-style-type:disc;
+ margin:0 0 10px 10px;
+}
+
+#ffffallback-radios {
+ background:#B3B3B3;
+ border-top:1px solid rgba(255,255,255,0.2);
+ margin:0px;
+ padding:4px 3px 4px 4px;
+ clear:both;
+ overflow:hidden;
+}
+#ffffallback-radios label.radio-checked {
+ background:#7C7C7C !important;
+ background-image: none;
+ color:#fff !important;
+ text-shadow:rgba(0,0,0,0.5) 0 1px 0 !important;
+ -moz-box-shadow: inset 0 1px 5px rgba(0,0,0,0.65);
+ -webkit-box-shadow: inset 0 1px 5px rgba(0,0,0,0.65);
+ -o-box-shadow: inset 0 1px 5px rgba(0,0,0,0.65);
+ box-shadow: inset 0 1px 5px rgba(0,0,0,0.65);
+}
+#ffffallback-radios label {
+ background-image: -moz-linear-gradient(-90deg, #fefefe , #b7b7b7 );
+ background-image: -webkit-gradient(linear, 0 top, 0 bottom, from( #fefefe ), to( #b7b7b7 ));
+ background-image: linear-gradient(top, #fefefe, #b7b7b7);
+ border: 1px solid #555;
+ border-width:1px 0 1px 1px;
+ color:#313131;
+ float:left;
+ margin:0;
+ padding:4px 0px;
+ text-align:center;
+ text-shadow:rgba(255,255,255,0.4) 0 1px 0;
+ width:68px;
+ -webkit-border-top-left-radius: 3px;
+ -webkit-border-bottom-left-radius:3px;
+ -moz-border-radius-topleft: 3px;
+ -moz-border-radius-bottomleft: 3px;
+ border-top-left-radius: 3px;
+ border-bottom-left-radius: 3px;
+ -webkit-box-shadow: rgba(225, 225, 225, 0.4) 0px 1px 0px;
+}
+#ffffallback-radios label+label {
+ border: 1px solid #555;
+ border-width: 1px;
+ -webkit-border-radius: 0;
+ -moz-border-radius: 0;
+ border-radius: 0;
+}
+#ffffallback-radios label+label+label {
+ border-width:1px 1px 1px 0px;
+ -webkit-border-top-right-radius: 3px;
+ -webkit-border-bottom-right-radius: 3px;
+ -moz-border-radius-topright: 3px;
+ -moz-border-radius-bottomright: 3px;
+ border-top-right-radius: 3px;
+ border-bottom-right-radius: 3px;
+}
+#ffffallback-radios label:active, #ffffallback-update:active {
+ background-image: -moz-linear-gradient(-90deg, #b9b9b9 , #969696 );
+ background-image: -webkit-gradient(linear, 0 top, 0 bottom, from( #b9b9b9 ), to( #969696 ));
+ background-image: linear-gradient(top, #b9b9b9, #969696);
+ -moz-box-shadow: inset 0 1px 5px rgba(0,0,0,0.75);
+ -webkit-box-shadow: inset 0 1px 5px rgba(0,0,0,0.75);
+ -o-box-shadow: inset 0 1px 5px rgba(0,0,0,0.75);
+ box-shadow: inset 0 1px 5px rgba(0,0,0,0.75);
+}
+#ffffallback-radios label input {
+ display:none;
+}
+
+
+
+#ffffallback-fonts {
+ list-style: none;
+ margin-top: 0;
+ max-height: 500px;
+ overflow-y: scroll;
+ -moz-box-shadow: inset 0 2px 5px black;
+ -webkit-box-shadow: inset 0 2px 5px black;
+ -o-box-shadow: inset 0 2px 5px black;
+ box-shadow: inset 0 2px 5px black;
+}
+
+#ffffallback-controller ::-webkit-scrollbar {
+ width: 10px;
+ height: 10px;
+}
+
+#ffffallback-controller ::-webkit-scrollbar-track-piece {
+ background-color: #3b3b3b;
+ -webkit-border-radius: 6px;
+}
+
+#ffffallback-controller ::-webkit-scrollbar-thumb:vertical {
+ height: 50px;
+ background-color: #666;
+ -webkit-border-radius: 6px;
+}
+
+#ffffallback-controller ::-webkit-scrollbar-button:start:decrement,
+#ffffallback-controller ::-webkit-scrollbar-button:end:increment {
+ height: 2px;
+ display: block;
+ background-color: transparent;
+}
+
+#ffffallback-fonts li {
+ border-bottom:1px solid #222;
+ list-style: none;
+ margin: 0;
+ margin-top: 1em;
+ padding:0 1em 1em 1em;
+}
+
+#ffffallback-fonts li input {
+ display: block;
+ -webkit-box-shadow: rgb(68, 68, 68) 0px 1px 0px;
+ background: rgb(102, 102, 102);
+ border: 1px solid black;
+ border-radius:4px;
+ color: rgb(204, 204, 204);
+ font:normal 13px/normal Arial, sans-serif;
+ padding: 5px;
+ width:160px;
+ margin-top:10px;
+}
+#ffffallback-update {
+ padding:4px 9px;
+ border-radius: 5px;
+ border:0;
+ font: bold 12px/1.5 helvetica;
+ color:#444;
+ background-image: -moz-linear-gradient(-90deg, #fefefe , #b7b7b7 );
+ background-image: -webkit-gradient(linear, 0 top, 0 bottom, from( #fefefe ), to( #b7b7b7 ));
+ background-image: linear-gradient(top, #fefefe, #b7b7b7);
+ border: 1px solid #555; border: 1px solid #3D3D3D;
+ color:#313131;
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
+ text-shadow:;
+ width:64px;
+ -webkit-box-shadow: rgba(225, 225, 225, 0.4) 0px 1px 0px;
+ text-shadow:#fff 0 1px 0;
+ text-decoration:none;
+ position: relative;
+ right: -24px;
+ cursor:pointer;
+}
diff --git a/bookmarklet/ffffallback.js b/bookmarklet/ffffallback.js
new file mode 100644
index 0000000..1e622ac
--- /dev/null
+++ b/bookmarklet/ffffallback.js
@@ -0,0 +1,311 @@
+(function() {
+ var $ = {
+ memo: {},
+ }
+ $.each = function(collection, callback) {
+ if(!collection) {
+ return;
+ }
+ if(collection.hasOwnProperty('length') && collection.length == 0) {
+ return;
+ }
+ var key;
+ for (key in collection) {
+ if(collection.hasOwnProperty(key) && key !== 'length') {
+ callback.call(collection, collection[key], key);
+ }
+ }
+ };
+
+ $.getComputedStyleOfElement = function(elem) {
+ /**
+ * Based on this blog entry:
+ * http://blog.stchur.com/2006/06/21/css-computed-style/
+ */
+ if (typeof elem.currentStyle != 'undefined') {
+ return elem.currentStyle;
+ }
+ return document.defaultView.getComputedStyle(elem, null);
+ };
+
+ $.trimString = function(string, characterToTrim) {
+ characterToTrim = characterToTrim || ' ';
+ while(string[0] == characterToTrim) {
+ string = string.substring(1);
+ }
+ while(string[string.length - 1] == characterToTrim) {
+ string = string.substring(0, string.length - 1);
+ }
+ return string;
+ }
+
+ $.unquote = function(string) {
+ return $.trimString($.trimString($.trimString(string), '"'), "'");
+ }
+
+ $.getFontsFromDeclaration = function(fontDeclaration) {
+ if($.getFontsFromDeclaration.memo[fontDeclaration]) {
+ console.log('memo');
+ return $.getFontsFromDeclaration.memo[fontDeclaration];
+ }
+
+ var fonts = [];
+ $.each(fontDeclaration.split(','), function(font) {
+ fonts.push($.unquote(font));
+ });
+
+ $.getFontsFromDeclaration.memo[fontDeclaration] = fonts;
+ return $.unique(fonts);
+ }
+ $.getFontsFromDeclaration.memo = {};
+
+ $.getElementFont = function(elem) {
+ var style = $.getComputedStyleOfElement(elem);
+ if(style && style['font-family']) {
+ return style['font-family'];
+ } else {
+ return null;
+ }
+ }
+
+ $.unique = function(array) {
+ var uniquedArray = [];
+ var i;
+ for(i = 0; i < array.length; i++) {
+ if(uniquedArray.indexOf(array[i]) < 0) {
+ uniquedArray.push(array[i]);
+ }
+ }
+ return uniquedArray;
+ }
+
+ $.getAllFontsInUse = function(elem) {
+ var elemFont = $.getElementFont(elem);
+ var fonts = elemFont ? [elemFont] : [];
+ $.each(elem.childNodes, function(childElem) {
+ fonts = fonts.concat($.getAllFontsInUse(childElem));
+ });
+ return $.unique(fonts).sort();
+ }
+
+ $.getClassForFont = function(font) {
+ $.memo.getClassForFont = $.memo.getClassForFont || [];
+ if($.memo.getClassForFont.length === 0) {
+ $.memo.getClassForFont = $.getAllFontsInUse(document.body);
+ }
+
+ var index = $.memo.getClassForFont.indexOf(font);
+ if(index < 0) {
+ return false;
+ } else {
+ return 'ffffallback-fontclass-' + index;
+ }
+ };
+
+ $.addClassToElement = function(className, element) {
+ var elementClassName = className;
+ if(element.getAttribute('class')) {
+ elementClassName = element.getAttribute('class') + ' ' + elementClassName;
+ }
+ element.setAttribute('class', elementClassName);
+ };
+
+ $.removeClassFromElement = function(classNameToRemove, element) {
+ var elementClassName = '';
+ var classes = (element.getAttribute('class') || '').split(' ');
+ $.each(classes, function(existingClassName) {
+ if(existingClassName !== classNameToRemove) {
+ elementClassName += existingClassName + ' ';
+ }
+ });
+ element.setAttribute('class', $.trimString(elementClassName));
+ };
+
+ $.addFontClasses = function(elem, parentFont) {
+ parentFont = parentFont || null;
+ var font = $.getElementFont(elem);
+
+ if(elem.getAttribute) {
+ var className = false;
+ if(font) {
+ className = $.getClassForFont(font) || false;
+ }
+ if(className) {
+ // Only add the class name if the font is different from the parent element
+ // or if this element explicitly defines the parent's font.
+ className = className || 'ffffallback-fontclass-inherit-parent';
+ $.addClassToElement(className, elem);
+ }
+ }
+
+ $.each(elem.childNodes, function(childElem) {
+ $.addFontClasses(childElem, font);
+ });
+ }
+
+ $.capitalize = function(string) {
+ return string.toUpperCase().substring(0, 1) + string.substring(1);
+ }
+
+ $.createElementWithContent = function(tagName, content) {
+ var elem = document.createElement(tagName);
+ elem.innerHTML = content;
+ return elem;
+ };
+
+ $.event = function(element, event, handler, capture) {
+ capture = capture || false;
+ var boundHandler = function() {
+ return handler.apply(element, arguments);
+ }
+ element.addEventListener(event, boundHandler, false);
+ return boundHandler;
+ };
+
+ $.setFallbackCSS = function(cssObject) {
+ var cssText = '';
+
+ $.each(cssObject, function(declarations, selector) {
+ cssText += '#ffffallback-content-container ' + selector + ' {\n';
+ cssText += 'color: magenta !important;';
+ $.each(declarations, function(value, key) {
+ cssText += ' ' + key + ': ' + value + ';\n';
+ });
+ cssText += '}\n\n';
+ });
+
+ var styleElement = document.getElementById('ffffallback-css');
+ if(!styleElement) {
+ styleElement = $.createElementWithContent('style', '');
+ styleElement.setAttribute('id', 'ffffallback-css');
+ document.body.appendChild(styleElement);
+ }
+
+ styleElement.innerText = cssText;
+ console.log('Did set', cssText);
+ };
+
+ window.$fallback = $;
+
+ $.init = function() {
+ console.log('start');
+
+ var clonedCopy = $.createElementWithContent('div', document.body.innerHTML);
+ clonedCopy.setAttribute('id', 'ffffallback-content-container');
+
+ // Copy padding. TBD -- give cloned copy negative version of padding as margin
+ // to counteract positioning? Doesn't seem necessary but not sure why.
+ var bodyStyle = getComputedStyle(document.body);
+ clonedCopy.style.paddingBottom = bodyStyle['padding-bottom'] || 0;
+ clonedCopy.style.paddingLeft = bodyStyle['padding-left'] || 0;
+ clonedCopy.style.paddingRight = bodyStyle['padding-right'] || 0;
+ clonedCopy.style.paddingTop = bodyStyle['padding-top'] || 0;
+
+ document.body.appendChild(clonedCopy);
+ console.log('Added clone');
+ $.addFontClasses(clonedCopy);
+ console.log('Added font classes');
+
+ // OK, now add the controller
+ var controller = $.createElementWithContent('div', '\
+ <form id="ffffallback-toggles">\
+ <h1 id="ffffallback-title"><abbr title="Fast, flexible font fallback!">ffffallback!</abbr> <input type="submit" id="ffffallback-update" value="Update" /></h1>\
+ <div id="ffffallback-radios">\
+ <label><input type="radio" name="ffffallback-display-mode" accesskey="o" id="ffffallback-display-mode-original" /> Original</label>\
+ <label class="radio-checked"><input type="radio" name="ffffallback-display-mode" accesskey="b" id="ffffallback-display-mode-both" checked /> Both</label>\
+ <label><input type="radio" name="ffffallback-display-mode" accesskey="f" id="ffffallback-display-mode-fallback" /> Fallback</label>\
+ </div>\
+ <ul id="ffffallback-fonts"></ul>\
+ </form>\
+ ');
+ controller.setAttribute('id', 'ffffallback-controller');
+ document.body.appendChild(controller);
+ var fontList = document.getElementById('ffffallback-fonts');
+ fontList.innerHTML = '';
+
+ // Size the controller
+ var resizeController = function() {
+ var controller = document.getElementById('ffffallback-controller');
+ var title = document.getElementById('ffffallback-title');
+ var fonts = document.getElementById('ffffallback-fonts');
+ var toggles = document.getElementById('ffffallback-toggles');
+
+ fonts.style.maxHeight = (controller.offsetHeight - (title.offsetHeight + toggles.offsetHeight + 40)) + 'px';
+ }
+ window.addEventListener('resize', resizeController, false);
+ resizeController();
+
+ var fontClass;
+ $.each($.getAllFontsInUse(document.body), function(font) {
+ fontClass = $.getClassForFont(font);
+ fontList.appendChild($.createElementWithContent('li', '<b>' + font + '</b><input type="text" value="" placeholder="Fallback font" class="ffffallback-specify-font" data:font-class="' + fontClass + '" />'));
+ });
+
+ $.event(document.getElementById('ffffallback-display-mode-original'), 'click', function() {
+ $.removeClassFromElement('ffffallback-hide-original', document.body);
+ $.addClassToElement('ffffallback-hide-fallback', document.body);
+ //below is Josh's handywork... I have no idea how to toggle... plz help Mark
+
+ $.each(document.getElementsByClassName('radio-checked'), function(elem) {
+ $.removeClassFromElement('radio-checked', elem);
+ });
+
+ $.addClassToElement('radio-checked', this.parentNode);
+ console.log(document.body.className);
+ });
+ $.event(document.getElementById('ffffallback-display-mode-both'), 'click', function() {
+ $.removeClassFromElement('ffffallback-hide-original', document.body);
+ $.removeClassFromElement('ffffallback-hide-fallback', document.body);
+ //below is Josh's handywork... I have no idea how to toggle... plz help Mark
+ $.each(document.getElementsByClassName('radio-checked'), function(elem) {
+ console.log('Oh elem is!', elem);
+ $.removeClassFromElement('radio-checked', elem);
+ });
+ $.addClassToElement('radio-checked', this.parentNode);
+ console.log(document.body.className);
+ });
+ $.event(document.getElementById('ffffallback-display-mode-fallback'), 'click', function() {
+ $.addClassToElement('ffffallback-hide-original', document.body);
+ $.removeClassFromElement('ffffallback-hide-fallback', document.body);
+ //below is Josh's handywork... I have no idea how to toggle... plz help Mark
+ $.each(document.getElementsByClassName('radio-checked'), function(elem) {
+ $.removeClassFromElement('radio-checked', elem);
+ });
+ $.addClassToElement('radio-checked', this.parentNode);
+ console.log(document.body.className);
+ });
+
+ $.event(document.getElementById('ffffallback-update'), 'click', function(e) {
+ e.preventDefault();
+
+ console.log('Updating');
+
+ var cssDeclarations = {};
+ $.each(document.getElementsByClassName('ffffallback-specify-font'), function(fontInput) {
+ //var className = fontInput.getAttribute('data:font-class');
+ if(!fontInput.getAttribute) {
+ return;
+ }
+ var className = fontInput.getAttribute('data:font-class');
+ var value = $.trimString(fontInput.value);
+ if(!value) {
+ return;
+ }
+ cssDeclarations['.' + className] = {
+ // TODO: 'font' instead of font-family?
+ 'font-family': value
+ };
+ });
+ console.log(cssDeclarations);
+ $.setFallbackCSS(cssDeclarations);
+ });
+ }
+
+ window.addEventListener('load', function() {
+ $.init();
+ }, false);
+
+ if(document.body) {
+ $.init();
+ }
+})(); \ No newline at end of file
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..8c107ad
--- /dev/null
+++ b/index.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>FFFFALLBACK</title>
+ <style type="text/css" media="screen">
+ body {
+ color:#444;
+ font: normal normal normal 1em/1.5 'Helvetica Neue', Arial, Helvetica, sans-serif;
+ }
+ </style>
+</head>
+<body>
+ <hgroup>
+ <h1>FFFFALLBACK</h1>
+ <h2>A simple tool for bulletproof web typography.</h2>
+ </hgroup>
+ <p>Shhhh! This is top secret. Grab the bookmarklet and take it for a spin. Please send any and all feedback to me at <a href="mailto:josh@jbrewer.me">feedback@ffffallback.com</a></p>
+ <p>This is the bookmarklet: <a href="javascript:(function(){var scriptTag=document.createElement('script');scriptTag.setAttribute('src','http://ffffallback.com/bookmarklet/ffffallback.js?r' + Math.random());var linkTag=document.createElement('link');linkTag.setAttribute('href','http://ffffallback.com/bookmarklet/ffffallback.css');linkTag.setAttribute('rel','stylesheet');document.body.appendChild(scriptTag);document.body.appendChild(linkTag);})();">ffffallback</a>&mdash;drag it to your bookmarks bar and brace yourself for an onslaught of unicorns and rainbows.
+</body>
+</html>