From 0a0e1636bcabb3455b06aefc86f81281978e6f37 Mon Sep 17 00:00:00 2001 From: John Crepezzi Date: Sun, 27 Nov 2011 14:37:38 -0500 Subject: [PATCH 1/6] Allow the /about page --- static/robots.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/static/robots.txt b/static/robots.txt index 1f53798..1504053 100644 --- a/static/robots.txt +++ b/static/robots.txt @@ -1,2 +1,3 @@ User-agent: * +Allow: /about Disallow: / From 85fac80a6d3f84d0016aed411c23d11304971b1a Mon Sep 17 00:00:00 2001 From: John Crepezzi Date: Sun, 27 Nov 2011 14:47:36 -0500 Subject: [PATCH 2/6] Put staticCache back in --- TODO.md | 1 - server.js | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/TODO.md b/TODO.md index 97b7331..2d40912 100644 --- a/TODO.md +++ b/TODO.md @@ -8,7 +8,6 @@ * test new interface in browsers * compress assets * fix issues with deploy -* get staticCache back in # shared version only diff --git a/server.js b/server.js index caab64e..818712d 100644 --- a/server.js +++ b/server.js @@ -73,6 +73,7 @@ connect.createServer( }); }), // Otherwise, static + connect.staticCache(), connect.static(__dirname + '/static', { maxAge: config.staticMaxAge }), // Then we can loop back - and everything else should be a token, // so route it back to /index.html @@ -82,7 +83,6 @@ connect.createServer( next(); }); }), - // And then let static take over connect.static(__dirname + '/static', { maxAge: config.staticMaxAge }) ).listen(config.port, config.host); From c4a51849623f8269005c31c120a6b32878020006 Mon Sep 17 00:00:00 2001 From: John Crepezzi Date: Sun, 27 Nov 2011 14:48:33 -0500 Subject: [PATCH 3/6] Clean up TODO --- TODO.md | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/TODO.md b/TODO.md index 2d40912..56e33df 100644 --- a/TODO.md +++ b/TODO.md @@ -1,4 +1,4 @@ -# TODO +# TODO for OSS * tests * fix that chrome bug where it loads the doc twice * kick expiration back by increment on each view @@ -6,14 +6,10 @@ * Proper markdown highlighting * Better about page text * test new interface in browsers -* compress assets -* fix issues with deploy - +* auto-compress assets +* add feedback for errors to UI - esp. too long +* fix the copy URL button # shared version only * some way to do announcements easily (and use for ads) - - -# with brian's design -* add feedback for errors to UI - esp. too long -* copy URL to clipboard button +* fix issues with deploy From 4233e589957d57f60fdb81bb85d1ec0a7996fe71 Mon Sep 17 00:00:00 2001 From: John Crepezzi Date: Sun, 27 Nov 2011 15:34:09 -0500 Subject: [PATCH 4/6] Added copy URL functionality --- TODO.md | 1 - static/ZeroClipboard.js | 311 ++++++++++++++++++++++++++++++++++++++ static/ZeroClipboard.swf | Bin 0 -> 1071 bytes static/application.css | 4 + static/application.js | 31 +++- static/application.min.js | 2 - static/index.html | 3 +- 7 files changed, 343 insertions(+), 9 deletions(-) create mode 100755 static/ZeroClipboard.js create mode 100755 static/ZeroClipboard.swf delete mode 100644 static/application.min.js diff --git a/TODO.md b/TODO.md index 56e33df..b02e88b 100644 --- a/TODO.md +++ b/TODO.md @@ -8,7 +8,6 @@ * test new interface in browsers * auto-compress assets * add feedback for errors to UI - esp. too long -* fix the copy URL button # shared version only * some way to do announcements easily (and use for ads) diff --git a/static/ZeroClipboard.js b/static/ZeroClipboard.js new file mode 100755 index 0000000..5adde95 --- /dev/null +++ b/static/ZeroClipboard.js @@ -0,0 +1,311 @@ +// Simple Set Clipboard System +// Author: Joseph Huckaby + +var ZeroClipboard = { + + version: "1.0.7", + clients: {}, // registered upload clients on page, indexed by id + moviePath: 'ZeroClipboard.swf', // URL to movie + nextId: 1, // ID of next movie + + $: function(thingy) { + // simple DOM lookup utility function + if (typeof(thingy) == 'string') thingy = document.getElementById(thingy); + if (!thingy.addClass) { + // extend element with a few useful methods + thingy.hide = function() { this.style.display = 'none'; }; + thingy.show = function() { this.style.display = ''; }; + thingy.addClass = function(name) { this.removeClass(name); this.className += ' ' + name; }; + thingy.removeClass = function(name) { + var classes = this.className.split(/\s+/); + var idx = -1; + for (var k = 0; k < classes.length; k++) { + if (classes[k] == name) { idx = k; k = classes.length; } + } + if (idx > -1) { + classes.splice( idx, 1 ); + this.className = classes.join(' '); + } + return this; + }; + thingy.hasClass = function(name) { + return !!this.className.match( new RegExp("\\s*" + name + "\\s*") ); + }; + } + return thingy; + }, + + setMoviePath: function(path) { + // set path to ZeroClipboard.swf + this.moviePath = path; + }, + + dispatch: function(id, eventName, args) { + // receive event from flash movie, send to client + var client = this.clients[id]; + if (client) { + client.receiveEvent(eventName, args); + } + }, + + register: function(id, client) { + // register new client to receive events + this.clients[id] = client; + }, + + getDOMObjectPosition: function(obj, stopObj) { + // get absolute coordinates for dom element + var info = { + left: 0, + top: 0, + width: obj.width ? obj.width : obj.offsetWidth, + height: obj.height ? obj.height : obj.offsetHeight + }; + + while (obj && (obj != stopObj)) { + info.left += obj.offsetLeft; + info.top += obj.offsetTop; + obj = obj.offsetParent; + } + + return info; + }, + + Client: function(elem) { + // constructor for new simple upload client + this.handlers = {}; + + // unique ID + this.id = ZeroClipboard.nextId++; + this.movieId = 'ZeroClipboardMovie_' + this.id; + + // register client with singleton to receive flash events + ZeroClipboard.register(this.id, this); + + // create movie + if (elem) this.glue(elem); + } +}; + +ZeroClipboard.Client.prototype = { + + id: 0, // unique ID for us + ready: false, // whether movie is ready to receive events or not + movie: null, // reference to movie object + clipText: '', // text to copy to clipboard + handCursorEnabled: true, // whether to show hand cursor, or default pointer cursor + cssEffects: true, // enable CSS mouse effects on dom container + handlers: null, // user event handlers + + glue: function(elem, appendElem, stylesToAdd) { + // glue to DOM element + // elem can be ID or actual DOM element object + this.domElement = ZeroClipboard.$(elem); + + // float just above object, or zIndex 99 if dom element isn't set + var zIndex = 99; + if (this.domElement.style.zIndex) { + zIndex = parseInt(this.domElement.style.zIndex, 10) + 1; + } + + if (typeof(appendElem) == 'string') { + appendElem = ZeroClipboard.$(appendElem); + } + else if (typeof(appendElem) == 'undefined') { + appendElem = document.getElementsByTagName('body')[0]; + } + + // find X/Y position of domElement + var box = ZeroClipboard.getDOMObjectPosition(this.domElement, appendElem); + + // create floating DIV above element + this.div = document.createElement('div'); + var style = this.div.style; + style.position = 'absolute'; + style.left = '' + box.left + 'px'; + style.top = '' + box.top + 'px'; + style.width = '' + box.width + 'px'; + style.height = '' + box.height + 'px'; + style.zIndex = zIndex; + + if (typeof(stylesToAdd) == 'object') { + for (addedStyle in stylesToAdd) { + style[addedStyle] = stylesToAdd[addedStyle]; + } + } + + // style.backgroundColor = '#f00'; // debug + + appendElem.appendChild(this.div); + + this.div.innerHTML = this.getHTML( box.width, box.height ); + }, + + getHTML: function(width, height) { + // return HTML for movie + var html = ''; + var flashvars = 'id=' + this.id + + '&width=' + width + + '&height=' + height; + + if (navigator.userAgent.match(/MSIE/)) { + // IE gets an OBJECT tag + var protocol = location.href.match(/^https/i) ? 'https://' : 'http://'; + html += ''; + } + else { + // all other browsers get an EMBED tag + html += ''; + } + return html; + }, + + hide: function() { + // temporarily hide floater offscreen + if (this.div) { + this.div.style.left = '-2000px'; + } + }, + + show: function() { + // show ourselves after a call to hide() + this.reposition(); + }, + + destroy: function() { + // destroy control and floater + if (this.domElement && this.div) { + this.hide(); + this.div.innerHTML = ''; + + var body = document.getElementsByTagName('body')[0]; + try { body.removeChild( this.div ); } catch(e) {;} + + this.domElement = null; + this.div = null; + } + }, + + reposition: function(elem) { + // reposition our floating div, optionally to new container + // warning: container CANNOT change size, only position + if (elem) { + this.domElement = ZeroClipboard.$(elem); + if (!this.domElement) this.hide(); + } + + if (this.domElement && this.div) { + var box = ZeroClipboard.getDOMObjectPosition(this.domElement); + var style = this.div.style; + style.left = '' + box.left + 'px'; + style.top = '' + box.top + 'px'; + } + }, + + setText: function(newText) { + // set text to be copied to clipboard + this.clipText = newText; + if (this.ready) this.movie.setText(newText); + }, + + addEventListener: function(eventName, func) { + // add user event listener for event + // event types: load, queueStart, fileStart, fileComplete, queueComplete, progress, error, cancel + eventName = eventName.toString().toLowerCase().replace(/^on/, ''); + if (!this.handlers[eventName]) this.handlers[eventName] = []; + this.handlers[eventName].push(func); + }, + + setHandCursor: function(enabled) { + // enable hand cursor (true), or default arrow cursor (false) + this.handCursorEnabled = enabled; + if (this.ready) this.movie.setHandCursor(enabled); + }, + + setCSSEffects: function(enabled) { + // enable or disable CSS effects on DOM container + this.cssEffects = !!enabled; + }, + + receiveEvent: function(eventName, args) { + // receive event from flash + eventName = eventName.toString().toLowerCase().replace(/^on/, ''); + + // special behavior for certain events + switch (eventName) { + case 'load': + // movie claims it is ready, but in IE this isn't always the case... + // bug fix: Cannot extend EMBED DOM elements in Firefox, must use traditional function + this.movie = document.getElementById(this.movieId); + if (!this.movie) { + var self = this; + setTimeout( function() { self.receiveEvent('load', null); }, 1 ); + return; + } + + // firefox on pc needs a "kick" in order to set these in certain cases + if (!this.ready && navigator.userAgent.match(/Firefox/) && navigator.userAgent.match(/Windows/)) { + var self = this; + setTimeout( function() { self.receiveEvent('load', null); }, 100 ); + this.ready = true; + return; + } + + this.ready = true; + this.movie.setText( this.clipText ); + this.movie.setHandCursor( this.handCursorEnabled ); + break; + + case 'mouseover': + if (this.domElement && this.cssEffects) { + this.domElement.addClass('hover'); + if (this.recoverActive) this.domElement.addClass('active'); + } + break; + + case 'mouseout': + if (this.domElement && this.cssEffects) { + this.recoverActive = false; + if (this.domElement.hasClass('active')) { + this.domElement.removeClass('active'); + this.recoverActive = true; + } + this.domElement.removeClass('hover'); + } + break; + + case 'mousedown': + if (this.domElement && this.cssEffects) { + this.domElement.addClass('active'); + } + break; + + case 'mouseup': + if (this.domElement && this.cssEffects) { + this.domElement.removeClass('active'); + this.recoverActive = false; + } + break; + } // switch eventName + + if (this.handlers[eventName]) { + for (var idx = 0, len = this.handlers[eventName].length; idx < len; idx++) { + var func = this.handlers[eventName][idx]; + + if (typeof(func) == 'function') { + // actual function reference + func(this, args); + } + else if ((typeof(func) == 'object') && (func.length == 2)) { + // PHP style object + method, i.e. [myObject, 'myMethod'] + func[0][ func[1] ](this, args); + } + else if (typeof(func) == 'string') { + // name of function + window[func](this, args); + } + } // foreach event handler defined + } // user defined handler for event + } + +}; diff --git a/static/ZeroClipboard.swf b/static/ZeroClipboard.swf new file mode 100755 index 0000000000000000000000000000000000000000..13bf8e396202964e0048333d878f4b949a2f5e6a GIT binary patch literal 1071 zcmV+~1kn3KS5pay1^@tfoPAa6Qrkup-d$aeB-A-xFjKf1te)pFM-&Q&_dOT zp~-XxqP4X~YJ}vGWC;KAD1C=MKwiO_PG6^Vbs@z~r#qgr-}!Xr?4IxJ9P1kT4dpSa zmlT9hja*+}e;Cbih*6`(JT|+I(1(#NIVSiTL~Dq=|Lb=d5tOYL`L;_#dyQQ%FAAmI zcth~a_gzLk@xphk!Y?fFYp&C2`ZTZ#X}INt9hY9ojZWZ1Om23g$oC2%i(XLAs&#|V z5ArS7X}yhomj%SJGT~|rnZj|zM|I&j59e1QKqGxQN5!(ijWrx1S)ZN!RwWBwC`$uYc z!)028S7F4?l?H2dd39HKImh$+mv#S~I-YjmQ;P-rUfUM~-;Xr+ldpAXK+hS!b|@Ro zUs)@fv!kf9RjpFXZ?d(Pe_q{bY*sgP{Ykaib==7Da_N!X$Z^AwK5e&BZ5R56j>T=;_5DD$nR8}GiWShym;5A&x*eM;)Us-}<67Eb+@9n>sdlhm z`(coON!$a6H-ML=9U8}t-8aV1yD!xY9v@|7-FWq*lEUMka&b=Hq$X{>72}4eNl_P+ zccPJWGtXb!r#GbVPIO$}sN%oME%Yf<`b@|2f6G5y#$}-l zAR|D=L6`ti0Wt|N4P*v{Ss-&j?gE(yvY_TMkQE@SK-Pd%f#~WwXExMLZXW@84CD#m zFMxar!IU~i}ZGSTvX;GX_!`A@yKkIbSu*e=l_b9m*BF@hOB8SS;p?XkU4 z+#Y{FagI+_hF#pQ*y^c#B7H9*TQ=n-IvJZOQ*KYMV&e{u!2((~XOiIAy*Zr0yBr$x zqA6D~T{u}ZWn+;Cn@jC`refSD34E}PZ{YGaxq%P2g&VlCEyl30qM2Z<#-M2CQxMno zG_4J8H7mc8(VenQzJ;=@j=BiTh*RubMeS$61ORcM^S6!u6l;=?s|@ py1A~K8@jovn~!u;;=k8uI$3rc`gC{*rT-s&a~N%N=5J58nk1s|4c7nw literal 0 HcmV?d00001 diff --git a/static/application.css b/static/application.css index 141e2b2..6f994d5 100644 --- a/static/application.css +++ b/static/application.css @@ -68,6 +68,10 @@ textarea { display: inline-block; } +#key .box2 .link embed { + vertical-align: bottom; /* fix for zeroClipboard style */ +} + #key .box2 .function.enabled:hover { cursor: hand; cursor: pointer; diff --git a/static/application.js b/static/application.js index 9140474..3eae3b1 100644 --- a/static/application.js +++ b/static/application.js @@ -81,11 +81,13 @@ haste.prototype.setTitle = function(ext) { // Show the light key haste.prototype.lightKey = function() { this.configureKey(['new', 'save']); + this.removeClip(); }; // Show the full key haste.prototype.fullKey = function() { this.configureKey(['new', 'duplicate', 'twitter', 'link']); + this.configureClip(); }; // Set the key up for certain things to be enabled @@ -178,14 +180,32 @@ haste.prototype.lockDocument = function() { title += ' - ' + ret.language; } _this.setTitle(title); - _this.fullKey(); window.history.pushState(null, _this.appName + '-' + ret.key, '/' + ret.key); + _this.fullKey(); _this.$textarea.val('').hide(); _this.$box.show().focus(); } }); }; +// set up a clip that will copy the current url +haste.prototype.configureClip = function() { + var clip = this.clipper = new ZeroClipboard.Client(); + this.clipper.setHandCursor(true); + this.clipper.setCSSEffects(false); + // and then set and show + this.clipper.setText(window.location.href); + $('#key .box2 .link').html(this.clipper.getHTML(32, 37)); +}; + +// hide the current clip, if it exists +haste.prototype.removeClip = function() { + if (this.clipper) { + this.clipper.destroy(); + } + $('#key .box2 .link').html(''); +}; + haste.prototype.configureButtons = function() { var _this = this; this.buttons = [ @@ -238,9 +258,8 @@ haste.prototype.configureButtons = function() { { $where: $('#key .box2 .link'), label: 'Copy URL', - action: function() { - alert('not yet implemented'); - } + letBubble: true, + action: function() { } } ]; for (var i = 0; i < this.buttons.length; i++) { @@ -276,7 +295,9 @@ haste.prototype.configureShortcuts = function() { for (var i = 0 ; i < _this.buttons.length; i++) { button = _this.buttons[i]; if (button.shortcut && button.shortcut(evt)) { - evt.preventDefault(); + if (!button.letBubble) { + evt.preventDefault(); + } button.action(); return; } diff --git a/static/application.min.js b/static/application.min.js deleted file mode 100644 index 9893a7a..0000000 --- a/static/application.min.js +++ /dev/null @@ -1,2 +0,0 @@ -///// represents a single document -var haste_document=function(){this.locked=!1};haste_document.prototype.load=function(a,b,c){var d=this;$.ajax("/documents/"+a,{type:"get",dataType:"json",success:function(e){d.locked=!0,d.key=a,d.data=e.data;try{var f=c?hljs.highlight(c,e.data):hljs.highlightAuto(e.data)}catch(g){f={value:e.data,language:null}}b({value:f.value,key:a,language:f.language||c})},error:function(a){b(!1)}})},haste_document.prototype.save=function(a,b){if(this.locked)return!1;this.data=a;var c=this;$.ajax("/documents",{type:"post",data:a,dataType:"json",success:function(d){c.locked=!0,c.key=d.key;var e=hljs.highlightAuto(a);b({value:e.value,key:d.key,language:e.language})}})};var haste=function(a,b){this.appName=a,this.baseUrl=window.location.href,this.$textarea=$("textarea"),this.$box=$("#box"),this.$code=$("#box code"),this.options=b,this.configureShortcuts(),this.configureButtons(),b.twitter||$("#key .box2 .twitter").hide()};haste.prototype.setTitle=function(a){var b=a?this.appName+" - "+a:this.appName;document.title=b},haste.prototype.lightKey=function(){this.configureKey(["new","save"])},haste.prototype.fullKey=function(){this.configureKey(["new","duplicate","twitter","link"])},haste.prototype.configureKey=function(a){var b,c=0;$("#key .box2 .function").each(function(){b=$(this);for(c=0;c - + + From d3ba2e4b5b3fe138400b2242443677324e157608 Mon Sep 17 00:00:00 2001 From: John Crepezzi Date: Sun, 27 Nov 2011 15:35:46 -0500 Subject: [PATCH 5/6] Remove TODO --- TODO.md | 1 - 1 file changed, 1 deletion(-) diff --git a/TODO.md b/TODO.md index b02e88b..58fc476 100644 --- a/TODO.md +++ b/TODO.md @@ -5,7 +5,6 @@ * Add file extensions ourselves to push state * Proper markdown highlighting * Better about page text -* test new interface in browsers * auto-compress assets * add feedback for errors to UI - esp. too long From 0875ba625261bab4bdcdf1418362bf0a5f3eb46c Mon Sep 17 00:00:00 2001 From: John Crepezzi Date: Sun, 27 Nov 2011 15:49:17 -0500 Subject: [PATCH 6/6] Auto-compress javascript assets --- TODO.md | 1 - config.js | 2 ++ package.json | 3 ++- server.js | 20 ++++++++++++++++++++ static/ZeroClipboard.min.js | 1 + static/application.min.js | 1 + static/index.html | 4 ++-- 7 files changed, 28 insertions(+), 4 deletions(-) create mode 100644 static/ZeroClipboard.min.js create mode 100644 static/application.min.js diff --git a/TODO.md b/TODO.md index 58fc476..0b18e20 100644 --- a/TODO.md +++ b/TODO.md @@ -5,7 +5,6 @@ * Add file extensions ourselves to push state * Proper markdown highlighting * Better about page text -* auto-compress assets * add feedback for errors to UI - esp. too long # shared version only diff --git a/config.js b/config.js index f6e97b3..0208e7f 100644 --- a/config.js +++ b/config.js @@ -9,6 +9,8 @@ "staticMaxAge": 86400, + "recompressStaticAssets": true, + "logging": [ { "level": "verbose", diff --git a/package.json b/package.json index a9b1cba..9c69eaa 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,8 @@ "dependencies": { "winston": "*", "hashlib": "*", - "connect": "*" + "connect": "*", + "uglify-js": "*" }, "devDependencies": { diff --git a/server.js b/server.js index 818712d..5f19095 100644 --- a/server.js +++ b/server.js @@ -37,6 +37,26 @@ if (!config.storage.type) { var Store = require('./lib/' + config.storage.type + '_document_store'); var preferredStore = new Store(config.storage); +// Compress the static javascript assets +if (config.recompressStaticAssets) { + var jsp = require("uglify-js").parser; + var pro = require("uglify-js").uglify; + var list = fs.readdirSync('./static'); + for (var i = 0; i < list.length; i++) { + var item = list[i]; + var orig_code, ast; + if ((item.indexOf('.js') === item.length - 3) && (item.indexOf('.min.js') === -1)) { + dest = item.substring(0, item.length - 3) + '.min' + item.substring(item.length - 3); + orig_code = fs.readFileSync('./static/' + item, 'utf8'); + ast = jsp.parse(orig_code); + ast = pro.ast_mangle(ast); + ast = pro.ast_squeeze(ast); + fs.writeFileSync('./static/' + dest, pro.gen_code(ast), 'utf8'); + winston.info('compressed ' + item + ' into ' + dest); + } + } +} + // Send the static documents into the preferred store, skipping expirations for (var name in config.documents) { var path = config.documents[name]; diff --git a/static/ZeroClipboard.min.js b/static/ZeroClipboard.min.js new file mode 100644 index 0000000..2aca3c6 --- /dev/null +++ b/static/ZeroClipboard.min.js @@ -0,0 +1 @@ +var ZeroClipboard={version:"1.0.7",clients:{},moviePath:"ZeroClipboard.swf",nextId:1,$:function(a){return typeof a=="string"&&(a=document.getElementById(a)),a.addClass||(a.hide=function(){this.style.display="none"},a.show=function(){this.style.display=""},a.addClass=function(a){this.removeClass(a),this.className+=" "+a},a.removeClass=function(a){var b=this.className.split(/\s+/),c=-1;for(var d=0;d-1&&(b.splice(c,1),this.className=b.join(" ")),this},a.hasClass=function(a){return!!this.className.match(new RegExp("\\s*"+a+"\\s*"))}),a},setMoviePath:function(a){this.moviePath=a},dispatch:function(a,b,c){var d=this.clients[a];d&&d.receiveEvent(b,c)},register:function(a,b){this.clients[a]=b},getDOMObjectPosition:function(a,b){var c={left:0,top:0,width:a.width?a.width:a.offsetWidth,height:a.height?a.height:a.offsetHeight};while(a&&a!=b)c.left+=a.offsetLeft,c.top+=a.offsetTop,a=a.offsetParent;return c},Client:function(a){this.handlers={},this.id=ZeroClipboard.nextId++,this.movieId="ZeroClipboardMovie_"+this.id,ZeroClipboard.register(this.id,this),a&&this.glue(a)}};ZeroClipboard.Client.prototype={id:0,ready:!1,movie:null,clipText:"",handCursorEnabled:!0,cssEffects:!0,handlers:null,glue:function(a,b,c){this.domElement=ZeroClipboard.$(a);var d=99;this.domElement.style.zIndex&&(d=parseInt(this.domElement.style.zIndex,10)+1),typeof b=="string"?b=ZeroClipboard.$(b):typeof b=="undefined"&&(b=document.getElementsByTagName("body")[0]);var e=ZeroClipboard.getDOMObjectPosition(this.domElement,b);this.div=document.createElement("div");var f=this.div.style;f.position="absolute",f.left=""+e.left+"px",f.top=""+e.top+"px",f.width=""+e.width+"px",f.height=""+e.height+"px",f.zIndex=d;if(typeof c=="object")for(addedStyle in c)f[addedStyle]=c[addedStyle];b.appendChild(this.div),this.div.innerHTML=this.getHTML(e.width,e.height)},getHTML:function(a,b){var c="",d="id="+this.id+"&width="+a+"&height="+b;if(navigator.userAgent.match(/MSIE/)){var e=location.href.match(/^https/i)?"https://":"http://";c+=''}else c+='';return c},hide:function(){this.div&&(this.div.style.left="-2000px")},show:function(){this.reposition()},destroy:function(){if(this.domElement&&this.div){this.hide(),this.div.innerHTML="";var a=document.getElementsByTagName("body")[0];try{a.removeChild(this.div)}catch(b){}this.domElement=null,this.div=null}},reposition:function(a){a&&(this.domElement=ZeroClipboard.$(a),this.domElement||this.hide());if(this.domElement&&this.div){var b=ZeroClipboard.getDOMObjectPosition(this.domElement),c=this.div.style;c.left=""+b.left+"px",c.top=""+b.top+"px"}},setText:function(a){this.clipText=a,this.ready&&this.movie.setText(a)},addEventListener:function(a,b){a=a.toString().toLowerCase().replace(/^on/,""),this.handlers[a]||(this.handlers[a]=[]),this.handlers[a].push(b)},setHandCursor:function(a){this.handCursorEnabled=a,this.ready&&this.movie.setHandCursor(a)},setCSSEffects:function(a){this.cssEffects=!!a},receiveEvent:function(a,b){a=a.toString().toLowerCase().replace(/^on/,"");switch(a){case"load":this.movie=document.getElementById(this.movieId);if(!this.movie){var c=this;setTimeout(function(){c.receiveEvent("load",null)},1);return}if(!this.ready&&navigator.userAgent.match(/Firefox/)&&navigator.userAgent.match(/Windows/)){var c=this;setTimeout(function(){c.receiveEvent("load",null)},100),this.ready=!0;return}this.ready=!0,this.movie.setText(this.clipText),this.movie.setHandCursor(this.handCursorEnabled);break;case"mouseover":this.domElement&&this.cssEffects&&(this.domElement.addClass("hover"),this.recoverActive&&this.domElement.addClass("active"));break;case"mouseout":this.domElement&&this.cssEffects&&(this.recoverActive=!1,this.domElement.hasClass("active")&&(this.domElement.removeClass("active"),this.recoverActive=!0),this.domElement.removeClass("hover"));break;case"mousedown":this.domElement&&this.cssEffects&&this.domElement.addClass("active");break;case"mouseup":this.domElement&&this.cssEffects&&(this.domElement.removeClass("active"),this.recoverActive=!1)}if(this.handlers[a])for(var d=0,e=this.handlers[a].length;d - - + +