﻿Native.implement([Element, Window, Document, Events], { addOneEvent: function (type, fn) { return this.addEvent(type, function () { this.removeEvent(type, arguments.callee); return fn.apply(this, arguments) }) } }); String.implement({ parseQueryString: function () { var vars = this.split(/[&;]/), res = {}; if (vars.length) vars.each(function (val) { var index = val.indexOf('='), keys = index < 0 ? [''] : val.substr(0, index).match(/[^\]\[]+/g), value = decodeURIComponent(val.substr(index + 1)), obj = res; keys.each(function (key, i) { var current = obj[key]; if (i < keys.length - 1) obj = obj[key] = current || {}; else if ($type(current) == 'array') current.push(value); else obj[key] = $defined(current) ? [current, value] : value }) }); return res } }); Element.implement({ toJSON: function () { var queryObject = {}; this.getElements('input, select, textarea', true).each(function (el) { if (!el.name || el.disabled || el.type == 'submit' || el.type == 'reset' || el.type == 'file') return; var value = (el.tagName.toLowerCase() == 'select') ? Element.getSelected(el).map(function (opt) { return opt.value }) : ((el.type == 'radio' || el.type == 'checkbox') && !el.checked) ? null : el.value; $splat(value).each(function (val) { if (typeof val != 'undefined') { if (typeof queryObject[el.name] != 'undefined') { if ($type(queryObject[el.name]) == 'array') { queryObject[el.name].push(val) } else { queryObject[el.name] = [queryObject[el.name], val] } } else { queryObject[el.name] = val } } }) }); return queryObject } }); var CNB = {}; CNB.log = function () { if (window.console && console.log) { try { console.log.apply(console, arguments) } catch (e) { console.log(Array.slice(arguments)) } } }; CNB.htmlToElement = function (html, container) { if ($type(html) == 'string') { html = new Element('div', { 'html': html }); if (container === false) { html = html.getChildren() } } return html }; CNB.scrollTo = function (id) { var section = $(id); if (section !== null) { var scroll = new Fx.Scroll(window).toElement(section) } }; CNB.getCookieHost = function () { var hostMatch = location.hostname.match("([^\.]*?)\.(com|net|org|co\.uk|com\.au|co\.cn)$"); if ($chk(hostMatch)) { return '.' + hostMatch[0] } else { return location.hostname } }; CNB.hasCookiesEnabled = function () { Cookie.write('cookies-enabled', 'enabled'); if (Cookie.read('cookies-enabled') != null) { Cookie.dispose('cookies-enabled'); return true } else { return false } }; CNB.User = new Hash({ 'regId': null, 'isLoggedIn': false, 'geoDomain': null }); CNB.Overlay = new Class({ Implements: [Options, Events], options: { id: 'overlay', containerClass: 'contain-overlay-12', retainContent: false, content: null, contentId: null }, initialize: function (options) { this.setOptions(options); this.shell = new Element('div', { 'id': this.options.id, 'class': 'overlay-shell', 'styles': { 'display': 'none'} }); this.overlay = new Element('div', { 'class': 'overlay' }).inject(this.shell); this.interior = new Element('div', { 'class': 'overlay-int' }).inject(this.overlay); var closeButton = new Element('a', { 'class': 'overlay-close', 'text': 'close', 'events': { 'click': this.close.bind(this)} }).inject(this.interior); this.contentContainer = new Element('div', { 'class': 'overlay-content clear' }).inject(this.interior); this.containerClass = ''; this.setContainerClass(); this.addEvent('contentReady', function (content) { content.getElements('.close').each(function (el) { el.addEvent('click', this.close.bind(this)) } .bind(this)); var placeholders = content.getElements('*[placeholder]'); if (placeholders.length > 0) { var placeholder = new CNB.Placeholder(placeholders) } } .bind(this)); this.addEvent('open', function () { window.addEvent('keydown', this.keyEvents.bind(this)) } .bind(this)); this.addEvent('close', function () { window.removeEvent('keydown', this.keyEvents) } .bind(this)); window.addEvent('domready', function () { this.shell.inject($(document.body)) } .bind(this)) }, open: function (options) { if ($chk(options)) this.setOptions(options); window.addEvent('domready', function () { this.fireEvent('open'); this.setContainerClass(); this.setContent(); this.position(); this.shell.setStyle('display', 'block'); this.fireEvent('openComplete') } .bind(this)); return this }, close: function () { this.fireEvent('close'); this.shell.setStyle('display', 'none') }, remove: function () { this.fireEvent('remove'); this.shell.dispose() }, notify: function (message, options) { if (!$chk(message)) { CNB.log('No notification received for overlay.'); return false } var notification = new Element('div', { 'class': 'notify', 'html': message }); this.addOneEvent('openComplete', function () { this.closeDelay = this.close.delay(2500, this); this.addOneEvent('close', function () { $clear(this.closeDelay) } .bind(this)) } .bind(this)); this.open($merge(options, { 'content': notification, 'containerClass': 'contain-overlay-12' })) }, setContent: function (options) { if ($chk(options)) this.setOptions(options); this.fireEvent('setContent'); if ($chk(this.options.content)) { this._setHtml(this.options.content) } else if ($chk(this.options.contentId)) { this._getHtml(this.options.contentId) } this.setOptions({ 'content': null, 'contentId': null }) }, position: function () { var offset = Math.floor(window.getSize().y / 6); var scroll = window.getScroll().y; this.overlay.setStyle('margin-top', offset + scroll); this.shell.setStyle('height', window.getScrollSize().y) }, setContainerClass: function () { if ($chk(this.containerClass)) this.overlay.removeClass(this.containerClass); this.overlay.addClass(this.options.containerClass); this.containerClass = this.options.containerClass }, keyEvents: function (event) { if (event.key == 'esc') this.close() }, _setHtml: function (content) { if (this.contentContainer.getChildren().length > 0) this.contentContainer.empty(); if (!$chk(content)) { CNB.log('No content received for overlay.'); return false } if ($type(content) == 'string') { content = new Element('div', { 'html': content }) } content.inject(this.contentContainer); this.fireEvent('contentReady', content) }, _getHtml: function (id) { var content = $(id).get('html'); this._setHtml(content) } }); CNB.Overlay.Async = new Class({ Extends: CNB.Overlay, options: { url: '', data: '' }, initialize: function (options) { this.parent(options); this.loader = new CNB.Loading(this.contentContainer); this.addEvent('setContent', this.makeRequest.bind(this)) }, makeRequest: function () { if (!$chk(this.options.url)) return false; this.loader.add(); var request = new Request.HTML({ url: this.options.url, data: this.options.data, onSuccess: function (tree, els, html, js) { this._setHtml(html) } .bind(this), onComplete: this.loader.remove.bind(this.loader), onFailure: function (xhr) { CNB.log('request - failure'); this._setHtml('<div class="notify">Oops. Something went wrong.</div>') } .bind(this) }).get(); this.setOptions({ 'url': '', 'data': '' }) } }); CNB.Overlay.load = function (options) { var overlay; if ($chk(options.url)) { overlay = new CNB.Overlay.Async(options).open(); return false } else if (options.contentId != null || options.content != null) { overlay = new CNB.Overlay(options).open(); return false } overlay = new CNB.Overlay(options).notify('Sorry. That content could not be loaded.') }; CNB.Loading = new Class({ Implements: Options, options: { 'className': 'loading', 'opacity': '0', 'float': 'none' }, initialize: function (container, options) { this.setOptions(options); this.contentContainer = $(container); this.loadingContainer = new Element('div', { 'class': 'loading-container', 'styles': { 'float': this.options.float, 'display': this.contentContainer.getStyle('display')} }).wraps(this.contentContainer) }, add: function () { this.loadingContainer.addClass(this.options.className); this.contentContainer.setStyle('opacity', this.options.opacity) }, remove: function () { this.loadingContainer.removeClass(this.options.className); this.contentContainer.setStyle('opacity', '1'); this.contentContainer.removeProperty('style') } }); 

CNB.Selector = new Class({ Implements: [Options, Events], options: { cookieName: null, startSeq: 0, hiddenClass: 'hide' }, initialize: function (tabs, contents, options) { this.setOptions(options); this.tabs = $splat(tabs); this.contents = $splat(contents); this.seq = this.options.startSeq; if (this.options.cookieName != null) { var prevSeq = Cookie.read(this.options.cookieName); if (parseInt(prevSeq) < this.tabs.length) this.seq = prevSeq } }, load: function () { if ((this.tabs.length == 0) || (this.contents.length == 0)) return false; this.tabs.each(function (el, i) { if (!el.hasClass('external')) { el.addEvent('click', function (e) { e.stop(); this.open(i) } .bind(this)); this.close(i) } }, this); this.open(this.seq); this.addEvent('open', function () { this.close(this.seq) } .bind(this)); return this }, open: function (i) { this.fireEvent('open', i); this.tabs[i].addClass('on'); this.contents[i].removeClass(this.options.hiddenClass); this.seq = i; if (this.options.cookieName != null) { Cookie.write(this.options.cookieName, i, { 'domain': CNB.getCookieHost(), 'duration': 30, 'path': location.pathname }) } }, close: function (i) { this.fireEvent('close', i); this.tabs[i].removeClass('on'); this.contents[i].addClass(this.options.hiddenClass) } });

CNB.Pop = new Class({ Extends: CNB.Selector, options: { hiddenClass: 'pop-hidden', position: { x: 'left', y: 'bottom' }, offset: { x: 0, y: 0} }, initialize: function (tabs, contents, options) { this.parent(tabs, contents, options); this.addEvent('open', function (i) { this.contents[i].setStyle('visibility', 'visible'); this.position(i) } .bind(this)); this.addEvent('close', function (i) { this.contents[i].setStyle('visibility', 'hidden') } .bind(this)) }, load: function () {
    this.tabs.each(function (tab, i) {
        this.close(i); this.contents[i].setStyles({ 'position': 'absolute' });
        [tab, this.contents[i]].each(function (el) { el.addEvent('mouseenter', this.handleMouseEnter.pass(i, this)); el.addEvent('mouseleave', this.handleMouseLeave.pass(i, this)) }, this)
    }, this); return this
}, handleMouseEnter: function (i) { $clear(this.closeDelay); if (i != this.seq) this.close(this.seq); this.openDelay = this.open.delay(100, this, i) }, handleMouseLeave: function (i) { $clear(this.openDelay); this.closeDelay = this.close.delay(250, this, i) }, position: function (i) { this.contents[i].position({ relativeTo: this.tabs[i], position: this.options.position, offset: this.options.offset }) }
});

  CNB.Rotocop = new Class({ Implements: [Options, Events], options: { itemsPerPage: 3, showPrevNext: true, prevNextClass: '', controlsClass: '', showPage: false, slide: true, startPage: 1, timer: null }, initialize: function (container, options) { this.setOptions(options); this.container = $(container); this.contents = this.container.getChildren(); this.itemCount = this.contents.length; this.pageCount = Math.ceil(this.itemCount / this.options.itemsPerPage); this.page = this.options.startPage; this.width = this.container.getSize().x; this.cover = new Element('div', { 'styles': { 'width': this.width, 'overflow': 'hidden', 'position': 'relative'} }); this.controls = new Element('div', { 'class': 'roto-controls ' + this.options.controlsClass }) }, load: function () { if (this.pageCount == 1) return false; this.fireEvent('load', this.contents); this.container.setStyle('width', '10000px'); this.cover.wraps(this.container); this.controls.inject(this.cover, 'after'); if (this.options.showPrevNext) this.buildPrevNextNav(); if (this.options.showPage) this.buildPageNav(); if (this.page != 1) this.rotate(this.page); if ($chk(this.options.timer)) this.setTimer(); return this }, setTimer: function () { var timer = this.next.periodical(this.options.timer, this); var btns = []; if (this.options.showPrevNext) btns.extend([this.prevBtn, this.nextBtn]); if (this.options.showPage) btns.extend(this.pageNav); btns.each(function (el) { el.addEvent('click', function () { $clear(timer) }) }) }, rotate: function (page) { var firstInPage = this.contents[this.options.itemsPerPage * (page - 1)]; var shift = firstInPage.getPosition(this.container).x; if (this.options.slide == true) { this.container.tween('margin-left', '-' + shift + 'px') } else { this.container.setStyle('margin-left', '-' + shift + 'px') } if (this.options.showPage) { this.pageNav[this.page - 1].removeClass('on'); this.pageNav[page - 1].addClass('on') } if (this.options.showPrevNext) { [this.prevBtn, this.nextBtn].each(function (el) { el.removeClass('disabled') }); switch (page) { case this.pageCount: this.nextBtn.addClass('disabled'); break; case 1: this.prevBtn.addClass('disabled'); break } } this.page = page }, buildPrevNextNav: function () { var prevNext = new Element('div', { 'class': 'prev-next ' + this.options.prevNextClass }); this.prevBtn = new Element('a', { 'class': 'btn prev disabled', 'html': 'Previous', 'events': { 'click': this.prev.bind(this)} }).inject(prevNext, 'bottom'); this.nextBtn = new Element('a', { 'class': 'btn next', 'html': 'Next', 'events': { 'click': this.next.bind(this)} }).inject(prevNext, 'bottom'); prevNext.inject(this.controls, 'bottom') }, buildPageNav: function () { this.pageNav = []; var container = new Element('ul', { 'class': 'roto-pagination clear' }); for (i = 0; i < this.pageCount; i++) { this.pageNav[i] = new Element('li', { 'html': '<a>' + (i + 1) + '</a>' }).inject(container, 'bottom') } this.pageNav[0].addClass('on'); this.pageNav.each(function (el, i) { el.addEvent('click', this.rotate.pass(i + 1, this)) }, this); container.inject(this.controls, 'bottom') }, prev: function () { var prevPage = (this.page == 1) ? this.pageCount : this.page - 1; this.rotate(prevPage); this.fireEvent('prev') }, next: function () { var nextPage = (this.page == this.pageCount) ? 1 : this.page + 1; this.rotate(nextPage); this.fireEvent('next') } }); CNB.TagsMore = new Class({ Implements: Options, options: { visibleCount: 10, textMore: 'more&nbsp;+', textLess: 'less&nbsp;+' }, initialize: function (containers, options) { this.setOptions(options); $splat(containers).each(function (el) { var tags = el.get('html').clean().split(','); if (tags.length > this.options.visibleCount) this.build(el, tags) }, this) }, build: function (container, tags) { var moreTags = tags.splice(this.options.visibleCount, tags.length - this.options.visibleCount); var moreCont = new Element('span', { 'class': 'tags-more', 'html': moreTags.join(', ') }); var moreBtn = new Element('a', { 'class': 'more', 'html': this.options.textMore }); moreBtn.addEvent('click', this.toggle.pass([moreCont, moreBtn], this)); var hold = new Element('div', { 'html': tags.join(', ') + ', ' }).adopt(moreCont).appendText(' ').adopt(moreBtn); container.empty().adopt(hold); this.hide(moreCont, moreBtn) }, toggle: function (moreCont, moreBtn) { if (moreCont.retrieve('isVisible')) { this.hide(moreCont, moreBtn) } else { this.show(moreCont, moreBtn) } }, show: function (moreCont, moreBtn) { moreCont.store('isVisible', true).setStyle('display', 'inline'); moreBtn.set('html', this.options.textLess) }, hide: function (moreCont, moreBtn) { moreCont.store('isVisible', false).setStyle('display', 'none'); moreBtn.set('html', this.options.textMore) } }); CNB.Expander = new Class({ Implements: [Options, Events], options: { content: null, action: 'click', hidden: 'true', btn: null, btnClass: '', btnText: { show: 'Show', hide: 'Hide'} }, initialize: function (container, options) { this.setOptions(options); this.container = $(container); if ($chk(this.options.btn)) { this.btn = $(this.options.btn) } else { var btnCont = new Element('div', { 'class': 'more ' + this.options.btnClass }); this.btn = new Element('a', { 'text': this.options.btnText.show }).inject(btnCont); btnCont.inject(this.container, 'after') } this.slide = new Fx.Slide(this.container, { 'mode': 'vertical' }).hide(); this.visible = false; this.btn.addEvent(this.options.action, this.toggle.bind(this)); if ($chk(this.options.btnText.show)) { this.addEvents({ 'show': this.setText.bind(this, this.options.btnText.hide), 'hide': this.setText.bind(this, this.options.btnText.show) }) } }, toggle: function () { if (this.visible) { this.hide() } else { this.show() } }, setText: function (t) { var text = ($chk(t)) ? t : (this.visible) ? this.options.btnText.hide : this.options.btnText.show; this.btn.set('html', text) }, show: function () { this.visible = true; this.slide.slideIn(); this.fireEvent('show', [this.container, this.btn]) }, hide: function () { this.visible = false; this.slide.slideOut(); this.fireEvent('hide', [this.container, this.btn]) } }); CNB.Placeholder = new Class({ initialize: function (inputs) { var placeholders = $splat(inputs); if (placeholders.length > 0) { this.set(placeholders) } }, addPlaceholder: function (el) { var placeholder = el.getProperty('placeholder'); if (!$chk(el.value) || (el.value == placeholder)) { el.addClass('placeholder'); el.value = placeholder } }, removePlaceholder: function (el) { if (el.hasClass('placeholder')) { el.value = ''; el.removeClass('placeholder') } }, set: function (inputs) { inputs.each(function (el) { try { el.store('placeholder', this); el.addEvents({ 'focus': this.removePlaceholder.pass(el), 'blur': this.addPlaceholder.pass(el) }); this.addPlaceholder(el) } catch (e) { CNB.log('placeholder error:', e) } }, this) } }); CNB.Validator = new Class({ Implements: [Options, Events], options: { onValidateSuccess: function (event, form) { }, onValidateFailure: function (event, form) { event.stop() }, validateOnBlur: true, scrollToErrors: false }, initialize: function (form, options) { this.setOptions(options); this.form = $(form); this.rules = { 'required': { 'type': 'field', 'msg': 'This field is required', 'test': function (el) { if (el.type == 'select-one' || el.type == 'select') { return (el.selectedIndex >= 0 && el.options[el.selectedIndex].value != '') } else { return ((el.get('value') != null) && (el.get('value').length != 0)) } } }, 'one-required': { 'type': 'group', 'msg': 'One of these fields is required', 'test': function (el) { var parent = el.getParent('.validate-group') || el.getParent(); return parent.getElements('input').some(function (el) { if (['checkbox', 'radio'].contains(el.get('type'))) return el.get('checked') }) } }, 'validate-minlength': { 'type': 'field', 'msg': function (el) { return 'This field must be at least ' + el.getProperty('minlength') + ' characters' }, 'test': function (el) { return (el.get('value').length >= el.getProperty('minlength')) } }, 'validate-maxlength': { 'type': 'field', 'msg': function (el) { return 'This field must be no more than least ' + el.getProperty('maxlength') + ' characters' }, 'test': function (el) { return (el.get('value').length <= el.getProperty('maxlength')) } }, 'validate-email': { 'type': 'field', 'msg': 'Please enter a valid email.', 'test': function (el) { return (el.get('value').test(/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i)) } }, 'validate-match': { 'type': 'field', 'msg': function (el) { return '' }, 'test': function (el) { return true } }, 'validate-specialchars': { 'type': 'field', 'msg': 'Special characters are not allowed in this field', 'test': function (el) { return !(el.get('value').test(/[%;]/)) } }, 'validate-zipdcode-us': { 'type': 'field', 'msg': 'Invalid Postal Code', 'test': function (el) { return el.get('value').test(/^[0-9]+$/) } } }; this.errors = new Hash(); this.errorsGlobal = []; this.form.store('validator', this); this.form.addEvent('submit', this.validateFields.bind(this)); if (this.options.validateOnBlur) { this.getFields(true).each(function (el) { el.addEvent('blur', this.removeError.pass(el, this)); el.addEvent('blur', this.testField.bindWithEvent(this, el)) }, this) } }, getRule: function (name) { if (typeof this.rules[name] != 'undefined') { return this.rules[name] } else { return false } }, addRules: function (rules) { $each(rules, function (v, k) { this.rules[k] = v }, this) }, getFields: function (excludeToggles) { return this.form.getElements('input, select, textarea').filter(function (el) { if (el.disabled || el.type == 'submit' || el.type == 'reset' && el.type == 'file') { return false } if (excludeToggles) { if (el.type == 'checkbox' || el.type == 'radio') { return false } } return true }, this) }, testField: function (event, el) { el.className.split(' ').each(function (cl) { var rule = this.getRule(cl); if (rule !== false) { if (event.type == 'blur' && rule.type == 'group') return; if (!rule.test(el)) { var msg = (typeof rule.msg == 'function') ? rule.msg(el) : rule.msg; this.addError(el, msg, rule.type) } } }, this) }, validateFields: function (event) { this.errors.each(this.removeError, this); this.errorsGlobal.each(function (el) { el.destroy() }); this.getFields().each(function (el) { this.testField(event, el) }, this); if (this.errors.getLength() == 0) { this.fireEvent('validateSuccess', [event, this.form]) } else { this.fireEvent('validateFailure', [event, this.form]); if (this.options.scrollToErrors) { this.scrollToErrors() } } }, scrollToErrors: function () { var i = 0; this.errors.each(function (el, name) { if (i == 0) { var scroll = new Fx.Scroll(window).toElement(el.getParent()) } i++ }, this) }, removeError: function (el) { var error = el.retrieve('error'); if (error == null) return; error.container.destroy(); el.removeClass('error-input').eliminate('error'); this.errors.erase(el.getProperty('name')) }, addError: function (el, msg, type) { if (el.retrieve('error') != null) return; var cont; if (type == 'group') { var parent = el.getParent('.validate-group') || el.getParent(); cont = new Element('div', { 'class': 'error-lvl', 'html': msg }).inject(parent, 'top') } else { el.addClass('error-input'); cont = new Element('div', { 'class': 'error', 'html': msg }).inject(el, 'after') } el.store('error', { 'type': 'group', 'container': cont }); this.errors.set(el.getProperty('name'), el) }, addGlobalError: function (msg) { var cont = new Element('div', { 'class': 'error-lvl', 'html': msg }).inject(this.form, 'top'); this.errorsGlobal.push(cont) } }); window.addEvent('domready', function () { var placeholders = new CNB.Placeholder($$('input[placeholder]')); $(document.body).addEvent('click:relay(a)', function (e, el) { var href = el.getProperty('href'); if (href === null) return false; if (href.trim().indexOf('#') === 0) { e.stop(); CNB.scrollTo(href.substr(1)) } }) });
