/*! * e9Digital vendor widget - http://www.e9digital.com * Copyright (C) 2011 e9Digital * Author: Travis Cox * * For the documented source see http://www.e9digital.com/javascripts/vwidget.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 VWidget public namespace */ E9 = window.E9 || {}; (function() { if (E9 && E9.VWidget) return; /** * @constructor * @param {Object} opts the configuration options for the page */ E9.VWidget = function(opts) { this.init(opts); } E9.VWidget.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'; } 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':'vb-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('vb-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: 'vb-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.VWidget 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.VWidget 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 'vb-heading', regardless of the tag. */ headingTag: 'h2', /** * The html tag used for widget subheadings. The class of these elements * is 'vb-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.VWidget.COUNT; // and defines a global callback on E9.VWidget for jsonp E9.VWidget[this.callback] = function(response) { clearTimeout(that.jsonRequestTimer); that.renderHtmlFromResponse(response); that.removeScriptElement(); } // code must be passed if (!opts.code) { html = tag('h3', {'class':'vb-error'}, 'E9.VWidget requires that you pass a code identifying yourself as a member'); } else { html = tag('h3', {'class':'vb-loading'}, 'Loading...'); this.scriptUrl = this.url + '/directory/members/' + opts.code + '.json?jsonp=E9.VWidget.' + 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, "vb-recaptcha", { theme: this.recaptchaTheme, callback: function() {} }); }, addStylesheets: function() { var link = document.createElement("link"); link.href = this.url + "/stylesheets/vb-widget.css"; link.rel = "stylesheet"; link.type = "text/css"; addHeadElement(link); if (browser().version < 8) { link = document.createElement("link"); link.href = this.url + "/stylesheets/vb-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.VWidget.ERROR_MESSAGE; }, this.timeout); }, getFieldElements: function() { var elements = new Array(); try { elements.push(document.getElementById('vb-form-name')); elements.push(document.getElementById('vb-form-phone')); elements.push(document.getElementById('vb-form-email')); } catch(e) { } finally { return elements; } }, getShowLinks: function() { var showlinks = new Array(); try { var links = document.getElementById('vb-vendor-list').getElementsByTagName('a'); for(var i=0;i