Dealer widget scripts
Uncompressed dealer widget code
Please note that this example of the script may not be absolutely up-to-date.
The CSS used by the widget to display the modal is first minified and then included in the JS below, which is itself then minified. The original CSS is detailed below.
// wrapped up this way to minimise namespace pollution (function(win, doc) { // ====================================================================== // CONFIG // ====================================================================== var _Proto = 'https://'; var _Host = 'www.classicandsportsfinance.com'; var _HostPath = _Host + '/finance-enquiry-form'; var _Buttons = _Proto + _Host + '/dealer-widget/buttons/'; var _WidgetClass = 'csf-enquiry-widget'; var _WidgetTooltip = "Finance options are available for this vehicle"; var _ScriptWidgetType = 'CSF/Widget'; var _FrameURL = _Proto + _Host + '/dealer-widget-form/'; var _Params = ['make-model', 'price', 'dealer', 'image']; var _WidgetMinHeight = 500; var _WidgetMinWidth = 600; var _WidgetMaxHeight = 500; var _WidgetMaxWidth = 600; var _WidgetFrameID = "csf_widget_frame"; var _WidgetContainerID = "csf_widget_container"; var _CSS = ""; // put minified CSS in here // ====================================================================== // FUNCTIONS // ====================================================================== // create a stylesheet tag based on our minified CSS, and add it to the page function loadWidgetStyles() { // create a stylesheet tag element var ss = doc.createElement('style'); var hh = doc.getElementsByTagName('head')[0]; ss.setAttribute('type', 'text/css'); // add the tag to the document head // (this odd order helps with older IE) hh.appendChild(ss); // now append the CSS source if (ss.styleSheet) { ss.styleSheet.cssText = _CSS; } else { ss.appendChild(doc.createTextNode(_CSS)); } } // safe log file wrapper function log(msg) { if(console) console.log(msg); } // calculate a popup size // returns a boolean indicating if there's enough room function getPopupDimensions(wdims) { var pdims = { w: (_WidgetMaxWidth > wdims.w ) ? Math.floor(wdims.w * 0.9) : _WidgetMaxWidth, h: (_WidgetMaxHeight > wdims.h ) ? Math.floor(wdims.h * 0.9) : _WidgetMaxHeight }; return ((pdims.w >= _WidgetMinWidth) && (pdims.h >= _WidgetMinHeight)) ? pdims : null; } // get the dimensions of the current window function getWindowDimensions() { return { w: win.innerWidth || doc.documentElement.clientWidth || doc.body.clientWidth, h: win.innerHeight || doc.documentElement.clientHeight || doc.body.clientHeight }; } // this is really just for tidy code! function px(x) { return '' + x + 'px'; } // cross-platform add and remove event handlers function addEventHandler(e,ev,h) { // standards-compliant if (e.addEventListener) e.addEventListener(ev,h,false); // IE 8 else if (e.attachEvent) e.attachEvent('on'+ev,h); } function removeEventHandler(e,ev,h) { // standards-compliant if (e.removeEventListener) e.removeEventListener(ev,h,false); // IE 8 if (e.detachEvent) e.detachEvent('on'+ev,h); } // pressing the escape key clears the popup function escapeKeyHandler(e) { if(e.keyCode==27) widgetFormClose(); } // extract enquiry form parameters from the data attributes function buildEnquiryParamsFromAttributes(el, ps) { for(pi =0; pi < _Params.length; pi++) { var param = _Params[pi]; // if the attribute is specified (e.g. data-price), extract it var val = el.getAttribute('data-' + param); if((typeof(val) != 'undefined') && val) { ps[param] = val; } else { // if an extract attribute is set (e.g. data-extract-price) // locate the element it refers to, and calculate its plain text content var sel = el.getAttribute('data-extract-' + param); if((typeof(sel) != 'undefined') && sel) { var selected = doc.querySelector(sel); var selected_val = (selected.innerText || selected.textContent || '').replace(/[\s\n\t\r]+/, ' '); ps[param] = selected_val; } } } return ps; } // extract enquiry form parameters from the query string function buildEnquiryParamsFromQueryString(el, ps) { var qs = el.search.replace(/^\?/, '').split('&'); for( qi = 0; qi < qs.length; qi++ ) { var p = qs[qi].split('='); ps[p[0]] = decodeURIComponent(p[1].replace(/\+/g, '%20')); } return ps; } // create a new URL with our sanitised/combined parameters function getURLWithParameters(url, el) { var pairs = []; for(pi =0; pi < _Params.length; pi++) { var param = _Params[pi]; if(param == 'image') { continue; } var val; if(val = el.csf_enquiry_params[param]) { pairs[pairs.length] = param + '=' + encodeURIComponent(val); } } if(url.indexOf('/', url.length - 1) === -1) { url = url + '/'; } return url + '?' + pairs.join('&'); } // find all image links function findAllFormLinks() { var ws = []; // find all the CSF links in the page var links = doc.querySelectorAll( 'a[href^="http://' + _HostPath + '"], ' + 'a[href^="https://' + _HostPath + '"]'); var num_links = links.length; // loop through, annotating the script tags with the enquiry params for(var i=0;i<num_links;i++) { var l = links[i]; // if this isn't an upgraded button, we need to pull the enquiry params if(!l.csf_enquiry_params) { // enquiry params can come from the query string or from data attributes l.csf_enquiry_params = buildEnquiryParamsFromAttributes(l, buildEnquiryParamsFromQueryString(l, {})); } // we can use it if we have a dealer id if(l.csf_enquiry_params.dealer) { ws[ws.length] = l; } } return ws; } // find all our pure-javascript buttons function findAllScriptWidgets() { var ws = []; // find all the script tags in the page var ss = doc.querySelectorAll('script[type="' + _ScriptWidgetType + '"]'); var num_ss = ss.length; // loop through, annotating the script tags with the enquiry params for(var i=0;i<num_ss;i++) { var scr = ss[i]; scr.csf_enquiry_params = buildEnquiryParamsFromAttributes(scr, {}); // just needs a dealer ID to be useful if(scr.csf_enquiry_params.dealer) { ws[ws.length] = scr; } } return ws; } // close the widget form and clear up function widgetFormClose() { // clear any modal wrappers var modals = doc.querySelectorAll('.' + _WidgetClass + '-modal'); for (var i = 0; i < modals.length; i++) { modals[i].parentNode.removeChild(modals[i]); } // clear any containers var widgets = doc.querySelectorAll('.' + _WidgetClass + '-form-container'); for (var i = 0; i < widgets.length; i++) { widgets[i].parentNode.removeChild(widgets[i]); } // tidying up: remove the event handler we added removeEventHandler(win, 'keypress', escapeKeyHandler); removeEventHandler(win, 'resize', windowResizeHandler); return false; } function resizeContainer(c, pdims, wdims) { c.style.height = px(pdims.h); c.style.width = px(pdims.w); c.style.top = px(Math.floor((wdims.h - pdims.h) / 2)); c.style.left = px(Math.floor((wdims.w - pdims.w) / 2)); } function resizeFrame(f, pdims) { f.style.height = px(pdims.h); f.style.width = px(pdims.w); f.height = pdims.h; f.width = pdims.w; } function windowResizeHandler() { var wdims = getWindowDimensions(); var pdims = getPopupDimensions(wdims); if(pdims) { resizeContainer(doc.getElementById(_WidgetContainerID), pdims, wdims); resizeFrame(doc.getElementById(_WidgetFrameID), pdims); } } function widgetClick() { // close anything that is open now widgetFormClose(); // window dimensions var wdims = getWindowDimensions(); // check browser size against requirements var pdims = getPopupDimensions(wdims); if(!pdims) { log('The browser window is too small to display the popup.'); this.target="_blank"; return true; } // modal overlay var modal = doc.createElement('div'); modal.className = _WidgetClass + '-modal'; modal.onclick = widgetFormClose; // the popup container var container = doc.createElement('div'); container.className = _WidgetClass + '-form-container'; container.id= _WidgetContainerID; container.style.display = 'block'; resizeContainer(container, pdims, wdims); // close button for the popup var button = doc.createElement('span'); button.innerHTML = 'close window'; button.onclick = widgetFormClose; // inner div for the popup var inner = doc.createElement('div'); inner.className = _WidgetClass + '-form-container-inner'; // the iframe where the enquiry actually happens var frame = doc.createElement('iframe'); frame.src = getURLWithParameters(_FrameURL, this); frame.scrolling = "no"; frame.frameBorder = "0"; frame.id= _WidgetFrameID; resizeFrame(frame, pdims); // add the button and iframe to the inner inner.appendChild(button); inner.appendChild(frame); // add the inner part to the container container.appendChild(inner); // add the modal overlay to the page modal.style.display = 'block'; doc.body.appendChild(modal); // add the popup on top doc.body.appendChild(container); // add the escape key handler addEventHandler(win, 'keypress', escapeKeyHandler); // and the resize handler addEventHandler(win, 'resize', windowResizeHandler); return false; } // this function converts the script-type widget to a clickable image // before the main function upgrades it function convertScriptWidgets() { var ss = findAllScriptWidgets(); for(i=0; i < ss.length; i++) { var s = ss[i]; // create an image var im = doc.createElement('img'); im.src = _Buttons + (s.csf_enquiry_params.image || 'black_fe_orange_grey_120') + '.png'; // create A link var a = doc.createElement('a'); a.csf_enquiry_params = s.csf_enquiry_params; a.href= _Proto + _HostPath; a.appendChild(im); // make a note of where the script tag is var sp = s.parentNode; var sn = s.nextSibling; // now remove it s.parentNode.removeChild(s); // insert the A link where the script was if(sn) { sp.insertBefore(a, sn); } else { sp.appendChild(a); } } } // this function upgrades the links so they launch a popup instead function upgradeFormLinks() { var fls = findAllFormLinks(); for(i=0; i < fls.length; i++) { var fl = fls[i]; // add the click action fl.removeAttribute('target'); fl.onclick = widgetClick; // add a simple tooltip fl.title = _WidgetTooltip; // update the link with the fully-configured URL, for right-click friendliness fl.href = getURLWithParameters(_Proto + _HostPath, fl); } } // this kicks it all off // run directly or as a result of an onload handler function run() { // load our stylesheet loadWidgetStyles(); // convert buttons to image links convertScriptWidgets(); // upgrade form links upgradeFormLinks(); } // ====================================================================== // HERE'S WHERE IT STARTS // ====================================================================== // this script requires querySelector/querySelectorAll // which is supported by pretty much everything except IE7 and IE6 // (Note that this also rules out IE8 in compatibility mode) if(!doc.querySelector) { log("This browser does not support the CSF enquiry widget."); return; } // examine the document's state switch (doc.readyState) { // DOM not ready so we add an onload handler to do our stuff case "uninitialized": case "loading": case "loaded": addEventHandler(win, "load", function() { run(); }); break; // in these cases, the DOM is ready so we can continue case "interactive": case "complete": run(); } }(window, document));
Uncompressed widget CSS
The CSS, unminified:
.csf-enquiry-widget-modal { display: none; position: fixed; left: 0; top: 0; width: 100%; height: 100%; background: #000; filter: alpha(Opacity = 50); opacity: 0.5; -moz-opacity: 0.5; -khtml-opacity: 0.5; z-index: 999999; } .csf-enquiry-widget-form-container { display: none; position: fixed; border: 3px solid #999; -webkit-box-shadow: 10px 10px 12px 1px rgba(0,0,0,0.27); -moz-box-shadow: 10px 10px 12px 1px rgba(0,0,0,0.27); box-shadow: 10px 10px 12px 1px rgba(0,0,0,0.27); z-index: 999999; } .csf-enquiry-widget-form-container-inner { background-color: #fff; position: relative; top: 0; } .csf-enquiry-widget-form-container-inner span { cursor: pointer; position: absolute; display: inline-block; font-family: Arial, Helvetica, sans-serif; top: 8px; right: 8px; border: 0; font-size: 12px; text-align: center; color: #fff; background: #999; border-radius: 5px; padding: 0.25em 0.5em; text-decoration: none; } .csf-enquiry-widget-form-container-inner span:hover { text-decoration: none; background-color: #444; } .csf-enquiry-widget-form-container iframe { display: block; border: none; }