Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

add clippy

  • Loading branch information...
commit f494fac9b766cd4c698ac56d22a82472bf696211 1 parent f00860a
Travis Dunn authored
1  app/assets/javascripts/application.js
@@ -16,4 +16,5 @@
16 16
17 17 $(document).ready(function() {
18 18 $('.dropdown-toggle').dropdown();
  19 + $('.clippy').clippy();
19 20 });
93 app/assets/javascripts/jquery.clippy.js
... ... @@ -0,0 +1,93 @@
  1 +/*!
  2 + clippy-jquery: <http://github.com/jimmysawczuk/clippy-jquery>
  3 + (c) 2011-2012; MIT License, see README.md for full license information and acknowledgements
  4 +*/
  5 +(function($)
  6 +{
  7 + var _opts = { // default options
  8 + 'width': 14,
  9 + 'height': 14,
  10 + 'clippy_path': '/flash/clippy.swf',
  11 + 'keep_text': false,
  12 + 'force_load' : false,
  13 + 'flashvars' : {}
  14 + };
  15 +
  16 + $.fn.clippy = function(opts)
  17 + {
  18 + opts = $.extend(_opts, opts);
  19 +
  20 + var hasFlash = false;
  21 + try
  22 + {
  23 + var fo = new ActiveXObject('ShockwaveFlash.ShockwaveFlash');
  24 + if (fo)
  25 + {
  26 + hasFlash = true;
  27 + }
  28 + }
  29 + catch(e)
  30 + {
  31 + if (navigator.mimeTypes ["application/x-shockwave-flash"] != undefined)
  32 + {
  33 + hasFlash = true;
  34 + }
  35 + }
  36 +
  37 + // if browser has Flash support or manual override set...
  38 + if (hasFlash || opts.force_load)
  39 + {
  40 + // for every element matched...
  41 + $.each($(this), function(idx, val)
  42 + {
  43 + var text = "";
  44 + if (typeof opts.text != "undefined")
  45 + {
  46 + text = opts.text;
  47 + }
  48 + else if ($(val).data('text') && $.trim($(val).data('text')) != '')
  49 + {
  50 + text = $(val).data('text');
  51 + }
  52 + else
  53 + {
  54 + text = $.trim($(val).text());
  55 + }
  56 +
  57 + // text should be URI-encoded, per https://github.com/mojombo/clippy/pull/9
  58 + text = encodeURIComponent(text);
  59 +
  60 + var id = "";
  61 + if (typeof $(val).attr('id') === "undefined" || $.trim($(val).attr('id')) === "")
  62 + {
  63 + var id_suffix = Math.round(Math.random() * 10240).toString(16);
  64 + id = 'clippy-' + id_suffix;
  65 +
  66 + $(val).attr('id', id);
  67 + }
  68 + else
  69 + {
  70 + id = $(val).attr('id');
  71 + }
  72 +
  73 + if (!opts.keep_text)
  74 + {
  75 + $(val).html('');
  76 + }
  77 +
  78 + var flashvars = $.extend({}, opts.flashvars, {text: text});
  79 +
  80 + swfobject.embedSWF(opts.clippy_path, id, opts.width, opts.height,
  81 + '10', false, flashvars, {scale: "noscale"});
  82 + });
  83 + }
  84 + else
  85 + {
  86 + // hide all the clippies so unwanted text is not displayed when Flash is not supported
  87 + $.each(this, function(idx, val)
  88 + {
  89 + $(val).css({'display': 'none'});
  90 + });
  91 + }
  92 + };
  93 +})(jQuery);
837 app/assets/javascripts/swfobject.js
... ... @@ -0,0 +1,837 @@
  1 +/*! SWFObject v2.3.20120118 <http://github.com/swfobject/swfobject>
  2 + is released under the MIT License <http://www.opensource.org/licenses/mit-license.php>
  3 +*/
  4 +
  5 +var swfobject = function() {
  6 +
  7 + var UNDEF = "undefined",
  8 + OBJECT = "object",
  9 + SHOCKWAVE_FLASH = "Shockwave Flash",
  10 + SHOCKWAVE_FLASH_AX = "ShockwaveFlash.ShockwaveFlash",
  11 + FLASH_MIME_TYPE = "application/x-shockwave-flash",
  12 + EXPRESS_INSTALL_ID = "SWFObjectExprInst",
  13 + ON_READY_STATE_CHANGE = "onreadystatechange",
  14 +
  15 + win = window,
  16 + doc = document,
  17 + nav = navigator,
  18 +
  19 + plugin = false,
  20 + domLoadFnArr = [],
  21 + regObjArr = [],
  22 + objIdArr = [],
  23 + listenersArr = [],
  24 + storedFbContent,
  25 + storedFbContentId,
  26 + storedCallbackFn,
  27 + storedCallbackObj,
  28 + isDomLoaded = false,
  29 + isExpressInstallActive = false,
  30 + dynamicStylesheet,
  31 + dynamicStylesheetMedia,
  32 + autoHideShow = true,
  33 + encodeURI_enabled = false,
  34 +
  35 + /* Centralized function for browser feature detection
  36 + - User agent string detection is only used when no good alternative is possible
  37 + - Is executed directly for optimal performance
  38 + */
  39 + ua = function() {
  40 + var w3cdom = typeof doc.getElementById != UNDEF && typeof doc.getElementsByTagName != UNDEF && typeof doc.createElement != UNDEF,
  41 + u = nav.userAgent.toLowerCase(),
  42 + p = nav.platform.toLowerCase(),
  43 + windows = p ? /win/.test(p) : /win/.test(u),
  44 + mac = p ? /mac/.test(p) : /mac/.test(u),
  45 + webkit = /webkit/.test(u) ? parseFloat(u.replace(/^.*webkit\/(\d+(\.\d+)?).*$/, "$1")) : false, // returns either the webkit version or false if not webkit
  46 + ie = nav.appName === "Microsoft Internet Explorer",
  47 + playerVersion = [0,0,0],
  48 + d = null;
  49 + if (typeof nav.plugins != UNDEF && typeof nav.plugins[SHOCKWAVE_FLASH] == OBJECT) {
  50 + d = nav.plugins[SHOCKWAVE_FLASH].description;
  51 + // nav.mimeTypes["application/x-shockwave-flash"].enabledPlugin indicates whether plug-ins are enabled or disabled in Safari 3+
  52 + if (d && (typeof nav.mimeTypes != UNDEF && nav.mimeTypes[FLASH_MIME_TYPE] && nav.mimeTypes[FLASH_MIME_TYPE].enabledPlugin)){
  53 + plugin = true;
  54 + ie = false; // cascaded feature detection for Internet Explorer
  55 + d = d.replace(/^.*\s+(\S+\s+\S+$)/, "$1");
  56 + playerVersion[0] = toInt(d.replace(/^(.*)\..*$/, "$1"));
  57 + playerVersion[1] = toInt(d.replace(/^.*\.(.*)\s.*$/, "$1"));
  58 + playerVersion[2] = /[a-zA-Z]/.test(d) ? toInt(d.replace(/^.*[a-zA-Z]+(.*)$/, "$1")) : 0;
  59 + }
  60 + }
  61 + else if (typeof win.ActiveXObject != UNDEF) {
  62 + try {
  63 + var a = new ActiveXObject(SHOCKWAVE_FLASH_AX);
  64 + if (a) { // a will return null when ActiveX is disabled
  65 + d = a.GetVariable("$version");
  66 + if (d) {
  67 + ie = true; // cascaded feature detection for Internet Explorer
  68 + d = d.split(" ")[1].split(",");
  69 + playerVersion = [toInt(d[0]), toInt(d[1]), toInt(d[2])];
  70 + }
  71 + }
  72 + }
  73 + catch(e) {}
  74 + }
  75 + return { w3:w3cdom, pv:playerVersion, wk:webkit, ie:ie, win:windows, mac:mac };
  76 + }(),
  77 +
  78 + /* Cross-browser onDomLoad
  79 + - Will fire an event as soon as the DOM of a web page is loaded
  80 + - Internet Explorer workaround based on Diego Perini's solution: http://javascript.nwbox.com/IEContentLoaded/
  81 + - Regular onload serves as fallback
  82 + */
  83 + onDomLoad = function() {
  84 + if (!ua.w3) { return; }
  85 + if ((typeof doc.readyState != UNDEF && doc.readyState == "complete") || (typeof doc.readyState == UNDEF && (doc.getElementsByTagName("body")[0] || doc.body))) { // function is fired after onload, e.g. when script is inserted dynamically
  86 + callDomLoadFunctions();
  87 + }
  88 + if (!isDomLoaded) {
  89 + if (typeof doc.addEventListener != UNDEF) {
  90 + doc.addEventListener("DOMContentLoaded", callDomLoadFunctions, false);
  91 + }
  92 + if (ua.ie) {
  93 + doc.attachEvent(ON_READY_STATE_CHANGE, function detach() {
  94 + if (doc.readyState == "complete") {
  95 + doc.detachEvent(ON_READY_STATE_CHANGE, detach);
  96 + callDomLoadFunctions();
  97 + }
  98 + });
  99 + if (win == top) { // if not inside an iframe
  100 + (function checkDomLoadedIE(){
  101 + if (isDomLoaded) { return; }
  102 + try {
  103 + doc.documentElement.doScroll("left");
  104 + }
  105 + catch(e) {
  106 + setTimeout(checkDomLoadedIE, 0);
  107 + return;
  108 + }
  109 + callDomLoadFunctions();
  110 + }());
  111 + }
  112 + }
  113 + if (ua.wk) {
  114 + (function checkDomLoadedWK(){
  115 + if (isDomLoaded) { return; }
  116 + if (!/loaded|complete/.test(doc.readyState)) {
  117 + setTimeout(checkDomLoadedWK, 0);
  118 + return;
  119 + }
  120 + callDomLoadFunctions();
  121 + }());
  122 + }
  123 + }
  124 + }();
  125 +
  126 + function callDomLoadFunctions() {
  127 + if (isDomLoaded || !document.getElementsByTagName("body")[0]) { return; }
  128 + try { // test if we can really add/remove elements to/from the DOM; we don't want to fire it too early
  129 + var t, span = createElement("span");
  130 + span.style.display = "none"; //hide the span in case someone has styled spans via CSS
  131 + t = doc.getElementsByTagName("body")[0].appendChild(span);
  132 + t.parentNode.removeChild(t);
  133 + t = null; //clear the variables
  134 + span = null;
  135 + }
  136 + catch (e) { return; }
  137 + isDomLoaded = true;
  138 + var dl = domLoadFnArr.length;
  139 + for (var i = 0; i < dl; i++) {
  140 + domLoadFnArr[i]();
  141 + }
  142 + }
  143 +
  144 + function addDomLoadEvent(fn) {
  145 + if (isDomLoaded) {
  146 + fn();
  147 + }
  148 + else {
  149 + domLoadFnArr[domLoadFnArr.length] = fn; // Array.push() is only available in IE5.5+
  150 + }
  151 + }
  152 +
  153 + /* Cross-browser onload
  154 + - Based on James Edwards' solution: http://brothercake.com/site/resources/scripts/onload/
  155 + - Will fire an event as soon as a web page including all of its assets are loaded
  156 + */
  157 + function addLoadEvent(fn) {
  158 + if (typeof win.addEventListener != UNDEF) {
  159 + win.addEventListener("load", fn, false);
  160 + }
  161 + else if (typeof doc.addEventListener != UNDEF) {
  162 + doc.addEventListener("load", fn, false);
  163 + }
  164 + else if (typeof win.attachEvent != UNDEF) {
  165 + addListener(win, "onload", fn);
  166 + }
  167 + else if (typeof win.onload == "function") {
  168 + var fnOld = win.onload;
  169 + win.onload = function() {
  170 + fnOld();
  171 + fn();
  172 + };
  173 + }
  174 + else {
  175 + win.onload = fn;
  176 + }
  177 + }
  178 +
  179 +
  180 + /* Detect the Flash Player version for non-Internet Explorer browsers
  181 + - Detecting the plug-in version via the object element is more precise than using the plugins collection item's description:
  182 + a. Both release and build numbers can be detected
  183 + b. Avoid wrong descriptions by corrupt installers provided by Adobe
  184 + c. Avoid wrong descriptions by multiple Flash Player entries in the plugin Array, caused by incorrect browser imports
  185 + - Disadvantage of this method is that it depends on the availability of the DOM, while the plugins collection is immediately available
  186 + */
  187 + function testPlayerVersion() {
  188 + var b = doc.getElementsByTagName("body")[0];
  189 + var o = createElement(OBJECT);
  190 + o.setAttribute("style", "visibility: hidden;");
  191 + o.setAttribute("type", FLASH_MIME_TYPE);
  192 + var t = b.appendChild(o);
  193 + if (t) {
  194 + var counter = 0;
  195 + (function checkGetVariable(){
  196 + if (typeof t.GetVariable != UNDEF) {
  197 + try {
  198 + var d = t.GetVariable("$version");
  199 + if (d) {
  200 + d = d.split(" ")[1].split(",");
  201 + ua.pv = [toInt(d[0]), toInt(d[1]), toInt(d[2])];
  202 + }
  203 + } catch(e){
  204 + //t.GetVariable("$version") is known to fail in Flash Player 8 on Firefox
  205 + //If this error is encountered, assume FP8 or lower. Time to upgrade.
  206 + ua.pv = [8,0,0];
  207 + }
  208 + }
  209 + else if (counter < 10) {
  210 + counter++;
  211 + setTimeout(checkGetVariable, 10);
  212 + return;
  213 + }
  214 + b.removeChild(o);
  215 + t = null;
  216 + matchVersions();
  217 + }());
  218 + }
  219 + else {
  220 + matchVersions();
  221 + }
  222 + }
  223 +
  224 + /* Perform Flash Player and SWF version matching; static publishing only
  225 + */
  226 + function matchVersions() {
  227 + var rl = regObjArr.length;
  228 + if (rl > 0) {
  229 + for (var i = 0; i < rl; i++) { // for each registered object element
  230 + var id = regObjArr[i].id;
  231 + var cb = regObjArr[i].callbackFn;
  232 + var cbObj = {success:false, id:id};
  233 + if (ua.pv[0] > 0) {
  234 + var obj = getElementById(id);
  235 + if (obj) {
  236 + if (hasPlayerVersion(regObjArr[i].swfVersion) && !(ua.wk && ua.wk < 312)) { // Flash Player version >= published SWF version: Houston, we have a match!
  237 + setVisibility(id, true);
  238 + if (cb) {
  239 + cbObj.success = true;
  240 + cbObj.ref = getObjectById(id);
  241 + cbObj.id = id;
  242 + cb(cbObj);
  243 + }
  244 + }
  245 + else if (regObjArr[i].expressInstall && canExpressInstall()) { // show the Adobe Express Install dialog if set by the web page author and if supported
  246 + var att = {};
  247 + att.data = regObjArr[i].expressInstall;
  248 + att.width = obj.getAttribute("width") || "0";
  249 + att.height = obj.getAttribute("height") || "0";
  250 + if (obj.getAttribute("class")) { att.styleclass = obj.getAttribute("class"); }
  251 + if (obj.getAttribute("align")) { att.align = obj.getAttribute("align"); }
  252 + // parse HTML object param element's name-value pairs
  253 + var par = {};
  254 + var p = obj.getElementsByTagName("param");
  255 + var pl = p.length;
  256 + for (var j = 0; j < pl; j++) {
  257 + if (p[j].getAttribute("name").toLowerCase() != "movie") {
  258 + par[p[j].getAttribute("name")] = p[j].getAttribute("value");
  259 + }
  260 + }
  261 + showExpressInstall(att, par, id, cb);
  262 + }
  263 + else { // Flash Player and SWF version mismatch or an older Webkit engine that ignores the HTML object element's nested param elements: display fallback content instead of SWF
  264 + displayFbContent(obj);
  265 + if (cb) { cb(cbObj); }
  266 + }
  267 + }
  268 + }
  269 + else { // if no Flash Player is installed or the fp version cannot be detected we let the HTML object element do its job (either show a SWF or fallback content)
  270 + setVisibility(id, true);
  271 + if (cb) {
  272 + var o = getObjectById(id); // test whether there is an HTML object element or not
  273 + if (o && typeof o.SetVariable != UNDEF) {
  274 + cbObj.success = true;
  275 + cbObj.ref = o;
  276 + cbObj.id = o.id;
  277 + }
  278 + cb(cbObj);
  279 + }
  280 + }
  281 + }
  282 + }
  283 + }
  284 +
  285 + /* Main function
  286 + - Will preferably execute onDomLoad, otherwise onload (as a fallback)
  287 + */
  288 + domLoadFnArr[0] = function (){
  289 + if (plugin) {
  290 + testPlayerVersion();
  291 + }
  292 + else {
  293 + matchVersions();
  294 + }
  295 + };
  296 +
  297 + function getObjectById(objectIdStr) {
  298 +
  299 + var r = null,
  300 + o = getElementById(objectIdStr);
  301 +
  302 + if (o && o.nodeName.toUpperCase() === "OBJECT") {
  303 +
  304 + //If targeted object is valid Flash file
  305 + if (typeof o.SetVariable !== UNDEF){
  306 +
  307 + r = o;
  308 +
  309 + } else {
  310 +
  311 + //If SetVariable is not working on targeted object but a nested object is
  312 + //available, assume classic nested object markup. Return nested object.
  313 +
  314 + //If SetVariable is not working on targeted object and there is no nested object,
  315 + //return the original object anyway. This is probably new simplified markup.
  316 +
  317 + r = o.getElementsByTagName(OBJECT)[0] || o;
  318 +
  319 + }
  320 +
  321 + }
  322 +
  323 + return r;
  324 +
  325 + }
  326 +
  327 + /* Requirements for Adobe Express Install
  328 + - only one instance can be active at a time
  329 + - fp 6.0.65 or higher
  330 + - Win/Mac OS only
  331 + - no Webkit engines older than version 312
  332 + */
  333 + function canExpressInstall() {
  334 + return !isExpressInstallActive && hasPlayerVersion("6.0.65") && (ua.win || ua.mac) && !(ua.wk && ua.wk < 312);
  335 + }
  336 +
  337 + /* Show the Adobe Express Install dialog
  338 + - Reference: http://www.adobe.com/cfusion/knowledgebase/index.cfm?id=6a253b75
  339 + */
  340 + function showExpressInstall(att, par, replaceElemIdStr, callbackFn) {
  341 +
  342 + var obj = getElementById(replaceElemIdStr);
  343 +
  344 + //Ensure that replaceElemIdStr is really a string and not an element
  345 + replaceElemIdStr = getId(replaceElemIdStr);
  346 +
  347 + isExpressInstallActive = true;
  348 + storedCallbackFn = callbackFn || null;
  349 + storedCallbackObj = {success:false, id:replaceElemIdStr};
  350 +
  351 + if (obj) {
  352 + if (obj.nodeName.toUpperCase() == "OBJECT") { // static publishing
  353 + storedFbContent = abstractFbContent(obj);
  354 + storedFbContentId = null;
  355 + }
  356 + else { // dynamic publishing
  357 + storedFbContent = obj;
  358 + storedFbContentId = replaceElemIdStr;
  359 + }
  360 + att.id = EXPRESS_INSTALL_ID;
  361 + if (typeof att.width == UNDEF || (!/%$/.test(att.width) && toInt(att.width) < 310)) { att.width = "310"; }
  362 + if (typeof att.height == UNDEF || (!/%$/.test(att.height) && toInt(att.height) < 137)) { att.height = "137"; }
  363 + doc.title = doc.title.slice(0, 47) + " - Flash Player Installation";
  364 + var pt = ua.ie ? "ActiveX" : "PlugIn",
  365 + fv = "MMredirectURL=" + encodeURIComponent(win.location.toString().replace(/&/g,"%26")) + "&MMplayerType=" + pt + "&MMdoctitle=" + doc.title;
  366 + if (typeof par.flashvars != UNDEF) {
  367 + par.flashvars += "&" + fv;
  368 + }
  369 + else {
  370 + par.flashvars = fv;
  371 + }
  372 + // IE only: when a SWF is loading (AND: not available in cache) wait for the readyState of the object element to become 4 before removing it,
  373 + // because you cannot properly cancel a loading SWF file without breaking browser load references, also obj.onreadystatechange doesn't work
  374 + if (ua.ie && obj.readyState != 4) {
  375 + var newObj = createElement("div");
  376 + replaceElemIdStr += "SWFObjectNew";
  377 + newObj.setAttribute("id", replaceElemIdStr);
  378 + obj.parentNode.insertBefore(newObj, obj); // insert placeholder div that will be replaced by the object element that loads expressinstall.swf
  379 + obj.style.display = "none";
  380 + removeSWF(obj); //removeSWF accepts elements now
  381 + }
  382 + createSWF(att, par, replaceElemIdStr);
  383 + }
  384 + }
  385 +
  386 + /* Functions to abstract and display fallback content
  387 + */
  388 + function displayFbContent(obj) {
  389 + if (ua.ie && obj.readyState != 4) {
  390 + // IE only: when a SWF is loading (AND: not available in cache) wait for the readyState of the object element to become 4 before removing it,
  391 + // because you cannot properly cancel a loading SWF file without breaking browser load references, also obj.onreadystatechange doesn't work
  392 + obj.style.display = "none";
  393 + var el = createElement("div");
  394 + obj.parentNode.insertBefore(el, obj); // insert placeholder div that will be replaced by the fallback content
  395 + el.parentNode.replaceChild(abstractFbContent(obj), el);
  396 + removeSWF(obj); //removeSWF accepts elements now
  397 + }
  398 + else {
  399 + obj.parentNode.replaceChild(abstractFbContent(obj), obj);
  400 + }
  401 + }
  402 +
  403 + function abstractFbContent(obj) {
  404 + var ac = createElement("div");
  405 + if (ua.win && ua.ie) {
  406 + ac.innerHTML = obj.innerHTML;
  407 + }
  408 + else {
  409 + var nestedObj = obj.getElementsByTagName(OBJECT)[0];
  410 + if (nestedObj) {
  411 + var c = nestedObj.childNodes;
  412 + if (c) {
  413 + var cl = c.length;
  414 + for (var i = 0; i < cl; i++) {
  415 + if (!(c[i].nodeType == 1 && c[i].nodeName == "PARAM") && !(c[i].nodeType == 8)) {
  416 + ac.appendChild(c[i].cloneNode(true));
  417 + }
  418 + }
  419 + }
  420 + }
  421 + }
  422 + return ac;
  423 + }
  424 +
  425 +
  426 + function createIeObject(url, param_str){
  427 + var div = createElement("div");
  428 + div.innerHTML = "<object classid='clsid:D27CDB6E-AE6D-11cf-96B8-444553540000'><param name='movie' value='" +url + "'>" + param_str + "</object>";
  429 + return div.firstChild;
  430 + }
  431 +
  432 + /* Cross-browser dynamic SWF creation
  433 + */
  434 + function createSWF(attObj, parObj, id) {
  435 +
  436 + var r, el = getElementById(id);
  437 +
  438 + id = getId(id); // ensure id is truly an ID and not an element
  439 +
  440 + if (ua.wk && ua.wk < 312) { return r; }
  441 +
  442 + if (el) {
  443 +
  444 + var o = (ua.ie) ? createElement("div") : createElement(OBJECT),
  445 + attr,
  446 + attr_lower,
  447 + param;
  448 +
  449 + if (typeof attObj.id == UNDEF) { // if no 'id' is defined for the object element, it will inherit the 'id' from the fallback content
  450 + attObj.id = id;
  451 + }
  452 +
  453 + //Add params
  454 + for (param in parObj) {
  455 + //filter out prototype additions from other potential libraries and IE specific param element
  456 + if (parObj.hasOwnProperty(param) && param.toLowerCase() !== "movie") {
  457 + createObjParam(o, param, parObj[param]);
  458 + }
  459 + }
  460 +
  461 + //Create IE object, complete with param nodes
  462 + if(ua.ie){ o = createIeObject(attObj.data, o.innerHTML); }
  463 +
  464 + //Add attributes to object
  465 + for (attr in attObj) {
  466 + if (attObj.hasOwnProperty(attr)) { // filter out prototype additions from other potential libraries
  467 +
  468 + attr_lower = attr.toLowerCase();
  469 +
  470 + // 'class' is an ECMA4 reserved keyword
  471 + if (attr_lower === "styleclass") {
  472 + o.setAttribute("class", attObj[attr]);
  473 + } else if (attr_lower !== "classid" && attr_lower !== "data") {
  474 + o.setAttribute(attr, attObj[attr]);
  475 + }
  476 +
  477 + }
  478 + }
  479 +
  480 + if (ua.ie) {
  481 +
  482 + objIdArr[objIdArr.length] = attObj.id; // stored to fix object 'leaks' on unload (dynamic publishing only)
  483 +
  484 + } else {
  485 +
  486 + o.setAttribute("type", FLASH_MIME_TYPE);
  487 + o.setAttribute("data", attObj.data);
  488 +
  489 + }
  490 +
  491 + el.parentNode.replaceChild(o, el);
  492 + r = o;
  493 +
  494 + }
  495 + return r;
  496 + }
  497 +
  498 +
  499 + function createObjParam(el, pName, pValue) {
  500 + var p = createElement("param");
  501 + p.setAttribute("name", pName);
  502 + p.setAttribute("value", pValue);
  503 + el.appendChild(p);
  504 + }
  505 +
  506 + /* Cross-browser SWF removal
  507 + - Especially needed to safely and completely remove a SWF in Internet Explorer
  508 + */
  509 + function removeSWF(id) {
  510 + var obj = getElementById(id);
  511 + if (obj && obj.nodeName.toUpperCase() == "OBJECT") {
  512 + if (ua.ie) {
  513 + obj.style.display = "none";
  514 + (function removeSWFInIE(){
  515 + if (obj.readyState == 4) {
  516 + //This step prevents memory leaks in Internet Explorer
  517 + for (var i in obj) {
  518 + if (typeof obj[i] == "function") {
  519 + obj[i] = null;
  520 + }
  521 + }
  522 + obj.parentNode.removeChild(obj);
  523 + } else {
  524 + setTimeout(removeSWFInIE, 10);
  525 + }
  526 + }());
  527 + }
  528 + else {
  529 + obj.parentNode.removeChild(obj);
  530 + }
  531 + }
  532 + }
  533 +
  534 + function isElement(id){
  535 + return (id && id.nodeType && id.nodeType === 1);
  536 + }
  537 +
  538 + function getId(thing){
  539 + return (isElement(thing)) ? thing.id : thing;
  540 + }
  541 +
  542 + /* Functions to optimize JavaScript compression
  543 + */
  544 + function getElementById(id) {
  545 +
  546 + //Allow users to pass an element OR an element's ID
  547 + if(isElement(id)){ return id; }
  548 +
  549 + var el = null;
  550 + try {
  551 + el = doc.getElementById(id);
  552 + }
  553 + catch (e) {}
  554 + return el;
  555 + }
  556 +
  557 + function createElement(el) {
  558 + return doc.createElement(el);
  559 + }
  560 +
  561 + //To aid compression; replaces 14 instances of pareseInt with radix
  562 + function toInt(str){
  563 + return parseInt(str, 10);
  564 + }
  565 +
  566 + /* Updated attachEvent function for Internet Explorer
  567 + - Stores attachEvent information in an Array, so on unload the detachEvent functions can be called to avoid memory leaks
  568 + */
  569 + function addListener(target, eventType, fn) {
  570 + target.attachEvent(eventType, fn);
  571 + listenersArr[listenersArr.length] = [target, eventType, fn];
  572 + }
  573 +
  574 + /* Flash Player and SWF content version matching
  575 + */
  576 + function hasPlayerVersion(rv) {
  577 + rv += ""; //Coerce number to string, if needed.
  578 + var pv = ua.pv, v = rv.split(".");
  579 + v[0] = toInt(v[0]);
  580 + v[1] = toInt(v[1]) || 0; // supports short notation, e.g. "9" instead of "9.0.0"
  581 + v[2] = toInt(v[2]) || 0;
  582 + return (pv[0] > v[0] || (pv[0] == v[0] && pv[1] > v[1]) || (pv[0] == v[0] && pv[1] == v[1] && pv[2] >= v[2])) ? true : false;
  583 + }
  584 +
  585 + /* Cross-browser dynamic CSS creation
  586 + - Based on Bobby van der Sluis' solution: http://www.bobbyvandersluis.com/articles/dynamicCSS.php
  587 + */
  588 + function createCSS(sel, decl, media, newStyle) {
  589 + var h = doc.getElementsByTagName("head")[0];
  590 + if (!h) { return; } // to also support badly authored HTML pages that lack a head element
  591 + var m = (typeof media == "string") ? media : "screen";
  592 + if (newStyle) {
  593 + dynamicStylesheet = null;
  594 + dynamicStylesheetMedia = null;
  595 + }
  596 + if (!dynamicStylesheet || dynamicStylesheetMedia != m) {
  597 + // create dynamic stylesheet + get a global reference to it
  598 + var s = createElement("style");
  599 + s.setAttribute("type", "text/css");
  600 + s.setAttribute("media", m);
  601 + dynamicStylesheet = h.appendChild(s);
  602 + if (ua.ie && typeof doc.styleSheets != UNDEF && doc.styleSheets.length > 0) {
  603 + dynamicStylesheet = doc.styleSheets[doc.styleSheets.length - 1];
  604 + }
  605 + dynamicStylesheetMedia = m;
  606 + }
  607 + // add style rule
  608 + if(dynamicStylesheet){
  609 + if (typeof dynamicStylesheet.addRule != UNDEF) {
  610 + dynamicStylesheet.addRule(sel, decl);
  611 + } else if (typeof doc.createTextNode != UNDEF) {
  612 + dynamicStylesheet.appendChild(doc.createTextNode(sel + " {" + decl + "}"));
  613 + }
  614 + }
  615 + }
  616 +
  617 + function setVisibility(id, isVisible) {
  618 + if (!autoHideShow) { return; }
  619 + var v = isVisible ? "visible" : "hidden",
  620 + el = getElementById(id);
  621 + if (isDomLoaded && el) {
  622 + el.style.visibility = v;
  623 + } else if(typeof id === "string"){
  624 + createCSS("#" + id, "visibility:" + v);
  625 + }
  626 + }
  627 +
  628 + /* Filter to avoid XSS attacks
  629 + */
  630 + function urlEncodeIfNecessary(s) {
  631 + var regex = /[\\\"<>\.;]/;
  632 + var hasBadChars = regex.exec(s) != null;
  633 + return hasBadChars && typeof encodeURIComponent != UNDEF ? encodeURIComponent(s) : s;
  634 + }
  635 +
  636 + /* Release memory to avoid memory leaks caused by closures, fix hanging audio/video threads and force open sockets/NetConnections to disconnect (Internet Explorer only)
  637 + */
  638 + var cleanup = function() {
  639 + if (ua.ie) {
  640 + window.attachEvent("onunload", function() {
  641 + // remove listeners to avoid memory leaks
  642 + var ll = listenersArr.length;
  643 + for (var i = 0; i < ll; i++) {
  644 + listenersArr[i][0].detachEvent(listenersArr[i][1], listenersArr[i][2]);
  645 + }
  646 + // cleanup dynamically embedded objects to fix audio/video threads and force open sockets and NetConnections to disconnect
  647 + var il = objIdArr.length;
  648 + for (var j = 0; j < il; j++) {
  649 + removeSWF(objIdArr[j]);
  650 + }
  651 + // cleanup library's main closures to avoid memory leaks
  652 + for (var k in ua) {
  653 + ua[k] = null;
  654 + }
  655 + ua = null;
  656 + for (var l in swfobject) {
  657 + swfobject[l] = null;
  658 + }
  659 + swfobject = null;
  660 + });
  661 + }
  662 + }();
  663 +
  664 + return {
  665 + /* Public API
  666 + - Reference: http://code.google.com/p/swfobject/wiki/documentation
  667 + */
  668 + registerObject: function(objectIdStr, swfVersionStr, xiSwfUrlStr, callbackFn) {
  669 + if (ua.w3 && objectIdStr && swfVersionStr) {
  670 + var regObj = {};
  671 + regObj.id = objectIdStr;
  672 + regObj.swfVersion = swfVersionStr;
  673 + regObj.expressInstall = xiSwfUrlStr;
  674 + regObj.callbackFn = callbackFn;
  675 + regObjArr[regObjArr.length] = regObj;
  676 + setVisibility(objectIdStr, false);
  677 + }
  678 + else if (callbackFn) {
  679 + callbackFn({success:false, id:objectIdStr});
  680 + }
  681 + },
  682 +
  683 + getObjectById: function(objectIdStr) {
  684 + if (ua.w3) {
  685 + return getObjectById(objectIdStr);
  686 + }
  687 + },
  688 +
  689 + embedSWF: function(swfUrlStr, replaceElemIdStr, widthStr, heightStr, swfVersionStr, xiSwfUrlStr, flashvarsObj, parObj, attObj, callbackFn) {
  690 +
  691 + var id = getId(replaceElemIdStr),
  692 + callbackObj = {success:false, id:id};
  693 +
  694 + if (ua.w3 && !(ua.wk && ua.wk < 312) && swfUrlStr && replaceElemIdStr && widthStr && heightStr && swfVersionStr) {
  695 + setVisibility(id, false);
  696 + addDomLoadEvent(function() {
  697 + widthStr += ""; // auto-convert to string
  698 + heightStr += "";
  699 + var att = {};
  700 + if (attObj && typeof attObj === OBJECT) {
  701 + for (var i in attObj) { // copy object to avoid the use of references, because web authors often reuse attObj for multiple SWFs
  702 + att[i] = attObj[i];
  703 + }
  704 + }
  705 + att.data = swfUrlStr;
  706 + att.width = widthStr;
  707 + att.height = heightStr;
  708 + var par = {};
  709 + if (parObj && typeof parObj === OBJECT) {
  710 + for (var j in parObj) { // copy object to avoid the use of references, because web authors often reuse parObj for multiple SWFs
  711 + par[j] = parObj[j];
  712 + }
  713 + }
  714 + if (flashvarsObj && typeof flashvarsObj === OBJECT) {
  715 + for (var k in flashvarsObj) { // copy object to avoid the use of references, because web authors often reuse flashvarsObj for multiple SWFs
  716 + if(flashvarsObj.hasOwnProperty(k)){
  717 +
  718 + var key = (encodeURI_enabled) ? encodeURIComponent(k) : k,
  719 + value = (encodeURI_enabled) ? encodeURIComponent(flashvarsObj[k]) : flashvarsObj[k];
  720 +
  721 + if (typeof par.flashvars != UNDEF) {
  722 + par.flashvars += "&" + key + "=" + value;
  723 + }
  724 + else {
  725 + par.flashvars = key + "=" + value;
  726 + }
  727 +
  728 + }
  729 + }
  730 + }
  731 + if (hasPlayerVersion(swfVersionStr)) { // create SWF
  732 + var obj = createSWF(att, par, replaceElemIdStr);
  733 + if (att.id == id) {
  734 + setVisibility(id, true);
  735 + }
  736 + callbackObj.success = true;
  737 + callbackObj.ref = obj;
  738 + callbackObj.id = obj.id;
  739 + }
  740 + else if (xiSwfUrlStr && canExpressInstall()) { // show Adobe Express Install
  741 + att.data = xiSwfUrlStr;
  742 + showExpressInstall(att, par, replaceElemIdStr, callbackFn);
  743 + return;
  744 + }
  745 + else { // show fallback content
  746 + setVisibility(id, true);
  747 + }
  748 + if (callbackFn) { callbackFn(callbackObj); }
  749 + });
  750 + }
  751 + else if (callbackFn) { callbackFn(callbackObj); }
  752 + },
  753 +
  754 + switchOffAutoHideShow: function() {
  755 + autoHideShow = false;
  756 + },
  757 +
  758 + enableUriEncoding: function (bool) {
  759 + encodeURI_enabled = (typeof bool === UNDEF) ? true : bool;
  760 + },
  761 +
  762 + ua: ua,
  763 +
  764 + getFlashPlayerVersion: function() {
  765 + return { major:ua.pv[0], minor:ua.pv[1], release:ua.pv[2] };
  766 + },
  767 +
  768 + hasFlashPlayerVersion: hasPlayerVersion,
  769 +
  770 + createSWF: function(attObj, parObj, replaceElemIdStr) {
  771 + if (ua.w3) {
  772 + return createSWF(attObj, parObj, replaceElemIdStr);
  773 + }
  774 + else {
  775 + return undefined;
  776 + }
  777 + },
  778 +
  779 + showExpressInstall: function(att, par, replaceElemIdStr, callbackFn) {
  780 + if (ua.w3 && canExpressInstall()) {
  781 + showExpressInstall(att, par, replaceElemIdStr, callbackFn);
  782 + }
  783 + },
  784 +
  785 + removeSWF: function(objElemIdStr) {
  786 + if (ua.w3) {
  787 + removeSWF(objElemIdStr);
  788 + }
  789 + },
  790 +
  791 + createCSS: function(selStr, declStr, mediaStr, newStyleBoolean) {
  792 + if (ua.w3) {
  793 + createCSS(selStr, declStr, mediaStr, newStyleBoolean);
  794 + }
  795 + },
  796 +
  797 + addDomLoadEvent: addDomLoadEvent,
  798 +
  799 + addLoadEvent: addLoadEvent,
  800 +
  801 + getQueryParamValue: function(param) {
  802 + var q = doc.location.search || doc.location.hash;
  803 + if (q) {
  804 + if (/\?/.test(q)) { q = q.split("?")[1]; } // strip question mark
  805 + if (param == null) {
  806 + return urlEncodeIfNecessary(q);
  807 + }
  808 + var pairs = q.split("&");
  809 + for (var i = 0; i < pairs.length; i++) {
  810 + if (pairs[i].substring(0, pairs[i].indexOf("=")) == param) {
  811 + return urlEncodeIfNecessary(pairs[i].substring((pairs[i].indexOf("=") + 1)));
  812 + }
  813 + }
  814 + }
  815 + return "";
  816 + },
  817 +
  818 + // For internal usage only
  819 + expressInstallCallback: function() {
  820 + if (isExpressInstallActive) {
  821 + var obj = getElementById(EXPRESS_INSTALL_ID);
  822 + if (obj && storedFbContent) {
  823 + obj.parentNode.replaceChild(storedFbContent, obj);
  824 + if (storedFbContentId) {
  825 + setVisibility(storedFbContentId, true);
  826 + if (ua.ie) { storedFbContent.style.display = "block"; }
  827 + }
  828 + if (storedCallbackFn) { storedCallbackFn(storedCallbackObj); }
  829 + }
  830 + isExpressInstallActive = false;
  831 + }
  832 + },
  833 +
  834 + version: "2.3"
  835 +
  836 + };
  837 +}();
6 app/assets/stylesheets/application.css
@@ -29,6 +29,12 @@
29 29 text-decoration: none;
30 30 }
31 31
  32 + .input-append textarea {
  33 + -webkit-border-top-right-radius: 0;
  34 + -moz-border-radius-topright: 0;
  35 + border-top-right-radius: 0;
  36 + }
  37 +
32 38 .user-session {
33 39 color: #999;
34 40 margin: 10px 0px 30px 0px;
39 app/views/accounts/generic_accounts/_form.html.erb
@@ -2,10 +2,8 @@
2 2
3 3 <div class="span8">
4 4 <%= form_for [ :accounts, @account ] do |f| %>
5   - <% if controller.action_name != 'show' %>
6   - <%= f.label :title %>
7   - <%= f.text_field :title, :class => 'span7' %>
8   - <% end %>
  5 + <%= f.label :title %>
  6 + <%= f.text_field :title, :class => 'span7' %>
9 7
10 8 <%= f.label :username %>
11 9 <%= f.text_field :username, :class => 'span7' %>
@@ -15,24 +13,21 @@
15 13
16 14 <%= f.label :comments %>
17 15 <%= f.text_area :comments, :class => 'span8', :rows => 6 %>
18   -
19   - <% if controller.action_name != 'show' %>
20   - <fieldset>
21   - <legend>Groups</legend>
22   - <br />
23   - <%= hidden_field_tag "generic_account[group_ids][]", nil%>
24   - <% @allowed_groups.each do |group| %>
25   - <label class="checkbox inline">
26   - <%= check_box_tag 'generic_account[group_ids][]', group.id, @account.groups.include?(group) %>
27   - <%= group.name %>
28   - </label>
29   - <% end %>
30   - </fieldset>
31   -
32 16
33   - <hr />
34   - <button type="submit" class="btn"><%= @account.new_record? ? 'Create' : 'Update' %> Account</button>
35   - <% end %>
36   -
  17 + <fieldset>
  18 + <legend>Groups</legend>
  19 + <br />
  20 + <%= hidden_field_tag "generic_account[group_ids][]", nil%>
  21 + <% @allowed_groups.each do |group| %>
  22 + <label class="checkbox inline">
  23 + <%= check_box_tag 'generic_account[group_ids][]', group.id, @account.groups.include?(group) %>
  24 + <%= group.name %>
  25 + </label>
  26 + <% end %>
  27 + </fieldset>
  28 +
  29 + <hr />
  30 + <button type="submit" class="btn"><%= @account.new_record? ? 'Create' : 'Update' %> Account</button>
  31 +
37 32 <% end %>
38 33 </div>
20 app/views/accounts/generic_accounts/show.html.erb
@@ -9,4 +9,22 @@
9 9 </h3>
10 10 </div>
11 11
12   -<%= render 'form' %>
  12 +<div class="span8">
  13 + <%= form_for [ :accounts, @account ] do |f| %>
  14 + <div class="input-append">
  15 + <%= f.label :username %>
  16 + <%= f.text_field :username, :class => 'span7' %>
  17 + <span class="add-on"><span class="clippy" data-text="<%= @account.username %>"></span></span>
  18 + </div>
  19 +
  20 + <div class="input-append">
  21 + <%= f.label :password %>
  22 + <%= f.text_field :password, :class => 'span7' %>
  23 + <span class="add-on"><span class="clippy" data-text="<%= @account.password %>"></span></span>
  24 + </div>
  25 +
  26 + <%= f.label :comments %>
  27 + <%= f.text_area :comments, :class => 'span8', :rows => 6 %>
  28 + <% end %>
  29 +</div>
  30 +
40 app/views/accounts/web_accounts/_form.html.erb
@@ -2,10 +2,8 @@
2 2
3 3 <div class="span8">
4 4 <%= form_for [ :accounts, @account ] do |f| %>
5   - <% if controller.action_name != 'show' %>
6   - <%= f.label :title %>
7   - <%= f.text_field :title, :class => 'span7' %>
8   - <% end %>
  5 + <%= f.label :title %>
  6 + <%= f.text_field :title, :class => 'span7' %>
9 7
10 8 <%= f.label :url %>
11 9 <%= f.text_field :url, :class => 'span7' %>
@@ -18,23 +16,21 @@
18 16
19 17 <%= f.label :comments %>
20 18 <%= f.text_area :comments, :class => 'span8', :rows => 6 %>
21   -
22   - <% if controller.action_name != 'show' %>
23   - <fieldset>
24   - <legend>Groups</legend>
25   - <br />
26   - <%= hidden_field_tag "web_account[group_ids][]", nil%>
27   - <% @allowed_groups.each do |group| %>
28   - <label class="checkbox inline">
29   - <%= check_box_tag 'web_account[group_ids][]', group.id, @account.groups.include?(group) %>
30   - <%= group.name %>
31   - </label>
32   - <% end %>
33   - </fieldset>
34   -
35   - <hr />
36   - <button type="submit" class="btn"><%= @account.new_record? ? 'Create' : 'Update' %> Account</button>
37   - <% end %>
  19 +
  20 + <fieldset>
  21 + <legend>Groups</legend>
  22 + <br />
  23 + <%= hidden_field_tag "web_account[group_ids][]", nil%>
  24 + <% @allowed_groups.each do |group| %>
  25 + <label class="checkbox inline">
  26 + <%= check_box_tag 'web_account[group_ids][]', group.id, @account.groups.include?(group) %>
  27 + <%= group.name %>
  28 + </label>
  29 + <% end %>
  30 + </fieldset>
  31 +
  32 + <hr />
  33 + <button type="submit" class="btn"><%= @account.new_record? ? 'Create' : 'Update' %> Account</button>
38 34
39 35 <% end %>
40   -</div>
  36 +</div>
25 app/views/accounts/web_accounts/show.html.erb
@@ -9,4 +9,27 @@
9 9 </h3>
10 10 </div>
11 11
12   -<%= render 'form' %>
  12 +<div class="span8">
  13 + <%= form_for [ :accounts, @account ] do |f| %>
  14 + <div class="input-append">
  15 + <%= f.label :url %>
  16 + <%= f.text_field :url, :class => 'span7' %>
  17 + <span class="add-on"><span class="clippy" data-text="<%= @account.url %>"></span></span>
  18 + </div>
  19 +
  20 + <div class="input-append">
  21 + <%= f.label :username %>
  22 + <%= f.text_field :username, :class => 'span7' %>
  23 + <span class="add-on"><span class="clippy" data-text="<%= @account.username %>"></span></span>
  24 + </div>
  25 +
  26 + <div class="input-append">
  27 + <%= f.label :password %>
  28 + <%= f.text_field :password, :class => 'span7' %>
  29 + <span class="add-on"><span class="clippy" data-text="<%= @account.password %>"></span></span>
  30 + </div>
  31 +
  32 + <%= f.label :comments %>
  33 + <%= f.text_area :comments, :class => 'span8', :rows => 6 %>
  34 + <% end %>
  35 +</div>
4 app/views/layouts/application.html.erb
@@ -2,8 +2,8 @@
2 2 <html>
3 3 <head>
4 4 <title>Roswell</title>
5   - <%= stylesheet_link_tag "application", "font-awesome", :media => "all" %>
6   - <%= javascript_include_tag "application", "bootstrap.js" %>
  5 + <%= stylesheet_link_tag 'application', 'font-awesome', :media => 'all' %>
  6 + <%= javascript_include_tag 'application', 'bootstrap.js', 'jquery.clippy.js' %>
7 7 <%= csrf_meta_tags %>
8 8 </head>
9 9 <body>
32 app/views/notes/_form.html.erb
@@ -2,29 +2,25 @@
2 2
3 3 <div class="span8">
4 4 <%= form_for @note do |f| %>
5   - <% if controller.action_name != 'show' %>
6 5 <%= f.label :title %>
7 6 <%= f.text_field :title, :class => 'span7' %>
8   - <% end %>