Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Initial revision

  • Loading branch information...
commit 1f3bd20b2eed94c49653be8910d85cd32520c767 0 parents
Paul Carey authored
20 LICENSE
... ... @@ -0,0 +1,20 @@
  1 +Copyright (c) 2008 Paul Carey
  2 +
  3 +Permission is hereby granted, free of charge, to any person obtaining
  4 +a copy of this software and associated documentation files (the
  5 +"Software"), to deal in the Software without restriction, including
  6 +without limitation the rights to use, copy, modify, merge, publish,
  7 +distribute, sublicense, and/or sell copies of the Software, and to
  8 +permit persons to whom the Software is furnished to do so, subject to
  9 +the following conditions:
  10 +
  11 +The above copyright notice and this permission notice shall be
  12 +included in all copies or substantial portions of the Software.
  13 +
  14 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  15 +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  16 +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  17 +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  18 +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  19 +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  20 +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
52 README.textile
Source Rendered
... ... @@ -0,0 +1,52 @@
  1 +h3. Overview
  2 +
  3 +Fuschia is a graphical document browser for CouchDB. It's built on prefuse and Flex.
  4 +
  5 +h3. Using
  6 +
  7 +Clone this repo, set @DB_NAME@ in @upload_binaries.sh@ to your target database and run @./upload_binaries.sh@. This will create a design document named fuschia containing views that, for a given document, retrieve all documents that it points to, and all documents that point to it.
  8 +
  9 +Now direct your browser at http://localhost:5984/mydb/_design/fuschia/Fuschia.html, enter a full database uri (e.g. http://localhost:5984/mydb), seed document id and click load. You should be able to browse through your database.
  10 +
  11 +Fushica is at its best when it colors document nodes and displays document summaries. To have this happen, create a document at @mydb/fuschia@ based on the following example. You can upload it easily with curl, for example, @curl -T fuschia.json localhost:5984/mydb/fuschia@.
  12 +
  13 +<pre>
  14 +<code>
  15 +// classProperty is used to distinguish doc types. So for RelaxDB this would be 'class', for CouchRest::Model, 'couchrest-type'.
  16 +// fillColor represents the document node color. The first two characters specify an alpha value.
  17 +// summaryProperty should specify the most descriptive property of the document.
  18 +{
  19 + "_id" : "fuschia",
  20 + "classProperty" : "class",
  21 + "User" : {
  22 + "fillColor" : "0xff3355cc",
  23 + "summaryProperty" : "name"
  24 + },
  25 + "Post" : {
  26 + "fillColor" : "0xffcc5533",
  27 + "summaryProperty" : "contents"
  28 + },
  29 + "Comment" : {
  30 + "fillColor" : "0xff33cc55",
  31 + "summaryProperty" : "contents"
  32 + }
  33 +}
  34 +</code>
  35 +</pre>
  36 +
  37 +
  38 +Note: If your database doesn't use standard UUIDs, modify @isDocId@ in @src/fuschia_queries.js@ as necessary and overwrite @bin/fuschia_queries.json@ with your own version.
  39 +
  40 +h3. Hacking
  41 +
  42 +The "flare tutorial":http://flare.prefuse.org/tutorial is the best place to get started with flare. If you're new to CouchDB, the "wiki":http://wiki.apache.org/couchdb/ is a great place to begin.
  43 +
  44 +Instructions on developing with "flare in textmate":http://arrifana.org/blog/2008/03/flare-flex-sdk-and-mac-osx/.
  45 +
  46 +h3. Known Issues
  47 +
  48 + * Edges don't display bi-directional arrows
  49 +
  50 +h3. Example
  51 +
  52 +The example directory contains a script that feeds some sample data into CouchDB using RelaxDB. However, following the instructions in the 'Using' section above, you should be able to explore any CouchDB database that contains inter-document references.
292 bin/AC_OETags.js
... ... @@ -0,0 +1,292 @@
  1 +// Flash Player Version Detection - Rev 1.6
  2 +// Detect Client Browser type
  3 +// Copyright(c) 2005-2006 Adobe Macromedia Software, LLC. All rights reserved.
  4 +var isIE = (navigator.appVersion.indexOf("MSIE") != -1) ? true : false;
  5 +var isWin = (navigator.appVersion.toLowerCase().indexOf("win") != -1) ? true : false;
  6 +var isOpera = (navigator.userAgent.indexOf("Opera") != -1) ? true : false;
  7 +
  8 +function ControlVersion()
  9 +{
  10 + var version;
  11 + var axo;
  12 + var e;
  13 +
  14 + // NOTE : new ActiveXObject(strFoo) throws an exception if strFoo isn't in the registry
  15 +
  16 + try {
  17 + // version will be set for 7.X or greater players
  18 + axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7");
  19 + version = axo.GetVariable("$version");
  20 + } catch (e) {
  21 + }
  22 +
  23 + if (!version)
  24 + {
  25 + try {
  26 + // version will be set for 6.X players only
  27 + axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6");
  28 +
  29 + // installed player is some revision of 6.0
  30 + // GetVariable("$version") crashes for versions 6.0.22 through 6.0.29,
  31 + // so we have to be careful.
  32 +
  33 + // default to the first public version
  34 + version = "WIN 6,0,21,0";
  35 +
  36 + // throws if AllowScripAccess does not exist (introduced in 6.0r47)
  37 + axo.AllowScriptAccess = "always";
  38 +
  39 + // safe to call for 6.0r47 or greater
  40 + version = axo.GetVariable("$version");
  41 +
  42 + } catch (e) {
  43 + }
  44 + }
  45 +
  46 + if (!version)
  47 + {
  48 + try {
  49 + // version will be set for 4.X or 5.X player
  50 + axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.3");
  51 + version = axo.GetVariable("$version");
  52 + } catch (e) {
  53 + }
  54 + }
  55 +
  56 + if (!version)
  57 + {
  58 + try {
  59 + // version will be set for 3.X player
  60 + axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.3");
  61 + version = "WIN 3,0,18,0";
  62 + } catch (e) {
  63 + }
  64 + }
  65 +
  66 + if (!version)
  67 + {
  68 + try {
  69 + // version will be set for 2.X player
  70 + axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash");
  71 + version = "WIN 2,0,0,11";
  72 + } catch (e) {
  73 + version = -1;
  74 + }
  75 + }
  76 +
  77 + return version;
  78 +}
  79 +
  80 +// JavaScript helper required to detect Flash Player PlugIn version information
  81 +function GetSwfVer(){
  82 + // NS/Opera version >= 3 check for Flash plugin in plugin array
  83 + var flashVer = -1;
  84 +
  85 + if (navigator.plugins != null && navigator.plugins.length > 0) {
  86 + if (navigator.plugins["Shockwave Flash 2.0"] || navigator.plugins["Shockwave Flash"]) {
  87 + var swVer2 = navigator.plugins["Shockwave Flash 2.0"] ? " 2.0" : "";
  88 + var flashDescription = navigator.plugins["Shockwave Flash" + swVer2].description;
  89 + var descArray = flashDescription.split(" ");
  90 + var tempArrayMajor = descArray[2].split(".");
  91 + var versionMajor = tempArrayMajor[0];
  92 + var versionMinor = tempArrayMajor[1];
  93 + var versionRevision = descArray[3];
  94 + if (versionRevision == "") {
  95 + versionRevision = descArray[4];
  96 + }
  97 + if (versionRevision[0] == "d") {
  98 + versionRevision = versionRevision.substring(1);
  99 + } else if (versionRevision[0] == "r") {
  100 + versionRevision = versionRevision.substring(1);
  101 + if (versionRevision.indexOf("d") > 0) {
  102 + versionRevision = versionRevision.substring(0, versionRevision.indexOf("d"));
  103 + }
  104 + } else if (versionRevision[0] == "b") {
  105 + versionRevision = versionRevision.substring(1);
  106 + }
  107 + var flashVer = versionMajor + "." + versionMinor + "." + versionRevision;
  108 + }
  109 + }
  110 + // MSN/WebTV 2.6 supports Flash 4
  111 + else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.6") != -1) flashVer = 4;
  112 + // WebTV 2.5 supports Flash 3
  113 + else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.5") != -1) flashVer = 3;
  114 + // older WebTV supports Flash 2
  115 + else if (navigator.userAgent.toLowerCase().indexOf("webtv") != -1) flashVer = 2;
  116 + else if ( isIE && isWin && !isOpera ) {
  117 + flashVer = ControlVersion();
  118 + }
  119 + return flashVer;
  120 +}
  121 +
  122 +// When called with reqMajorVer, reqMinorVer, reqRevision returns true if that version or greater is available
  123 +function DetectFlashVer(reqMajorVer, reqMinorVer, reqRevision)
  124 +{
  125 + versionStr = GetSwfVer();
  126 + if (versionStr == -1 ) {
  127 + return false;
  128 + } else if (versionStr != 0) {
  129 + if(isIE && isWin && !isOpera) {
  130 + // Given "WIN 2,0,0,11"
  131 + tempArray = versionStr.split(" "); // ["WIN", "2,0,0,11"]
  132 + tempString = tempArray[1]; // "2,0,0,11"
  133 + versionArray = tempString.split(","); // ['2', '0', '0', '11']
  134 + } else {
  135 + versionArray = versionStr.split(".");
  136 + }
  137 + var versionMajor = versionArray[0];
  138 + var versionMinor = versionArray[1];
  139 + var versionRevision = versionArray[2];
  140 +
  141 + // is the major.revision >= requested major.revision AND the minor version >= requested minor
  142 + if (versionMajor > parseFloat(reqMajorVer)) {
  143 + return true;
  144 + } else if (versionMajor == parseFloat(reqMajorVer)) {
  145 + if (versionMinor > parseFloat(reqMinorVer))
  146 + return true;
  147 + else if (versionMinor == parseFloat(reqMinorVer)) {
  148 + if (versionRevision >= parseFloat(reqRevision))
  149 + return true;
  150 + }
  151 + }
  152 + return false;
  153 + }
  154 +}
  155 +
  156 +function AC_AddExtension(src, ext)
  157 +{
  158 + var qIndex = src.indexOf('?');
  159 + if ( qIndex != -1)
  160 + {
  161 + // Add the extention (if needed) before the query params
  162 + var path = src.substring(0, qIndex);
  163 + if (path.length >= ext.length && path.lastIndexOf(ext) == (path.length - ext.length))
  164 + return src;
  165 + else
  166 + return src.replace(/\?/, ext+'?');
  167 + }
  168 + else
  169 + {
  170 + // Add the extension (if needed) to the end of the URL
  171 + if (src.length >= ext.length && src.lastIndexOf(ext) == (src.length - ext.length))
  172 + return src; // Already have extension
  173 + else
  174 + return src + ext;
  175 + }
  176 +}
  177 +
  178 +function AC_Generateobj(objAttrs, params, embedAttrs)
  179 +{
  180 + var str = '';
  181 + if (isIE && isWin && !isOpera)
  182 + {
  183 + str += '<object ';
  184 + for (var i in objAttrs)
  185 + str += i + '="' + objAttrs[i] + '" ';
  186 + str += '>';
  187 + for (var i in params)
  188 + str += '<param name="' + i + '" value="' + params[i] + '" /> ';
  189 + str += '</object>';
  190 + } else {
  191 + str += '<embed ';
  192 + for (var i in embedAttrs)
  193 + str += i + '="' + embedAttrs[i] + '" ';
  194 + str += '> </embed>';
  195 + }
  196 +
  197 + document.write(str);
  198 +}
  199 +
  200 +function AC_FL_RunContent(){
  201 + var ret =
  202 + AC_GetArgs
  203 + ( arguments, ".swf", "movie", "clsid:d27cdb6e-ae6d-11cf-96b8-444553540000"
  204 + , "application/x-shockwave-flash"
  205 + );
  206 + AC_Generateobj(ret.objAttrs, ret.params, ret.embedAttrs);
  207 +}
  208 +
  209 +function AC_GetArgs(args, ext, srcParamName, classid, mimeType){
  210 + var ret = new Object();
  211 + ret.embedAttrs = new Object();
  212 + ret.params = new Object();
  213 + ret.objAttrs = new Object();
  214 + for (var i=0; i < args.length; i=i+2){
  215 + var currArg = args[i].toLowerCase();
  216 +
  217 + switch (currArg){
  218 + case "classid":
  219 + break;
  220 + case "pluginspage":
  221 + ret.embedAttrs[args[i]] = args[i+1];
  222 + break;
  223 + case "src":
  224 + case "movie":
  225 + args[i+1] = AC_AddExtension(args[i+1], ext);
  226 + ret.embedAttrs["src"] = args[i+1];
  227 + ret.params[srcParamName] = args[i+1];
  228 + break;
  229 + case "onafterupdate":
  230 + case "onbeforeupdate":
  231 + case "onblur":
  232 + case "oncellchange":
  233 + case "onclick":
  234 + case "ondblClick":
  235 + case "ondrag":
  236 + case "ondragend":
  237 + case "ondragenter":
  238 + case "ondragleave":
  239 + case "ondragover":
  240 + case "ondrop":
  241 + case "onfinish":
  242 + case "onfocus":
  243 + case "onhelp":
  244 + case "onmousedown":
  245 + case "onmouseup":
  246 + case "onmouseover":
  247 + case "onmousemove":
  248 + case "onmouseout":
  249 + case "onkeypress":
  250 + case "onkeydown":
  251 + case "onkeyup":
  252 + case "onload":
  253 + case "onlosecapture":
  254 + case "onpropertychange":
  255 + case "onreadystatechange":
  256 + case "onrowsdelete":
  257 + case "onrowenter":
  258 + case "onrowexit":
  259 + case "onrowsinserted":
  260 + case "onstart":
  261 + case "onscroll":
  262 + case "onbeforeeditfocus":
  263 + case "onactivate":
  264 + case "onbeforedeactivate":
  265 + case "ondeactivate":
  266 + case "type":
  267 + case "codebase":
  268 + ret.objAttrs[args[i]] = args[i+1];
  269 + break;
  270 + case "id":
  271 + case "width":
  272 + case "height":
  273 + case "align":
  274 + case "vspace":
  275 + case "hspace":
  276 + case "class":
  277 + case "title":
  278 + case "accesskey":
  279 + case "name":
  280 + case "tabindex":
  281 + ret.embedAttrs[args[i]] = ret.objAttrs[args[i]] = args[i+1];
  282 + break;
  283 + default:
  284 + ret.embedAttrs[args[i]] = ret.params[args[i]] = args[i+1];
  285 + }
  286 + }
  287 + ret.objAttrs["classid"] = classid;
  288 + if (mimeType) ret.embedAttrs["type"] = mimeType;
  289 + return ret;
  290 +}
  291 +
  292 +
121 bin/Fuschia.html
... ... @@ -0,0 +1,121 @@
  1 +<!-- saved from url=(0014)about:internet -->
  2 +<html lang="en">
  3 +
  4 +<!--
  5 +Smart developers always View Source.
  6 +
  7 +This application was built using Adobe Flex, an open source framework
  8 +for building rich Internet applications that get delivered via the
  9 +Flash Player or to desktops via Adobe AIR.
  10 +
  11 +Learn more about Flex at http://flex.org
  12 +// -->
  13 +
  14 +<head>
  15 +<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  16 +
  17 +<!-- BEGIN Browser History required section -->
  18 +<link rel="stylesheet" type="text/css" href="history/history.css" />
  19 +<!-- END Browser History required section -->
  20 +
  21 +<title></title>
  22 +<script src="AC_OETags.js" language="javascript"></script>
  23 +
  24 +<!-- BEGIN Browser History required section -->
  25 +<script src="history/history.js" language="javascript"></script>
  26 +<!-- END Browser History required section -->
  27 +
  28 +<style>
  29 +body { margin: 0px; overflow:hidden }
  30 +</style>
  31 +<script language="JavaScript" type="text/javascript">
  32 +<!--
  33 +// -----------------------------------------------------------------------------
  34 +// Globals
  35 +// Major version of Flash required
  36 +var requiredMajorVersion = 9;
  37 +// Minor version of Flash required
  38 +var requiredMinorVersion = 0;
  39 +// Minor version of Flash required
  40 +var requiredRevision = 124;
  41 +// -----------------------------------------------------------------------------
  42 +// -->
  43 +</script>
  44 +</head>
  45 +
  46 +<body scroll="no">
  47 +<script language="JavaScript" type="text/javascript">
  48 +<!--
  49 +// Version check for the Flash Player that has the ability to start Player Product Install (6.0r65)
  50 +var hasProductInstall = DetectFlashVer(6, 0, 65);
  51 +
  52 +// Version check based upon the values defined in globals
  53 +var hasRequestedVersion = DetectFlashVer(requiredMajorVersion, requiredMinorVersion, requiredRevision);
  54 +
  55 +if ( hasProductInstall && !hasRequestedVersion ) {
  56 + // DO NOT MODIFY THE FOLLOWING FOUR LINES
  57 + // Location visited after installation is complete if installation is required
  58 + var MMPlayerType = (isIE == true) ? "ActiveX" : "PlugIn";
  59 + var MMredirectURL = window.location;
  60 + document.title = document.title.slice(0, 47) + " - Flash Player Installation";
  61 + var MMdoctitle = document.title;
  62 +
  63 + AC_FL_RunContent(
  64 + "src", "playerProductInstall",
  65 + "FlashVars", "MMredirectURL="+MMredirectURL+'&MMplayerType='+MMPlayerType+'&MMdoctitle='+MMdoctitle+"",
  66 + "width", "1000",
  67 + "height", "700",
  68 + "align", "middle",
  69 + "id", "Fuschia",
  70 + "quality", "high",
  71 + "bgcolor", "#ffffff",
  72 + "name", "Fuschia",
  73 + "allowScriptAccess","sameDomain",
  74 + "type", "application/x-shockwave-flash",
  75 + "pluginspage", "http://www.adobe.com/go/getflashplayer"
  76 + );
  77 +} else if (hasRequestedVersion) {
  78 + // if we've detected an acceptable version
  79 + // embed the Flash Content SWF when all tests are passed
  80 + AC_FL_RunContent(
  81 + "src", "Fuschia",
  82 + "width", "1000",
  83 + "height", "700",
  84 + "align", "middle",
  85 + "id", "Fuschia",
  86 + "quality", "high",
  87 + "bgcolor", "#ffffff",
  88 + "name", "Fuschia",
  89 + "allowScriptAccess","sameDomain",
  90 + "type", "application/x-shockwave-flash",
  91 + "pluginspage", "http://www.adobe.com/go/getflashplayer"
  92 + );
  93 + } else { // flash is too old or we can't detect the plugin
  94 + var alternateContent = 'Alternate HTML content should be placed here. '
  95 + + 'This content requires the Adobe Flash Player. '
  96 + + '<a href=http://www.adobe.com/go/getflash/>Get Flash</a>';
  97 + document.write(alternateContent); // insert non-flash content
  98 + }
  99 +// -->
  100 +</script>
  101 +<noscript>
  102 + <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
  103 + id="Fuschia" width="1000" height="700"
  104 + codebase="http://fpdownload.macromedia.com/get/flashplayer/current/swflash.cab">
  105 + <param name="movie" value="Fuschia.swf" />
  106 + <param name="quality" value="high" />
  107 + <param name="bgcolor" value="#ffffff" />
  108 + <param name="allowScriptAccess" value="sameDomain" />
  109 + <embed src="Fuschia.swf" quality="high" bgcolor="#ffffff"
  110 + width="1000" height="700" name="Fuschia" align="middle"
  111 + play="true"
  112 + loop="false"
  113 + quality="high"
  114 + allowScriptAccess="sameDomain"
  115 + type="application/x-shockwave-flash"
  116 + pluginspage="http://www.adobe.com/go/getflashplayer">
  117 + </embed>
  118 + </object>
  119 +</noscript>
  120 +</body>
  121 +</html>
BIN  bin/Fuschia.swf
Binary file not shown
11 bin/fuschia_queries.json
... ... @@ -0,0 +1,11 @@
  1 +{
  2 + "_id":"_design/fuschia",
  3 + "views":{
  4 + "to_doc":{
  5 + "map":"function (doc) {\n var isDocId = function (str) {\n var res = /[0-9a-f-]+/(str);\n return res && str.length >= 32 && str === res[0];\n };\n \n for(var n in doc) {\n var att = doc[n];\n if (n !== \"_id\" && isDocId(att)) {\n emit(att, null);\n }\n }\n}\n\n"
  6 + },
  7 + "from_doc":{
  8 + "map":"function (doc) {\n var isDocId = function (str) {\n var res = /[0-9a-f-]+/(str);\n return res && str.length >= 32 && str === res[0];\n };\n \n for(var n in doc) {\n var att = doc[n];\n if (n !== \"_id\" && isDocId(att)) {\n emit(doc._id, att);\n }\n }\n}\n"
  9 + }
  10 + }
  11 +}
6 bin/history/history.css
... ... @@ -0,0 +1,6 @@
  1 +/* This CSS stylesheet defines styles used by required elements in a flex application page that supports browser history */
  2 +
  3 +#ie_historyFrame { width: 0px; height: 0px; display:none }
  4 +#firefox_anchorDiv { width: 0px; height: 0px; display:none }
  5 +#safari_formDiv { width: 0px; height: 0px; display:none }
  6 +#safari_rememberDiv { width: 0px; height: 0px; display:none }
662 bin/history/history.js
... ... @@ -0,0 +1,662 @@
  1 +BrowserHistoryUtils = {
  2 + addEvent: function(elm, evType, fn, useCapture) {
  3 + useCapture = useCapture || false;
  4 + if (elm.addEventListener) {
  5 + elm.addEventListener(evType, fn, useCapture);
  6 + return true;
  7 + }
  8 + else if (elm.attachEvent) {
  9 + var r = elm.attachEvent('on' + evType, fn);
  10 + return r;
  11 + }
  12 + else {
  13 + elm['on' + evType] = fn;
  14 + }
  15 + }
  16 +}
  17 +
  18 +BrowserHistory = (function() {
  19 + // type of browser
  20 + var browser = {
  21 + ie: false,
  22 + firefox: false,
  23 + safari: false,
  24 + opera: false,
  25 + version: -1
  26 + };
  27 +
  28 + // if setDefaultURL has been called, our first clue
  29 + // that the SWF is ready and listening
  30 + //var swfReady = false;
  31 +
  32 + // the URL we'll send to the SWF once it is ready
  33 + //var pendingURL = '';
  34 +
  35 + // Default app state URL to use when no fragment ID present
  36 + var defaultHash = '';
  37 +
  38 + // Last-known app state URL
  39 + var currentHref = document.location.href;
  40 +
  41 + // Initial URL (used only by IE)
  42 + var initialHref = document.location.href;
  43 +
  44 + // Initial URL (used only by IE)
  45 + var initialHash = document.location.hash;
  46 +
  47 + // History frame source URL prefix (used only by IE)
  48 + var historyFrameSourcePrefix = 'history/historyFrame.html?';
  49 +
  50 + // History maintenance (used only by Safari)
  51 + var currentHistoryLength = -1;
  52 +
  53 + var historyHash = [];
  54 +
  55 + var initialState = createState(initialHref, initialHref + '#' + initialHash, initialHash);
  56 +
  57 + var backStack = [];
  58 + var forwardStack = [];
  59 +
  60 + var currentObjectId = null;
  61 +
  62 + //UserAgent detection
  63 + var useragent = navigator.userAgent.toLowerCase();
  64 +
  65 + if (useragent.indexOf("opera") != -1) {
  66 + browser.opera = true;
  67 + } else if (useragent.indexOf("msie") != -1) {
  68 + browser.ie = true;
  69 + browser.version = parseFloat(useragent.substring(useragent.indexOf('msie') + 4));
  70 + } else if (useragent.indexOf("safari") != -1) {
  71 + browser.safari = true;
  72 + browser.version = parseFloat(useragent.substring(useragent.indexOf('safari') + 7));
  73 + } else if (useragent.indexOf("gecko") != -1) {
  74 + browser.firefox = true;
  75 + }
  76 +
  77 + if (browser.ie == true && browser.version == 7) {
  78 + window["_ie_firstload"] = false;
  79 + }
  80 +
  81 + // Accessor functions for obtaining specific elements of the page.
  82 + function getHistoryFrame()
  83 + {
  84 + return document.getElementById('ie_historyFrame');
  85 + }
  86 +
  87 + function getAnchorElement()
  88 + {
  89 + return document.getElementById('firefox_anchorDiv');
  90 + }
  91 +
  92 + function getFormElement()
  93 + {
  94 + return document.getElementById('safari_formDiv');
  95 + }
  96 +
  97 + function getRememberElement()
  98 + {
  99 + return document.getElementById("safari_remember_field");
  100 + }
  101 +
  102 + // Get the Flash player object for performing ExternalInterface callbacks.
  103 + // Updated for changes to SWFObject2.
  104 + function getPlayer(id) {
  105 + if (id && document.getElementById(id)) {
  106 + var r = document.getElementById(id);
  107 + if (typeof r.SetVariable != "undefined") {
  108 + return r;
  109 + }
  110 + else {
  111 + var o = r.getElementsByTagName("object");
  112 + var e = r.getElementsByTagName("embed");
  113 + if (o.length > 0 && typeof o[0].SetVariable != "undefined") {
  114 + return o[0];
  115 + }
  116 + else if (e.length > 0 && typeof e[0].SetVariable != "undefined") {
  117 + return e[0];
  118 + }
  119 + }
  120 + }
  121 + else {
  122 + var o = document.getElementsByTagName("object");
  123 + var e = document.getElementsByTagName("embed");
  124 + if (e.length > 0 && typeof e[0].SetVariable != "undefined") {
  125 + return e[0];
  126 + }
  127 + else if (o.length > 0 && typeof o[0].SetVariable != "undefined") {
  128 + return o[0];
  129 + }
  130 + else if (o.length > 1 && typeof o[1].SetVariable != "undefined") {
  131 + return o[1];
  132 + }
  133 + }
  134 + return undefined;
  135 + }
  136 +
  137 + function getPlayers() {
  138 + var players = [];
  139 + if (players.length == 0) {
  140 + var tmp = document.getElementsByTagName('object');
  141 + players = tmp;
  142 + }
  143 +
  144 + if (players.length == 0 || players[0].object == null) {
  145 + var tmp = document.getElementsByTagName('embed');
  146 + players = tmp;
  147 + }
  148 + return players;
  149 + }
  150 +
  151 + function getIframeHash() {
  152 + var doc = getHistoryFrame().contentWindow.document;
  153 + var hash = String(doc.location.search);
  154 + if (hash.length == 1 && hash.charAt(0) == "?") {
  155 + hash = "";
  156 + }
  157 + else if (hash.length >= 2 && hash.charAt(0) == "?") {
  158 + hash = hash.substring(1);
  159 + }
  160 + return hash;
  161 + }
  162 +
  163 + /* Get the current location hash excluding the '#' symbol. */
  164 + function getHash() {
  165 + // It would be nice if we could use document.location.hash here,
  166 + // but it's faulty sometimes.
  167 + var idx = document.location.href.indexOf('#');
  168 + return (idx >= 0) ? document.location.href.substr(idx+1) : '';
  169 + }
  170 +
  171 + /* Get the current location hash excluding the '#' symbol. */
  172 + function setHash(hash) {
  173 + // It would be nice if we could use document.location.hash here,
  174 + // but it's faulty sometimes.
  175 + if (hash == '') hash = '#'
  176 + document.location.hash = hash;
  177 + }
  178 +
  179 + function createState(baseUrl, newUrl, flexAppUrl) {
  180 + return { 'baseUrl': baseUrl, 'newUrl': newUrl, 'flexAppUrl': flexAppUrl, 'title': null };
  181 + }
  182 +
  183 + /* Add a history entry to the browser.
  184 + * baseUrl: the portion of the location prior to the '#'
  185 + * newUrl: the entire new URL, including '#' and following fragment
  186 + * flexAppUrl: the portion of the location following the '#' only
  187 + */
  188 + function addHistoryEntry(baseUrl, newUrl, flexAppUrl) {
  189 +
  190 + //delete all the history entries
  191 + forwardStack = [];
  192 +
  193 + if (browser.ie) {
  194 + //Check to see if we are being asked to do a navigate for the first
  195 + //history entry, and if so ignore, because it's coming from the creation
  196 + //of the history iframe
  197 + if (flexAppUrl == defaultHash && document.location.href == initialHref && window['_ie_firstload']) {
  198 + currentHref = initialHref;
  199 + return;
  200 + }
  201 + if ((!flexAppUrl || flexAppUrl == defaultHash) && window['_ie_firstload']) {
  202 + newUrl = baseUrl + '#' + defaultHash;
  203 + flexAppUrl = defaultHash;
  204 + } else {
  205 + // for IE, tell the history frame to go somewhere without a '#'
  206 + // in order to get this entry into the browser history.
  207 + getHistoryFrame().src = historyFrameSourcePrefix + flexAppUrl;
  208 + }
  209 + setHash(flexAppUrl);
  210 + } else {
  211 +
  212 + //ADR
  213 + if (backStack.length == 0 && initialState.flexAppUrl == flexAppUrl) {
  214 + initialState = createState(baseUrl, newUrl, flexAppUrl);
  215 + } else if(backStack.length > 0 && backStack[backStack.length - 1].flexAppUrl == flexAppUrl) {
  216 + backStack[backStack.length - 1] = createState(baseUrl, newUrl, flexAppUrl);
  217 + }
  218 +
  219 + if (browser.safari) {
  220 + // for Safari, submit a form whose action points to the desired URL
  221 + if (browser.version <= 419.3) {
  222 + var file = window.location.pathname.toString();
  223 + file = file.substring(file.lastIndexOf("/")+1);
  224 + getFormElement().innerHTML = '<form name="historyForm" action="'+file+'#' + flexAppUrl + '" method="GET"></form>';
  225 + //get the current elements and add them to the form
  226 + var qs = window.location.search.substring(1);
  227 + var qs_arr = qs.split("&");
  228 + for (var i = 0; i < qs_arr.length; i++) {
  229 + var tmp = qs_arr[i].split("=");
  230 + var elem = document.createElement("input");
  231 + elem.type = "hidden";
  232 + elem.name = tmp[0];
  233 + elem.value = tmp[1];
  234 + document.forms.historyForm.appendChild(elem);
  235 + }
  236 + document.forms.historyForm.submit();
  237 + } else {
  238 + top.location.hash = flexAppUrl;
  239 + }
  240 + // We also have to maintain the history by hand for Safari
  241 + historyHash[history.length] = flexAppUrl;
  242 + _storeStates();
  243 + } else {
  244 + // Otherwise, write an anchor into the page and tell the browser to go there
  245 + addAnchor(flexAppUrl);
  246 + setHash(flexAppUrl);
  247 + }
  248 + }
  249 + backStack.push(createState(baseUrl, newUrl, flexAppUrl));
  250 + }
  251 +
  252 + function _storeStates() {
  253 + if (browser.safari) {
  254 + getRememberElement().value = historyHash.join(",");
  255 + }
  256 + }
  257 +
  258 + function handleBackButton() {
  259 + //The "current" page is always at the top of the history stack.
  260 + var current = backStack.pop();
  261 + if (!current) { return; }
  262 + var last = backStack[backStack.length - 1];
  263 + if (!last && backStack.length == 0){
  264 + last = initialState;
  265 + }
  266 + forwardStack.push(current);
  267 + }
  268 +
  269 + function handleForwardButton() {
  270 + //summary: private method. Do not call this directly.
  271 +
  272 + var last = forwardStack.pop();
  273 + if (!last) { return; }
  274 + backStack.push(last);
  275 + }
  276 +
  277 + function handleArbitraryUrl() {
  278 + //delete all the history entries
  279 + forwardStack = [];
  280 + }
  281 +
  282 + /* Called periodically to poll to see if we need to detect navigation that has occurred */
  283 + function checkForUrlChange() {
  284 +
  285 + if (browser.ie) {
  286 + if (currentHref != document.location.href && currentHref + '#' != document.location.href) {
  287 + //This occurs when the user has navigated to a specific URL
  288 + //within the app, and didn't use browser back/forward
  289 + //IE seems to have a bug where it stops updating the URL it
  290 + //shows the end-user at this point, but programatically it
  291 + //appears to be correct. Do a full app reload to get around
  292 + //this issue.
  293 + if (browser.version < 7) {
  294 + currentHref = document.location.href;
  295 + document.location.reload();
  296 + } else {
  297 + if (getHash() != getIframeHash()) {
  298 + // this.iframe.src = this.blankURL + hash;
  299 + var sourceToSet = historyFrameSourcePrefix + getHash();
  300 + getHistoryFrame().src = sourceToSet;
  301 + }
  302 + }
  303 + }
  304 + }
  305 +
  306 + if (browser.safari) {
  307 + // For Safari, we have to check to see if history.length changed.
  308 + if (currentHistoryLength >= 0 && history.length != currentHistoryLength) {
  309 + //alert("did change: " + history.length + ", " + historyHash.length + "|" + historyHash[history.length] + "|>" + historyHash.join("|"));
  310 + // If it did change, then we have to look the old state up
  311 + // in our hand-maintained array since document.location.hash
  312 + // won't have changed, then call back into BrowserManager.
  313 + currentHistoryLength = history.length;
  314 + var flexAppUrl = historyHash[currentHistoryLength];
  315 + if (flexAppUrl == '') {
  316 + //flexAppUrl = defaultHash;
  317 + }
  318 + //ADR: to fix multiple
  319 + if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) {
  320 + var pl = getPlayers();
  321 + for (var i = 0; i < pl.length; i++) {
  322 + pl[i].browserURLChange(flexAppUrl);
  323 + }
  324 + } else {
  325 + getPlayer().browserURLChange(flexAppUrl);
  326 + }
  327 + _storeStates();
  328 + }
  329 + }
  330 + if (browser.firefox) {
  331 + if (currentHref != document.location.href) {
  332 + var bsl = backStack.length;
  333 +
  334 + var urlActions = {
  335 + back: false,
  336 + forward: false,
  337 + set: false
  338 + }
  339 +
  340 + if ((window.location.hash == initialHash || window.location.href == initialHref) && (bsl == 1)) {
  341 + urlActions.back = true;
  342 + // FIXME: could this ever be a forward button?
  343 + // we can't clear it because we still need to check for forwards. Ugg.
  344 + // clearInterval(this.locationTimer);
  345 + handleBackButton();
  346 + }
  347 +
  348 + // first check to see if we could have gone forward. We always halt on
  349 + // a no-hash item.
  350 + if (forwardStack.length > 0) {
  351 + if (forwardStack[forwardStack.length-1].flexAppUrl == getHash()) {
  352 + urlActions.forward = true;
  353 + handleForwardButton();
  354 + }
  355 + }
  356 +
  357 + // ok, that didn't work, try someplace back in the history stack
  358 + if ((bsl >= 2) && (backStack[bsl - 2])) {
  359 + if (backStack[bsl - 2].flexAppUrl == getHash()) {
  360 + urlActions.back = true;
  361 + handleBackButton();
  362 + }
  363 + }
  364 +
  365 + if (!urlActions.back && !urlActions.forward) {
  366 + var foundInStacks = {
  367 + back: -1,
  368 + forward: -1
  369 + }
  370 +
  371 + for (var i = 0; i < backStack.length; i++) {
  372 + if (backStack[i].flexAppUrl == getHash() && i != (bsl - 2)) {
  373 + arbitraryUrl = true;
  374 + foundInStacks.back = i;
  375 + }
  376 + }
  377 + for (var i = 0; i < forwardStack.length; i++) {
  378 + if (forwardStack[i].flexAppUrl == getHash() && i != (bsl - 2)) {
  379 + arbitraryUrl = true;
  380 + foundInStacks.forward = i;
  381 + }
  382 + }
  383 + handleArbitraryUrl();
  384 + }
  385 +
  386 + // Firefox changed; do a callback into BrowserManager to tell it.
  387 + currentHref = document.location.href;
  388 + var flexAppUrl = getHash();
  389 + if (flexAppUrl == '') {
  390 + //flexAppUrl = defaultHash;
  391 + }
  392 + //ADR: to fix multiple
  393 + if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) {
  394 + var pl = getPlayers();
  395 + for (var i = 0; i < pl.length; i++) {
  396 + pl[i].browserURLChange(flexAppUrl);
  397 + }
  398 + } else {
  399 + getPlayer().browserURLChange(flexAppUrl);
  400 + }
  401 + }
  402 + }
  403 + //setTimeout(checkForUrlChange, 50);
  404 + }
  405 +
  406 + /* Write an anchor into the page to legitimize it as a URL for Firefox et al. */
  407 + function addAnchor(flexAppUrl)
  408 + {
  409 + if (document.getElementsByName(flexAppUrl).length == 0) {
  410 + getAnchorElement().innerHTML += "<a name='" + flexAppUrl + "'>" + flexAppUrl + "</a>";
  411 + }
  412 + }
  413 +
  414 + var _initialize = function () {
  415 + if (browser.ie)
  416 + {
  417 + var scripts = document.getElementsByTagName('script');
  418 + for (var i = 0, s; s = scripts[i]; i++) {
  419 + if (s.src.indexOf("history.js") > -1) {
  420 + var iframe_location = (new String(s.src)).replace("history.js", "historyFrame.html");
  421 + }
  422 + }
  423 + historyFrameSourcePrefix = iframe_location + "?";
  424 + var src = historyFrameSourcePrefix;
  425 +
  426 + var iframe = document.createElement("iframe");
  427 + iframe.id = 'ie_historyFrame';
  428 + iframe.name = 'ie_historyFrame';
  429 + //iframe.src = historyFrameSourcePrefix;
  430 + try {
  431 + document.body.appendChild(iframe);
  432 + } catch(e) {
  433 + setTimeout(function() {
  434 + document.body.appendChild(iframe);
  435 + }, 0);
  436 + }
  437 + }
  438 +
  439 + if (browser.safari)
  440 + {
  441 + var rememberDiv = document.createElement("div");
  442 + rememberDiv.id = 'safari_rememberDiv';
  443 + document.body.appendChild(rememberDiv);
  444 + rememberDiv.innerHTML = '<input type="text" id="safari_remember_field" style="width: 500px;">';
  445 +
  446 + var formDiv = document.createElement("div");
  447 + formDiv.id = 'safari_formDiv';
  448 + document.body.appendChild(formDiv);
  449 +
  450 + var reloader_content = document.createElement('div');
  451 + reloader_content.id = 'safarireloader';
  452 + var scripts = document.getElementsByTagName('script');
  453 + for (var i = 0, s; s = scripts[i]; i++) {
  454 + if (s.src.indexOf("history.js") > -1) {
  455 + html = (new String(s.src)).replace(".js", ".html");
  456 + }
  457 + }
  458 + reloader_content.innerHTML = '<iframe id="safarireloader-iframe" src="about:blank" frameborder="no" scrolling="no"></iframe>';
  459 + document.body.appendChild(reloader_content);
  460 + reloader_content.style.position = 'absolute';
  461 + reloader_content.style.left = reloader_content.style.top = '-9999px';
  462 + iframe = reloader_content.getElementsByTagName('iframe')[0];
  463 +
  464 + if (document.getElementById("safari_remember_field").value != "" ) {
  465 + historyHash = document.getElementById("safari_remember_field").value.split(",");
  466 + }
  467 +
  468 + }
  469 +
  470 + if (browser.firefox)
  471 + {
  472 + var anchorDiv = document.createElement("div");
  473 + anchorDiv.id = 'firefox_anchorDiv';
  474 + document.body.appendChild(anchorDiv);
  475 + }
  476 +
  477 + //setTimeout(checkForUrlChange, 50);
  478 + }
  479 +
  480 + return {
  481 + historyHash: historyHash,
  482 + backStack: function() { return backStack; },
  483 + forwardStack: function() { return forwardStack },
  484 + getPlayer: getPlayer,
  485 + initialize: function(src) {
  486 + _initialize(src);
  487 + },
  488 + setURL: function(url) {
  489 + document.location.href = url;
  490 + },
  491 + getURL: function() {
  492 + return document.location.href;
  493 + },
  494 + getTitle: function() {
  495 + return document.title;
  496 + },
  497 + setTitle: function(title) {
  498 + try {
  499 + backStack[backStack.length - 1].title = title;
  500 + } catch(e) { }
  501 + //if on safari, set the title to be the empty string.
  502 + if (browser.safari) {
  503 + if (title == "") {
  504 + try {
  505 + var tmp = window.location.href.toString();
  506 + title = tmp.substring((tmp.lastIndexOf("/")+1), tmp.lastIndexOf("#"));
  507 + } catch(e) {
  508 + title = "";
  509 + }
  510 + }
  511 + }
  512 + document.title = title;
  513 + },
  514 + setDefaultURL: function(def)
  515 + {
  516 + defaultHash = def;
  517 + def = getHash();
  518 + //trailing ? is important else an extra frame gets added to the history
  519 + //when navigating back to the first page. Alternatively could check
  520 + //in history frame navigation to compare # and ?.
  521 + if (browser.ie)
  522 + {
  523 + window['_ie_firstload'] = true;
  524 + var sourceToSet = historyFrameSourcePrefix + def;
  525 + var func = function() {
  526 + getHistoryFrame().src = sourceToSet;
  527 + window.location.replace("#" + def);
  528 + setInterval(checkForUrlChange, 50);
  529 + }
  530 + try {
  531 + func();
  532 + } catch(e) {
  533 + window.setTimeout(function() { func(); }, 0);
  534 + }
  535 + }
  536 +
  537 + if (browser.safari)
  538 + {
  539 + currentHistoryLength = history.length;
  540 + if (historyHash.length == 0) {
  541 + historyHash[currentHistoryLength] = def;
  542 + var newloc = "#" + def;
  543 + window.location.replace(newloc);
  544 + } else {
  545 + //alert(historyHash[historyHash.length-1]);
  546 + }
  547 + //setHash(def);
  548 + setInterval(checkForUrlChange, 50);
  549 + }
  550 +
  551 +
  552 + if (browser.firefox || browser.opera)
  553 + {
  554 + var reg = new RegExp("#" + def + "$");
  555 + if (window.location.toString().match(reg)) {
  556 + } else {
  557 + var newloc ="#" + def;
  558 + window.location.replace(newloc);
  559 + }
  560 + setInterval(checkForUrlChange, 50);
  561 + //setHash(def);
  562 + }
  563 +
  564 + },
  565 +
  566 + /* Set the current browser URL; called from inside BrowserManager to propagate
  567 + * the application state out to the container.
  568 + */
  569 + setBrowserURL: function(flexAppUrl, objectId) {
  570 + if (browser.ie && typeof objectId != "undefined") {
  571 + currentObjectId = objectId;
  572 + }
  573 + //fromIframe = fromIframe || false;
  574 + //fromFlex = fromFlex || false;
  575 + //alert("setBrowserURL: " + flexAppUrl);
  576 + //flexAppUrl = (flexAppUrl == "") ? defaultHash : flexAppUrl ;
  577 +
  578 + var pos = document.location.href.indexOf('#');
  579 + var baseUrl = pos != -1 ? document.location.href.substr(0, pos) : document.location.href;
  580 + var newUrl = baseUrl + '#' + flexAppUrl;
  581 +
  582 + if (document.location.href != newUrl && document.location.href + '#' != newUrl) {
  583 + currentHref = newUrl;
  584 + addHistoryEntry(baseUrl, newUrl, flexAppUrl);
  585 + currentHistoryLength = history.length;
  586 + }
  587 +
  588 + return false;
  589 + },
  590 +
  591 + browserURLChange: function(flexAppUrl) {
  592 + var objectId = null;
  593 + if (browser.ie && currentObjectId != null) {
  594 + objectId = currentObjectId;
  595 + }
  596 + pendingURL = '';
  597 +
  598 + if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) {
  599 + var pl = getPlayers();
  600 + for (var i = 0; i < pl.length; i++) {
  601 + try {
  602 + pl[i].browserURLChange(flexAppUrl);
  603 + } catch(e) { }
  604 + }
  605 + } else {
  606 + try {
  607 + getPlayer(objectId).browserURLChange(flexAppUrl);
  608 + } catch(e) { }
  609 + }
  610 +
  611 + currentObjectId = null;
  612 + }
  613 +
  614 + }
  615 +
  616 +})();
  617 +
  618 +// Initialization
  619 +
  620 +// Automated unit testing and other diagnostics
  621 +
  622 +function setURL(url)
  623 +{
  624 + document.location.href = url;
  625 +}
  626 +
  627 +function backButton()
  628 +{
  629 + history.back();
  630 +}
  631 +
  632 +function forwardButton()
  633 +{
  634 + history.forward();
  635 +}
  636 +
  637 +function goForwardOrBackInHistory(step)
  638 +{
  639 + history.go(step);
  640 +}
  641 +
  642 +//BrowserHistoryUtils.addEvent(window, "load", function() { BrowserHistory.initialize(); });
  643 +(function(i) {
  644 + var u =navigator.userAgent;var e=/*@cc_on!@*/false;
  645 + var st = setTimeout;
  646 + if(/webkit/i.test(u)){
  647 + st(function(){
  648 + var dr=document.readyState;
  649 + if(dr=="loaded"||dr=="complete"){i()}
  650 + else{st(arguments.callee,10);}},10);
  651 + } else if((/mozilla/i.test(u)&&!/(compati)/.test(u)) || (/opera/i.test(u))){
  652 + document.addEventListener("DOMContentLoaded",i,false);
  653 + } else if(e){
  654 + (function(){
  655 + var t=document.createElement('doc:rdy');
  656 + try{t.doScroll('left');
  657 + i();t=null;
  658 + }catch(e){st(arguments.callee,0);}})();
  659 + } else{
  660 + window.onload=i;
  661 + }
  662 +})( function() {BrowserHistory.initialize();} );
29 bin/history/historyFrame.html
... ... @@ -0,0 +1,29 @@
  1 +<html>
  2 + <head>
  3 + <META HTTP-EQUIV="Pragma" CONTENT="no-cache">
  4 + <META HTTP-EQUIV="Expires" CONTENT="-1">
  5 + </head>
  6 + <body>
  7 + <script>
  8 + function processUrl()
  9 + {
  10 +
  11 + var pos = url.indexOf("?");
  12 + url = pos != -1 ? url.substr(pos + 1) : "";
  13 + if (!parent._ie_firstload) {
  14 + parent.BrowserHistory.setBrowserURL(url);
  15 + try {
  16 + parent.BrowserHistory.browserURLChange(url);
  17 + } catch(e) { }
  18 + } else {
  19 + parent._ie_firstload = false;
  20 + }
  21 + }
  22 +
  23 + var url = document.location.href;
  24 + processUrl();
  25 + document.write(encodeURIComponent(url));
  26 + </script>
  27 + Hidden frame for Browser History support.
  28 + </body>
  29 +</html>
BIN  bin/playerProductInstall.swf
Binary file not shown