diff options
| -rw-r--r-- | README | 4 | ||||
| -rw-r--r-- | bookmarklet/ffffallback-logo.png | bin | 0 -> 1742 bytes | |||
| -rw-r--r-- | bookmarklet/ffffallback.css | 228 | ||||
| -rw-r--r-- | bookmarklet/ffffallback.js | 311 | ||||
| -rw-r--r-- | index.html | 21 |
5 files changed, 564 insertions, 0 deletions
@@ -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 Binary files differnew file mode 100644 index 0000000..0181fd2 --- /dev/null +++ b/bookmarklet/ffffallback-logo.png 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>—drag it to your bookmarks bar and brace yourself for an onslaught of unicorns and rainbows. +</body> +</html> |
