/*!
* e9Digital Vendor Widget - http://www.e9digital.com
* Copyright (C) 2011 e9Digital
* Author: Travis Cox
*
* For the documented source see http://www.e9digital.com/javascripts/vendor-widget.js
*
* Basic Usage:
*
* In addition to "code" several other options are available, including callbacks
* which provide access to the Widget and its generated HTML, these documentation
* for these options can be found at the above url.
*/
/**
* @namespace E9 VendorWidget public namespace
*/
E9 = window.E9 || {};
(function() {
if (E9 && E9.VendorWidget) return;
/**
* @constructor
* @param {Object} opts the configuration options for the page
*/
E9.VendorWidget = function(opts) {
this.init(opts);
}
E9.VendorWidget.jsonP = function(url, callback) {
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = url;
var head = document.getElementsByTagName('head')[0];
head.insertBefore(script, head.firstChild);
callback(script);
return script;
}
var
/*
Developed by Robert Nyman, http://www.robertnyman.com
Code/licensing: http://code.google.com/p/getelementsbyclassname/
*/
getElementsByClassName = function (className, tag, elm){
if (document.getElementsByClassName) {
getElementsByClassName = function (className, tag, elm) {
elm = elm || document;
var elements = elm.getElementsByClassName(className),
nodeName = (tag)? new RegExp("\\b" + tag + "\\b", "i") : null,
returnElements = [],
current;
for(var i=0, il=elements.length; i'+content+'' + element + '>';
} else {
html += '/>';
}
return html;
},
/*
* helper function to create divs, simple interface to #tag
*/
div = function(attrs, content) {
return tag('div', attrs, content);
},
boolCheckbox = function(default_value, attrs, label) {
attrs['type'] = 'checkbox';
attrs['checked'] = 'checked';
attrs['value'] = '0';
attrs['style'] = 'display:none;visibility:hidden';
var retv = tag('input', attrs);
if (!default_value) delete attrs['checked'];
delete attrs['style'];
attrs['value'] = '1';
retv += tag('input', attrs);
if (label) retv += tag('label', {'class':'e9-label'}, label);
return retv;
},
timestamp = function() {
return new Date().getTime();
},
wait = function(options) {
options.success = options.success || function() {};
options.until = options.until || function() { return false; };
options.error = options.error || function() {};
options.timeout = options.timeout || 5000;
options.interval = options.interval || 2;
var start = timestamp(), elapsed, now;
window.setTimeout(function() {
now = timestamp();
elapsed = now - start;
if (options.until(elapsed)) {
options.success();
return false;
}
if (now >= start + options.timeout) {
options.error();
return false;
}
window.setTimeout(arguments.callee, options.interval);
}, options.interval)
},
resetForm = function() {
var form = document.getElementById('e9-form'),
inputs = form.getElementsByTagName('input');
for (var i=0;i
*
*
*
* B. Deferred:
*
* ...
*
*
* In case A, the widget will be written in place where it is called.
* In case B, the widget will be written inside the div "foo" that
* already exists. In this way you could defer the loading til the end
* of the page, or in, for example, the jQuery.ready handler;
*
* Note that in case B, if elementId is passed but does not exist,
* the widget will still write itself in place, but inside an element
* with the ID passed.
*/
elementId: 'e9-widget-container',
/**
* By default the widget prepends a stylesheet link to which
* contains widget specific styles (plus an additional IE stylesheet if
* an IE browser is detected).
*
* Passing this as false prevents the style load from happening.
*/
styles: true,
/**
* A callback which occurs at the end of the init process, before render.
* At this point the widget is fully configured, but waiting on initial
* response from the server before rendering HTML.
*
* To manipulate HTML you should not use this, but onRender
*
* @param {Function} widget The E9.VendorWidget instance being created
*/
onInit: function(widget) {},
/**
* A callback which occurs after the HTML has been rendered, immediately
* before it is made visible. At this point you have access to all the
* HTML generated by the widget, referenced by the widget property 'element'.
*
* @param {Function} widget the E9.VendorWidget instance being created
*/
onRender: function(widget) {},
/**
* Callback that occurs on timeout error. You may override this if, e.g.
* you wanted to change the error message or HTML.
*/
onError: function(widget) {},
/**
* the timeout to wait for a response from the vendorboon server before displaying
* an error.
*/
timeout: 10000,
/**
* the timeout to wait for a response from the google recaptcha server before displaying
* an error.
*/
recaptcha_timeout: 10000,
/**
* The html tag used for widget headings. The class of these elements
* is 'e9-heading', regardless of the tag.
*/
headingTag: 'h2',
/**
* The html tag used for widget subheadings. The class of these elements
* is 'e9-subheading', regardless of the tag.
*/
subheadingTag: 'h3',
/**
* The text of the "Show Description" links which show or hide the long
* description for each vendor.
*/
showDescText: 'View More Info',
/**
* The recaptcha theme used.
*
* Accepted options: red, white, blackglass, clean
*
* For details, see:
* http://code.google.com/apis/recaptcha/docs/customization.html
*
*/
recaptchaTheme: 'white'
};
return {
init: function(opts) {
var that = this, html;
if (!opts) opts = {};
this.url = opts.url || defaults.url;
// if url is protocol relative, prepend protocol
if (/^\/\//.test(this.url)) {
this.url = location.protocol + this.url;
// else if we're https, ensure the url is
} else if (location.protocol.match(/^https/)) {
this.url = this.url.replace(/^http:/, 'https:');
}
// cut trailing / from url if present
if (/\/$/.test(this.url)) this.url = this.url.substr(0, this.url.length - 1);
// defines a callback in case of more than one widget on a page (unlikely)...
this.callback = 'cb' + ++E9.VendorWidget.COUNT;
// and defines a global callback on E9.VendorWidget for jsonp
E9.VendorWidget[this.callback] = function(response) {
clearTimeout(that.jsonRequestTimer);
that.renderHtmlFromResponse(response);
that.removeScriptElement();
}
// code must be passed
if (!opts.code) {
html = tag('h3', {'class':'e9-error'}, 'E9.VendorWidget requires that you pass a code identifying yourself as a member');
} else {
html = tag('h3', {'class':'e9-loading'}, 'Loading...');
this.scriptUrl = this.url + '/directory/members/' + opts.code + '.json?jsonp=E9.VendorWidget.' + this.callback;
this.formUrl = this.url + '/contact_requests.json';
}
/* form is currently off */
this.showForm = false;
this.recaptchaPublicKey = recaptchaPublicKey;
this.recaptchaTheme = opts.recaptchaTheme || defaults.recaptchaTheme;
this.recaptcha_timeout = opts.recaptcha_timeout || defaults.recaptcha_timeout;
this.styles = opts.hasOwnProperty('styles') ? opts.styles : true
this.timeout = opts.timeout || defaults.timeout;
this.elementId = opts.elementId || defaults.elementId;
this.onRender = opts.onRender || defaults.onRender;
this.onInit = opts.onInit || defaults.onInit;
this.timeout = opts.timeout || defaults.timeout;
this.headingTag = opts.headingTag || defaults.headingTag;
this.subheadingTag = opts.subheadingTag || defaults.subheadingTag;
this.showDescText = opts.showDescText || defaults.showDescText;
this.element = document.getElementById(this.elementId);
if (!this.element) {
document.write(div(this.elementId, ''));
this.element = document.getElementById(this.elementId);
}
if (opts.width) this.element.style.width = opts.width;
if (opts.height) this.element.style.height = opts.height;
this.element.innerHTML = html;
this.onInit(this);
},
removeScriptElement: function() {
removeHeadElement(this.scriptElement);
},
addReCAPTCHAScript: function() {
var script = document.createElement('script');
script.type = 'text/javascript';
// NOTE protocol relative recaptcha url
script.src = "//www.google.com/recaptcha/api/js/recaptcha_ajax.js";
var head = document.getElementsByTagName('head')[0];
head.insertBefore(script, head.firstChild);
},
displayReCAPTCHA: function() {
Recaptcha.create(this.recaptchaPublicKey, "e9-recaptcha", {
theme: this.recaptchaTheme,
callback: function() {}
});
},
addStylesheets: function() {
var link = document.createElement("link");
link.href = this.url + "/stylesheets/e9-widget.css";
link.rel = "stylesheet";
link.type = "text/css";
addHeadElement(link);
if (browser().version < 8) {
link = document.createElement("link");
link.href = this.url + "/stylesheets/e9-widget-ie.css";
link.rel = "stylesheet";
link.type = "text/css";
addHeadElement(link);
}
},
setTimeout: function(e) {
var that = this;
this.jsonRequestTimer = window.setTimeout(function() {
that.element.innerHTML = E9.VendorWidget.ERROR_MESSAGE;
}, this.timeout);
},
getFieldElements: function() {
var elements = new Array();
try {
elements.push(document.getElementById('e9-form-name'));
elements.push(document.getElementById('e9-form-phone'));
elements.push(document.getElementById('e9-form-email'));
} catch(e) {
} finally {
return elements;
}
},
getShowLinks: function() {
var showlinks = new Array();
try {
var links = document.getElementById('e9-vendor-list').getElementsByTagName('a');
for(var i=0;i