Skip to content

Instantly share code, notes, and snippets.

@xiata
Created April 9, 2012 23:04
Show Gist options
  • Save xiata/2347239 to your computer and use it in GitHub Desktop.
Save xiata/2347239 to your computer and use it in GitHub Desktop.
Refactor of GetSatisfaction Feedback widget embed.
(function() {
var GSFN = {
gId: function(id) {
return (typeof id == "string" ? document.getElementById(id) : id);
},
hasClassName: function(element, className) {
return new RegExp("\\s*" + className + "\\b").test(element.className || "");
},
addClassName: function(element, className) {
if (!GSFN.hasClassName(element, className)) element.className += (element.className ? ' ' : '') + className;
return element;
},
removeClassName: function(element, className) {
element.className = GSFN.strip(element.className.replace(new RegExp("\\s*" + className + "\\b"), ''));
return element;
},
strip: function(string) {
return string.replace(/(^\s+)|(\s+$)/g, '');
},
add_css: function(css_content) {
var style = document.createElement('style');
style.type = 'text/css';
if (style.styleSheet) {
style.styleSheet.cssText = css_content;
} else {
style.appendChild(document.createTextNode(css_content));
}
(document.getElementsByTagName('head')[0] || document.body).appendChild(style);
},
feedback_widget: function(options) {
this.options = options || {};
this.options.display = this.options.display || "overlay";
this.options.placement = this.options.placement || 'left';
this.options.color = this.options.color || '#222';
this.widget_disabled = false;
this.feedback_base_url = location.protocol + local_base_url;
this.asset_base_url = (this.options.local_assets ? this.feedback_base_url : location.protocol + s3_base_url);
var initialURL = '';
if (this.options.display == 'overlay') {
this.options.width = this.options.width || "658px";
this.options.height = this.options.height || "100%";
} else {
initialURL = this._feedbackURL();
this.options.width = this.options.width || "100%";
this.options.height = this.options.height || "500px";
}
var self = this;
if (this.options.display == 'overlay') {
GSFN.add_css(templates.css(this.asset_base_url));
var tabHTML = templates.tab(this.options.color, this.options.placement);
var overlayHTML = templates.overlay(this.widget_disabled, initialURL, this.options.width, this.options.height);
appendHTML(this.options.container, tabHTML + overlayHTML, function() {
self._refElements();
addEvent('fdbk_tab', 'click', self.show, self);
addEvent('fdbk_close', 'click', self.hide, self);
self._iframe.removeAttribute("src");
});
} else {
var iframeHTML = templates.iframe(this.widget_disabled, initialURL, this.options.width, this.options.height);
appendHTML(this.options.container, iframeHTML, function() { self._refElements(); });
}
}
};
GSFN.feedback_widget.prototype = {
VERSION: 2,
asset_url: function(asset) {
return this.asset_base_url + asset;
},
set_position: function() {
this.scroll_top = document.documentElement.scrollTop || document.body.scrollTop;
this.scroll_height = document.documentElement.scrollHeight;
this.client_height = window.innerHeight || document.documentElement.clientHeight;
this._screen.style.height = this.scroll_height+"px";
this._container.style.top = this.scroll_top+(this.client_height*0.1)+"px";
},
show: function() {
this._iframe.setAttribute("src", this._feedbackURL());
addOnceEvent(this._iframe, "load", this.loaded, this);
addOnceEvent(this._iframe, "error", this.notloaded, this);
this.set_position();
GSFN.addClassName(this._html, 'feedback_tab_on');
this._overlay.style.display = "block";
return false;
},
hide: function() {
this._overlay.style.display = "none";
this._iframe.removeAttribute("src");
GSFN.removeClassName(this._iframe, "loading");
GSFN.removeClassName(this._html, 'feedback_tab_on');
return false;
},
loaded: function() {
GSFN.addClassName(this._iframe, "loaded");
},
notLoaded: function() {
GSFN.removeClassName(this._iframe, "loaded");
},
get_fastpass_url: function(options) {
if (options.fastpass) {
return options.fastpass;
}
var script_tags = document.getElementsByTagName('script');
for (var i = 0; i < script_tags.length; i++) {
var tag = script_tags[i];
if (tag.src.match(/\/fastpass/ && tag.src.match(/oauth/))) {
return tag.src;
}
}
},
// Generate the feedback URL.
_feedbackURL: function() {
var o = this.options, fields = feedback_fields, tagged = feedback_tagged, queries = [];
for (var i = 0; i < fields.length; ++i) {
if (o[fields[i]] != null) queries.push(fields[i] + "=" + o[fields[i]]);
}
var fastpass = this.get_fastpass_url(o);
if (fastpass) queries.push('fastpass=' + fastpass);
if (o.auto_tag != false) {
for (var i = 0; i < tagged.length; ++i) {
if (o[tagged[i]] != null) queries.push(tagged[i] + "=" + escFunc(o[tagged[i]]));
}
}
return this.feedback_base_url + "/" + this.options.company + "/feedback/topics/new?" + queries.join('&');
},
_refElements: function() {
this._screen = GSFN.gId('fdbk_screen');
this._container = GSFN.gId('fdbk_container');
this._iframe = GSFN.gId('fdbk_iframe');
this._overlay = GSFN.gId('fdbk_overlay');
this._html = document.getElementsByTagName('html')[0];
}
};
// Export GSFN feedback widget by merging.
if (!window.GSFN) window.GSFN = {};
for (var k in GSFN) {
if (GSFN.hasOwnProperty(k)) window.GSFN[k] = GSFN[k];
}
// == Private data ================================
var local_base_url = "//getsatisfaction.com";
var s3_base_url = "//d1xklv3tn7qmp2.cloudfront.net"; //s3_base_url = "//d3rdqalhjaisuu.cloudfront.net";
var escFunc = encodeURIComponent || escape;
var feedback_fields = ['display', 'style', 'popular_topics', 'limit', 'problem', 'powered_by', 'custom_css', 'custom_ie_css', 'custom_js', 'auto_tag', 'interstitial', 'community_base_url', 'document_domain'];
var feedback_tagged = ['product', 'tag', 'user_defined_code'];
// Don't use DOM 1 event listeners when you can avoid it.
var addEvent = (function() {
if (window.addEventListener) {
return function(obj, type, callback, scope) { // Most everyone
obj = GSFN.gId(obj);
if (scope) return obj.addEventListener(type, function() { return callback.apply(scope, arguments); }, false);
else return GSFN.gId(obj).addEventListener(type, callback, false);
}
}
return function(obj, type, callback, scope) { // IE 6 - 8
obj = GSFN.gId(obj);
if (scope) return obj.attachEvent("on" + type, function() { return callback.apply(scope, arguments); });
else return obj.attachEvent("on" + type, callback);
}
})();
var addOnceEvent = (function(obj, type, callback, scope) {
obj = GSFN.gId(obj);
var func = function() {
if (window.removeEventListener) obj.removeEventListener(type, callback, false);
else obj.detachEvent("on" + type, callback);
callback.apply(scope || this, arguments);
}
addEvent(obj, type, func);
});
// Avoid document.write(). Widget will render either in container or body if not found.
// Note: this does nothing if the page is already loaded and the item can't be found.
var appendHTML = function(container, html, callback) {
var container_el = GSFN.gId(container);
callback = callback || function() {};
if (container_el) {
container_el.innerHTML += html;
callback(container_el);
}
else {
function later() {
if (!later.loaded) {
later.loaded = true;
var container_el = (GSFN.gId(container) || document.body);
container_el.innerHTML += html;
callback(container_el);
}
}
addEvent(window, "DOMContentLoaded", later);
addEvent(window, "load", later);
}
}
// Honestly this should be generated by HAMLJS.
var templates = {
tab: function(color, placement) {
return '<a href="#" id="fdbk_tab" class="fdbk_tab_'+placement+'" style="background-color:'+color+'">FEEDBACK</a>';
},
overlay: function(enabled, url, width, height) {
return '<div id="fdbk_overlay" style="display:none"><div id="fdbk_container"><a href="#" id="fdbk_close"></a>' + templates.iframe(enabled, url, width, height) + '</div><div id="fdbk_screen"></div></div>';
},
iframe: function(disabled, url, width, height) {
if (disabled) {
return '<div id="fdbk_iframe" style="position:relative; top: 20px; margin:20px;background:orange;color:purple;font-size:72px; padding: 20px;">WIDGETS ARE UNAVAILABLE LOL</div>';
} else {
url = url ? (' src="' + url + '"') : ''
return '<iframe id="fdbk_iframe" allowTransparency="true" scrolling="no" frameborder="0" class="loading" width="'+width+'" height="'+height+'" style="width: '+width+'; height: '+height+';"' + url + '></iframe>';
}
},
css: function(url) {
return "#fdbk_overlay {\n width: 100%;\n height: 100%;\n top: 0;\n left: 0;\n z-index: 1000000;\n position: absolute; }\n\n#fdbk_screen {\n top: 0;\n left: 0;\n z-index: 1;\n width: 100%;\n position: absolute;\n background-color: black;\n opacity: 0.45;\n -moz-opacity: 0.45;\n filter: alpha(opacity=45); }\n\n#fdbk_container {\n width: 680px;\n height: 640px;\n margin: 0 auto;\n z-index: 2;\n position: relative; }\n #fdbk_container iframe {\n width: 658px;\n height: 100%;\n margin: 20px;\n background: transparent; }\n #fdbk_container iframe.loading {\n background: transparent url("+url+"/_cb/8e27877/assets/fb_loading.png) no-repeat; }\n\na#fdbk_tab {\n top: 25%;\n left: 0;\n width: 42px;\n height: 102px;\n color: white;\n cursor: pointer;\n text-indent: -100000px;\n overflow: hidden;\n position: fixed;\n z-index: 100000;\n margin-left: -7px;\n background-image: url("+url+"/_cb/8e27877/assets/feedback_trans_tab.png);\n _position: absolute;\n _background-image: url("+url+"/_cb/8e27877/assets/feedback_tab_ie6.png); }\n a#fdbk_tab:hover {\n margin-left: -4px; }\n\na.fdbk_tab_right {\n right: 0 !important;\n left: auto !important;\n margin-right: 0 !important;\n margin-left: auto !important;\n width: 35px !important; }\n a.fdbk_tab_right:hover {\n width: 38px !important;\n margin-right: 0 !important;\n margin-left: auto !important; }\n\na.fdbk_tab_bottom {\n top: auto !important;\n bottom: 0 !important;\n left: 20% !important;\n height: 38px !important;\n width: 102px !important;\n background-position: 0 -102px !important;\n margin-bottom: -7px !important;\n margin-left: auto !important; }\n a.fdbk_tab_bottom:hover {\n margin-bottom: -4px !important;\n margin-left: auto !important; }\n\na.fdbk_tab_hidden {\n display: none !important; }\n\na#fdbk_close {\n position: absolute;\n cursor: pointer;\n outline: none;\n top: 0;\n left: 0;\n z-index: 4;\n width: 42px;\n height: 42px;\n overflow: hidden;\n background-image: url("+url+"/_cb/8e27877/assets/feedback-close.png);\n _background: none;\n _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\""+url+"/_cb/8e27877/assets/feedback-close.png\", sizingMethod='crop'); }\n a#fdbk_close:hover {\n background-position: -42px 0; }\n\n.feedback_tab_on embed, .feedback_tab_on select, .feedback_tab_on object {\n visibility: hidden; }\n";
}
};
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment