var BrowserDetect = {
init: function () {
this.browser = this.searchString(this.dataBrowser) || "An unknown browser";
this.version = this.searchVersion(navigator.userAgent)
|| this.searchVersion(navigator.appVersion)
|| "an unknown version";
this.OS = this.searchString(this.dataOS) || "an unknown OS";
},
searchString: function (data) {
for (var i=0;i<data.length;i++)	{
var dataString = data[i].string;
var dataProp = data[i].prop;
this.versionSearchString = data[i].versionSearch || data[i].identity;
if (dataString) {
if (dataString.indexOf(data[i].subString) != -1)
return data[i].identity;
}
else if (dataProp)
return data[i].identity;
}
},
searchVersion: function (dataString) {
var index = dataString.indexOf(this.versionSearchString);
if (index == -1) return;
return parseFloat(dataString.substring(index+this.versionSearchString.length+1));
},
dataBrowser: [
{
string: navigator.userAgent,
subString: "Chrome",
identity: "Chrome"
},
{ 	string: navigator.userAgent,
subString: "OmniWeb",
versionSearch: "OmniWeb/",
identity: "OmniWeb"
},
{
string: navigator.vendor,
subString: "Apple",
identity: "Safari"
},
{
prop: window.opera,
identity: "Opera"
},
{
string: navigator.vendor,
subString: "iCab",
identity: "iCab"
},
{
string: navigator.vendor,
subString: "KDE",
identity: "Konqueror"
},
{
string: navigator.userAgent,
subString: "Firefox",
identity: "Firefox"
},
{
string: navigator.vendor,
subString: "Camino",
identity: "Camino"
},
{		// for newer Netscapes (6+)
string: navigator.userAgent,
subString: "Netscape",
identity: "Netscape"
},
{
string: navigator.userAgent,
subString: "MSIE",
identity: "Explorer",
versionSearch: "MSIE"
},
{
string: navigator.userAgent,
subString: "Gecko",
identity: "Mozilla",
versionSearch: "rv"
},
{ 		// for older Netscapes (4-)
string: navigator.userAgent,
subString: "Mozilla",
identity: "Netscape",
versionSearch: "Mozilla"
}
],
dataOS : [
{
string: navigator.platform,
subString: "Win",
identity: "Windows"
},
{
string: navigator.platform,
subString: "Mac",
identity: "Mac"
},
{
string: navigator.platform,
subString: "Linux",
identity: "Linux"
}
]
};
/*  Prototype JavaScript framework, version 1.5.0
*  (c) 2005-2007 Sam Stephenson
*
*  Prototype is freely distributable under the terms of an MIT-style license.
*  For details, see the Prototype web site: http://prototype.conio.net/
*
/*--------------------------------------------------------------------------*/
var Prototype = {
Version: '1.5.0',
BrowserFeatures: {
XPath: !!document.evaluate
},
ScriptFragment: '(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)',
emptyFunction: function() {},
K: function(x) { return x }
}
var Class = {
create: function() {
return function() {
this.initialize.apply(this, arguments);
}
}
}
var Abstract = new Object();
Object.extend = function(destination, source) {
for (var property in source) {
destination[property] = source[property];
}
return destination;
}
Object.extend(Object, {
inspect: function(object) {
try {
if (object === undefined) return 'undefined';
if (object === null) return 'null';
return object.inspect ? object.inspect() : object.toString();
} catch (e) {
if (e instanceof RangeError) return '...';
throw e;
}
},
keys: function(object) {
var keys = [];
for (var property in object)
keys.push(property);
return keys;
},
values: function(object) {
var values = [];
for (var property in object)
values.push(object[property]);
return values;
},
clone: function(object) {
return Object.extend({}, object);
}
});
Function.prototype.bind = function() {
var __method = this, args = $A(arguments), object = args.shift();
return function() {
return __method.apply(object, args.concat($A(arguments)));
}
}
Function.prototype.bindAsEventListener = function(object) {
var __method = this, args = $A(arguments), object = args.shift();
return function(event) {
return __method.apply(object, [( event || window.event)].concat(args).concat($A(arguments)));
}
}
Object.extend(Number.prototype, {
toColorPart: function() {
var digits = this.toString(16);
if (this < 16) return '0' + digits;
return digits;
},
succ: function() {
return this + 1;
},
times: function(iterator) {
$R(0, this, true).each(iterator);
return this;
}
});
var Try = {
these: function() {
var returnValue;
for (var i = 0, length = arguments.length; i < length; i++) {
var lambda = arguments[i];
try {
returnValue = lambda();
break;
} catch (e) {}
}
return returnValue;
}
}
/*--------------------------------------------------------------------------*/
var PeriodicalExecuter = Class.create();
PeriodicalExecuter.prototype = {
initialize: function(callback, frequency) {
this.callback = callback;
this.frequency = frequency;
this.currentlyExecuting = false;
this.registerCallback();
},
registerCallback: function() {
this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
},
stop: function() {
if (!this.timer) return;
clearInterval(this.timer);
this.timer = null;
},
onTimerEvent: function() {
if (!this.currentlyExecuting) {
try {
this.currentlyExecuting = true;
this.callback(this);
} finally {
this.currentlyExecuting = false;
}
}
}
}
String.interpret = function(value){
return value == null ? '' : String(value);
}
Object.extend(String.prototype, {
gsub: function(pattern, replacement) {
var result = '', source = this, match;
replacement = arguments.callee.prepareReplacement(replacement);
while (source.length > 0) {
if (match = source.match(pattern)) {
result += source.slice(0, match.index);
result += String.interpret(replacement(match));
source  = source.slice(match.index + match[0].length);
} else {
result += source, source = '';
}
}
return result;
},
sub: function(pattern, replacement, count) {
replacement = this.gsub.prepareReplacement(replacement);
count = count === undefined ? 1 : count;
return this.gsub(pattern, function(match) {
if (--count < 0) return match[0];
return replacement(match);
});
},
scan: function(pattern, iterator) {
this.gsub(pattern, iterator);
return this;
},
truncate: function(length, truncation) {
length = length || 30;
truncation = truncation === undefined ? '...' : truncation;
return this.length > length ?
this.slice(0, length - truncation.length) + truncation : this;
},
strip: function() {
return this.replace(/^\s+/, '').replace(/\s+$/, '');
},
stripTags: function() {
return this.replace(/<\/?[^>]+>/gi, '');
},
stripScripts: function() {
return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
},
extractScripts: function() {
var matchAll = new RegExp(Prototype.ScriptFragment, 'img');
var matchOne = new RegExp(Prototype.ScriptFragment, 'im');
return (this.match(matchAll) || []).map(function(scriptTag) {
return (scriptTag.match(matchOne) || ['', ''])[1];
});
},
evalScripts: function() {
return this.extractScripts().map(function(script) { return eval(script) });
},
escapeHTML: function() {
var div = document.createElement('div');
var text = document.createTextNode(this);
div.appendChild(text);
return div.innerHTML;
},
unescapeHTML: function() {
var div = document.createElement('div');
div.innerHTML = this.stripTags();
return div.childNodes[0] ? (div.childNodes.length > 1 ?
$A(div.childNodes).inject('',function(memo,node){ return memo+node.nodeValue }) :
div.childNodes[0].nodeValue) : '';
},
toQueryParams: function(separator) {
var match = this.strip().match(/([^?#]*)(#.*)?$/);
if (!match) return {};
return match[1].split(separator || '&').inject({}, function(hash, pair) {
if ((pair = pair.split('='))[0]) {
var name = decodeURIComponent(pair[0]);
var value = pair[1] ? decodeURIComponent(pair[1]) : undefined;
if (hash[name] !== undefined) {
if (hash[name].constructor != Array)
hash[name] = [hash[name]];
if (value) hash[name].push(value);
}
else hash[name] = value;
}
return hash;
});
},
toArray: function() {
return this.split('');
},
succ: function() {
return this.slice(0, this.length - 1) +
String.fromCharCode(this.charCodeAt(this.length - 1) + 1);
},
camelize: function() {
var parts = this.split('-'), len = parts.length;
if (len == 1) return parts[0];
var camelized = this.charAt(0) == '-'
? parts[0].charAt(0).toUpperCase() + parts[0].substring(1)
: parts[0];
for (var i = 1; i < len; i++)
camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);
return camelized;
},
capitalize: function(){
return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
},
underscore: function() {
return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase();
},
dasherize: function() {
return this.gsub(/_/,'-');
},
inspect: function(useDoubleQuotes) {
var escapedString = this.replace(/\\/g, '\\\\');
if (useDoubleQuotes)
return '"' + escapedString.replace(/"/g, '\\"') + '"';
else
return "'" + escapedString.replace(/'/g, '\\\'') + "'";
}
});
String.prototype.gsub.prepareReplacement = function(replacement) {
if (typeof replacement == 'function') return replacement;
var template = new Template(replacement);
return function(match) { return template.evaluate(match) };
}
String.prototype.parseQuery = String.prototype.toQueryParams;
var Template = Class.create();
Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
Template.prototype = {
initialize: function(template, pattern) {
this.template = template.toString();
this.pattern  = pattern || Template.Pattern;
},
evaluate: function(object) {
return this.template.gsub(this.pattern, function(match) {
var before = match[1];
if (before == '\\') return match[2];
return before + String.interpret(object[match[3]]);
});
}
}
var $break    = new Object();
var $continue = new Object();
var Enumerable = {
each: function(iterator) {
var index = 0;
try {
this._each(function(value) {
try {
iterator(value, index++);
} catch (e) {
if (e != $continue) throw e;
}
});
} catch (e) {
if (e != $break) throw e;
}
return this;
},
eachSlice: function(number, iterator) {
var index = -number, slices = [], array = this.toArray();
while ((index += number) < array.length)
slices.push(array.slice(index, index+number));
return slices.map(iterator);
},
all: function(iterator) {
var result = true;
this.each(function(value, index) {
result = result && !!(iterator || Prototype.K)(value, index);
if (!result) throw $break;
});
return result;
},
any: function(iterator) {
var result = false;
this.each(function(value, index) {
if (result = !!(iterator || Prototype.K)(value, index))
throw $break;
});
return result;
},
collect: function(iterator) {
var results = [];
this.each(function(value, index) {
results.push((iterator || Prototype.K)(value, index));
});
return results;
},
detect: function(iterator) {
var result;
this.each(function(value, index) {
if (iterator(value, index)) {
result = value;
throw $break;
}
});
return result;
},
findAll: function(iterator) {
var results = [];
this.each(function(value, index) {
if (iterator(value, index))
results.push(value);
});
return results;
},
grep: function(pattern, iterator) {
var results = [];
this.each(function(value, index) {
var stringValue = value.toString();
if (stringValue.match(pattern))
results.push((iterator || Prototype.K)(value, index));
})
return results;
},
include: function(object) {
var found = false;
this.each(function(value) {
if (value == object) {
found = true;
throw $break;
}
});
return found;
},
inGroupsOf: function(number, fillWith) {
fillWith = fillWith === undefined ? null : fillWith;
return this.eachSlice(number, function(slice) {
while(slice.length < number) slice.push(fillWith);
return slice;
});
},
inject: function(memo, iterator) {
this.each(function(value, index) {
memo = iterator(memo, value, index);
});
return memo;
},
invoke: function(method) {
var args = $A(arguments).slice(1);
return this.map(function(value) {
return value[method].apply(value, args);
});
},
max: function(iterator) {
var result;
this.each(function(value, index) {
value = (iterator || Prototype.K)(value, index);
if (result == undefined || value >= result)
result = value;
});
return result;
},
min: function(iterator) {
var result;
this.each(function(value, index) {
value = (iterator || Prototype.K)(value, index);
if (result == undefined || value < result)
result = value;
});
return result;
},
partition: function(iterator) {
var trues = [], falses = [];
this.each(function(value, index) {
((iterator || Prototype.K)(value, index) ?
trues : falses).push(value);
});
return [trues, falses];
},
pluck: function(property) {
var results = [];
this.each(function(value, index) {
results.push(value[property]);
});
return results;
},
reject: function(iterator) {
var results = [];
this.each(function(value, index) {
if (!iterator(value, index))
results.push(value);
});
return results;
},
sortBy: function(iterator) {
return this.map(function(value, index) {
return {value: value, criteria: iterator(value, index)};
}).sort(function(left, right) {
var a = left.criteria, b = right.criteria;
return a < b ? -1 : a > b ? 1 : 0;
}).pluck('value');
},
toArray: function() {
return this.map();
},
zip: function() {
var iterator = Prototype.K, args = $A(arguments);
if (typeof args.last() == 'function')
iterator = args.pop();
var collections = [this].concat(args).map($A);
return this.map(function(value, index) {
return iterator(collections.pluck(index));
});
},
size: function() {
return this.toArray().length;
},
inspect: function() {
return '#<Enumerable:' + this.toArray().inspect() + '>';
}
}
Object.extend(Enumerable, {
map:     Enumerable.collect,
find:    Enumerable.detect,
select:  Enumerable.findAll,
member:  Enumerable.include,
entries: Enumerable.toArray
});
var $A = Array.from = function(iterable) {
if (!iterable) return [];
if (iterable.toArray) {
return iterable.toArray();
} else {
var results = [];
for (var i = 0, length = iterable.length; i < length; i++)
results.push(iterable[i]);
return results;
}
}
Object.extend(Array.prototype, Enumerable);
if (!Array.prototype._reverse)
Array.prototype._reverse = Array.prototype.reverse;
Object.extend(Array.prototype, {
_each: function(iterator) {
for (var i = 0, length = this.length; i < length; i++)
iterator(this[i]);
},
clear: function() {
this.length = 0;
return this;
},
first: function() {
return this[0];
},
last: function() {
return this[this.length - 1];
},
compact: function() {
return this.select(function(value) {
return value != null;
});
},
flatten: function() {
return this.inject([], function(array, value) {
return array.concat(value && value.constructor == Array ?
value.flatten() : [value]);
});
},
without: function() {
var values = $A(arguments);
return this.select(function(value) {
return !values.include(value);
});
},
indexOf: function(object) {
for (var i = 0, length = this.length; i < length; i++)
if (this[i] == object) return i;
return -1;
},
reverse: function(inline) {
return (inline !== false ? this : this.toArray())._reverse();
},
reduce: function() {
return this.length > 1 ? this : this[0];
},
uniq: function() {
return this.inject([], function(array, value) {
return array.include(value) ? array : array.concat([value]);
});
},
clone: function() {
return [].concat(this);
},
size: function() {
return this.length;
},
inspect: function() {
return '[' + this.map(Object.inspect).join(', ') + ']';
}
});
Array.prototype.toArray = Array.prototype.clone;
function $w(string){
string = string.strip();
return string ? string.split(/\s+/) : [];
}
if(window.opera){
Array.prototype.concat = function(){
var array = [];
for(var i = 0, length = this.length; i < length; i++) array.push(this[i]);
for(var i = 0, length = arguments.length; i < length; i++) {
if(arguments[i].constructor == Array) {
for(var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++)
array.push(arguments[i][j]);
} else {
array.push(arguments[i]);
}
}
return array;
}
}
var Hash = function(obj) {
Object.extend(this, obj || {});
};
Object.extend(Hash, {
toQueryString: function(obj) {
var parts = [];
this.prototype._each.call(obj, function(pair) {
if (!pair.key) return;
if (pair.value && pair.value.constructor == Array) {
var values = pair.value.compact();
if (values.length < 2) pair.value = values.reduce();
else {
key = encodeURIComponent(pair.key);
values.each(function(value) {
value = value != undefined ? encodeURIComponent(value) : '';
parts.push(key + '=' + encodeURIComponent(value));
});
return;
}
}
if (pair.value == undefined) pair[1] = '';
parts.push(pair.map(encodeURIComponent).join('='));
});
return parts.join('&');
}
});
Object.extend(Hash.prototype, Enumerable);
Object.extend(Hash.prototype, {
_each: function(iterator) {
for (var key in this) {
var value = this[key];
if (value && value == Hash.prototype[key]) continue;
var pair = [key, value];
pair.key = key;
pair.value = value;
iterator(pair);
}
},
keys: function() {
return this.pluck('key');
},
values: function() {
return this.pluck('value');
},
merge: function(hash) {
return $H(hash).inject(this, function(mergedHash, pair) {
mergedHash[pair.key] = pair.value;
return mergedHash;
});
},
remove: function() {
var result;
for(var i = 0, length = arguments.length; i < length; i++) {
var value = this[arguments[i]];
if (value !== undefined){
if (result === undefined) result = value;
else {
if (result.constructor != Array) result = [result];
result.push(value)
}
}
delete this[arguments[i]];
}
return result;
},
toQueryString: function() {
return Hash.toQueryString(this);
},
inspect: function() {
return '#<Hash:{' + this.map(function(pair) {
return pair.map(Object.inspect).join(': ');
}).join(', ') + '}>';
}
});
function $H(object) {
if (object && object.constructor == Hash) return object;
return new Hash(object);
};
ObjectRange = Class.create();
Object.extend(ObjectRange.prototype, Enumerable);
Object.extend(ObjectRange.prototype, {
initialize: function(start, end, exclusive) {
this.start = start;
this.end = end;
this.exclusive = exclusive;
},
_each: function(iterator) {
var value = this.start;
while (this.include(value)) {
iterator(value);
value = value.succ();
}
},
include: function(value) {
if (value < this.start)
return false;
if (this.exclusive)
return value < this.end;
return value <= this.end;
}
});
var $R = function(start, end, exclusive) {
return new ObjectRange(start, end, exclusive);
}
var Ajax = {
getTransport: function() {
return Try.these(
function() {return new XMLHttpRequest()},
function() {return new ActiveXObject('Msxml2.XMLHTTP')},
function() {return new ActiveXObject('Microsoft.XMLHTTP')}
) || false;
},
activeRequestCount: 0
}
Ajax.Responders = {
responders: [],
_each: function(iterator) {
this.responders._each(iterator);
},
register: function(responder) {
if (!this.include(responder))
this.responders.push(responder);
},
unregister: function(responder) {
this.responders = this.responders.without(responder);
},
dispatch: function(callback, request, transport, json) {
this.each(function(responder) {
if (typeof responder[callback] == 'function') {
try {
responder[callback].apply(responder, [request, transport, json]);
} catch (e) {}
}
});
}
};
Object.extend(Ajax.Responders, Enumerable);
Ajax.Responders.register({
onCreate: function() {
Ajax.activeRequestCount++;
},
onComplete: function() {
Ajax.activeRequestCount--;
}
});
Ajax.Base = function() {};
Ajax.Base.prototype = {
setOptions: function(options) {
this.options = {
method:       'post',
asynchronous: true,
contentType:  'application/x-www-form-urlencoded',
encoding:     'UTF-8',
parameters:   ''
}
Object.extend(this.options, options || {});
this.options.method = this.options.method.toLowerCase();
if (typeof this.options.parameters == 'string')
this.options.parameters = this.options.parameters.toQueryParams();
}
}
Ajax.Request = Class.create();
Ajax.Request.Events =
['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
_complete: false,
initialize: function(url, options) {
this.transport = Ajax.getTransport();
this.setOptions(options);
this.request(url);
},
request: function(url) {
this.url = url;
this.method = this.options.method;
var params = this.options.parameters;
if (!['get', 'post'].include(this.method)) {
// simulate other verbs over post
params['_method'] = this.method;
this.method = 'post';
}
params = Hash.toQueryString(params);
if (params && /Konqueror|Safari|KHTML/.test(navigator.userAgent)) params += '&_='
// when GET, append parameters to URL
if (this.method == 'get' && params)
this.url += (this.url.indexOf('?') > -1 ? '&' : '?') + params;
try {
Ajax.Responders.dispatch('onCreate', this, this.transport);
this.transport.open(this.method.toUpperCase(), this.url,
this.options.asynchronous);
if (this.options.asynchronous)
setTimeout(function() { this.respondToReadyState(1) }.bind(this), 10);
this.transport.onreadystatechange = this.onStateChange.bind(this);
this.setRequestHeaders();
var body = this.method == 'post' ? (this.options.postBody || params) : null;
this.transport.send(body);
/* Force Firefox to handle ready state 4 for synchronous requests */
if (!this.options.asynchronous && this.transport.overrideMimeType)
this.onStateChange();
}
catch (e) {
this.dispatchException(e);
}
},
onStateChange: function() {
var readyState = this.transport.readyState;
if (readyState > 1 && !((readyState == 4) && this._complete))
this.respondToReadyState(this.transport.readyState);
},
setRequestHeaders: function() {
var headers = {
'X-Requested-With': 'XMLHttpRequest',
'X-Prototype-Version': Prototype.Version,
'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
};
if (this.method == 'post') {
headers['Content-type'] = this.options.contentType +
(this.options.encoding ? '; charset=' + this.options.encoding : '');
/* Force "Connection: close" for older Mozilla browsers to work
* around a bug where XMLHttpRequest sends an incorrect
* Content-length header. See Mozilla Bugzilla #246651.
*/
if (this.transport.overrideMimeType &&
(navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005)
headers['Connection'] = 'close';
}
// user-defined headers
if (typeof this.options.requestHeaders == 'object') {
var extras = this.options.requestHeaders;
if (typeof extras.push == 'function')
for (var i = 0, length = extras.length; i < length; i += 2)
headers[extras[i]] = extras[i+1];
else
$H(extras).each(function(pair) { headers[pair.key] = pair.value });
}
for (var name in headers)
this.transport.setRequestHeader(name, headers[name]);
},
success: function() {
return !this.transport.status
|| (this.transport.status >= 200 && this.transport.status < 300);
},
respondToReadyState: function(readyState) {
var state = Ajax.Request.Events[readyState];
var transport = this.transport, json = this.evalJSON();
if (state == 'Complete') {
try {
this._complete = true;
(this.options['on' + this.transport.status]
|| this.options['on' + (this.success() ? 'Success' : 'Failure')]
|| Prototype.emptyFunction)(transport, json);
} catch (e) {
this.dispatchException(e);
}
if ((this.getHeader('Content-type') || 'text/javascript').strip().
match(/^(text|application)\/(x-)?(java|ecma)script(;.*)?$/i))
this.evalResponse();
}
try {
(this.options['on' + state] || Prototype.emptyFunction)(transport, json);
Ajax.Responders.dispatch('on' + state, this, transport, json);
} catch (e) {
this.dispatchException(e);
}
if (state == 'Complete') {
// avoid memory leak in MSIE: clean up
this.transport.onreadystatechange = Prototype.emptyFunction;
}
},
getHeader: function(name) {
try {
return this.transport.getResponseHeader(name);
} catch (e) { return null }
},
evalJSON: function() {
try {
var json = this.getHeader('X-JSON');
return json ? eval('(' + json + ')') : null;
} catch (e) { return null }
},
evalResponse: function() {
try {
return eval(this.transport.responseText);
} catch (e) {
this.dispatchException(e);
}
},
dispatchException: function(exception) {
(this.options.onException || Prototype.emptyFunction)(this, exception);
Ajax.Responders.dispatch('onException', this, exception);
}
});
Ajax.Updater = Class.create();
Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {
initialize: function(container, url, options) {
this.container = {
success: (container.success || container),
failure: (container.failure || (container.success ? null : container))
}
this.transport = Ajax.getTransport();
this.setOptions(options);
var onComplete = this.options.onComplete || Prototype.emptyFunction;
this.options.onComplete = (function(transport, param) {
this.updateContent();
onComplete(transport, param);
}).bind(this);
this.request(url);
},
updateContent: function() {
var receiver = this.container[this.success() ? 'success' : 'failure'];
var response = this.transport.responseText;
if (!this.options.evalScripts) response = response.stripScripts();
if (receiver = $(receiver)) {
if (this.options.insertion)
new this.options.insertion(receiver, response);
else
receiver.update(response);
}
if (this.success()) {
if (this.onComplete)
setTimeout(this.onComplete.bind(this), 10);
}
}
});
Ajax.PeriodicalUpdater = Class.create();
Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), {
initialize: function(container, url, options) {
this.setOptions(options);
this.onComplete = this.options.onComplete;
this.frequency = (this.options.frequency || 2);
this.decay = (this.options.decay || 1);
this.updater = {};
this.container = container;
this.url = url;
this.start();
},
start: function() {
this.options.onComplete = this.updateComplete.bind(this);
this.onTimerEvent();
},
stop: function() {
this.updater.options.onComplete = undefined;
clearTimeout(this.timer);
(this.onComplete || Prototype.emptyFunction).apply(this, arguments);
},
updateComplete: function(request) {
if (this.options.decay) {
this.decay = (request.responseText == this.lastText ?
this.decay * this.options.decay : 1);
this.lastText = request.responseText;
}
this.timer = setTimeout(this.onTimerEvent.bind(this),
this.decay * this.frequency * 1000);
},
onTimerEvent: function() {
this.updater = new Ajax.Updater(this.container, this.url, this.options);
}
});
function $(element) {
if (arguments.length > 1) {
for (var i = 0, elements = [], length = arguments.length; i < length; i++)
elements.push($(arguments[i]));
return elements;
}
if (typeof element == 'string')
element = document.getElementById(element);
return Element.extend(element);
}
if (Prototype.BrowserFeatures.XPath) {
document._getElementsByXPath = function(expression, parentElement) {
var results = [];
var query = document.evaluate(expression, $(parentElement) || document,
null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
for (var i = 0, length = query.snapshotLength; i < length; i++)
results.push(query.snapshotItem(i));
return results;
};
}
document.getElementsByClassName = function(className, parentElement) {
if (Prototype.BrowserFeatures.XPath) {
var q = ".//*[contains(concat(' ', @class, ' '), ' " + className + " ')]";
return document._getElementsByXPath(q, parentElement);
} else {
var children = ($(parentElement) || document.body).getElementsByTagName('*');
var elements = [], child;
for (var i = 0, length = children.length; i < length; i++) {
child = children[i];
if (Element.hasClassName(child, className))
elements.push(Element.extend(child));
}
return elements;
}
};
/*--------------------------------------------------------------------------*/
if (!window.Element)
var Element = new Object();
Element.extend = function(element) {
if (!element || _nativeExtensions || element.nodeType == 3) return element;
if (!element._extended && element.tagName && element != window) {
var methods = Object.clone(Element.Methods), cache = Element.extend.cache;
if (element.tagName == 'FORM')
Object.extend(methods, Form.Methods);
if (['INPUT', 'TEXTAREA', 'SELECT'].include(element.tagName))
Object.extend(methods, Form.Element.Methods);
Object.extend(methods, Element.Methods.Simulated);
for (var property in methods) {
var value = methods[property];
if (typeof value == 'function' && !(property in element))
element[property] = cache.findOrStore(value);
}
}
element._extended = true;
return element;
};
Element.extend.cache = {
findOrStore: function(value) {
return this[value] = this[value] || function() {
return value.apply(null, [this].concat($A(arguments)));
}
}
};
Element.Methods = {
visible: function(element) {
return $(element).style.display != 'none';
},
toggle: function(element) {
element = $(element);
Element[Element.visible(element) ? 'hide' : 'show'](element);
return element;
},
hide: function(element) {
$(element).style.display = 'none';
return element;
},
show: function(element) {
if(element.style) {
$(element).style.display = '';
}
return element;
},
remove: function(element) {
element = $(element);
element.parentNode.removeChild(element);
return element;
},
update: function(element, html) {
html = typeof html == 'undefined' ? '' : html.toString();
$(element).innerHTML = html.stripScripts();
setTimeout(function() {html.evalScripts()}, 10);
return element;
},
replace: function(element, html) {
element = $(element);
html = typeof html == 'undefined' ? '' : html.toString();
if (element.outerHTML) {
element.outerHTML = html.stripScripts();
} else {
var range = element.ownerDocument.createRange();
range.selectNodeContents(element);
element.parentNode.replaceChild(
range.createContextualFragment(html.stripScripts()), element);
}
setTimeout(function() {html.evalScripts()}, 10);
return element;
},
inspect: function(element) {
element = $(element);
var result = '<' + element.tagName.toLowerCase();
$H({'id': 'id', 'className': 'class'}).each(function(pair) {
var property = pair.first(), attribute = pair.last();
var value = (element[property] || '').toString();
if (value) result += ' ' + attribute + '=' + value.inspect(true);
});
return result + '>';
},
recursivelyCollect: function(element, property) {
element = $(element);
var elements = [];
while (element = element[property])
if (element.nodeType == 1)
elements.push(Element.extend(element));
return elements;
},
ancestors: function(element) {
return $(element).recursivelyCollect('parentNode');
},
descendants: function(element) {
return $A($(element).getElementsByTagName('*'));
},
immediateDescendants: function(element) {
if (!(element = $(element).firstChild)) return [];
while (element && element.nodeType != 1) element = element.nextSibling;
if (element) return [element].concat($(element).nextSiblings());
return [];
},
previousSiblings: function(element) {
return $(element).recursivelyCollect('previousSibling');
},
nextSiblings: function(element) {
return $(element).recursivelyCollect('nextSibling');
},
siblings: function(element) {
element = $(element);
return element.previousSiblings().reverse().concat(element.nextSiblings());
},
match: function(element, selector) {
if (typeof selector == 'string')
selector = new Selector(selector);
return selector.match($(element));
},
up: function(element, expression, index) {
return Selector.findElement($(element).ancestors(), expression, index);
},
down: function(element, expression, index) {
return Selector.findElement($(element).descendants(), expression, index);
},
previous: function(element, expression, index) {
return Selector.findElement($(element).previousSiblings(), expression, index);
},
next: function(element, expression, index) {
return Selector.findElement($(element).nextSiblings(), expression, index);
},
getElementsBySelector: function() {
var args = $A(arguments), element = $(args.shift());
return Selector.findChildElements(element, args);
},
getElementsByClassName: function(element, className) {
return document.getElementsByClassName(className, element);
},
readAttribute: function(element, name) {
element = $(element);
if (document.all && !window.opera) {
var t = Element._attributeTranslations;
if (t.values[name]) return t.values[name](element, name);
if (t.names[name])  name = t.names[name];
var attribute = element.attributes[name];
if(attribute) return attribute.nodeValue;
}
return element.getAttribute(name);
},
getHeight: function(element) {
return $(element).getDimensions().height;
},
getWidth: function(element) {
return $(element).getDimensions().width;
},
classNames: function(element) {
return new Element.ClassNames(element);
},
hasClassName: function(element, className) {
if (!(element = $(element))) return;
var elementClassName = element.className;
if (elementClassName.length == 0) return false;
if (elementClassName == className ||
elementClassName.match(new RegExp("(^|\\s)" + className + "(\\s|$)")))
return true;
return false;
},
addClassName: function(element, className) {
if (!(element = $(element))) return;
Element.classNames(element).add(className);
return element;
},
removeClassName: function(element, className) {
if (!(element = $(element))) return;
Element.classNames(element).remove(className);
return element;
},
toggleClassName: function(element, className) {
if (!(element = $(element))) return;
Element.classNames(element)[element.hasClassName(className) ? 'remove' : 'add'](className);
return element;
},
observe: function() {
Event.observe.apply(Event, arguments);
return $A(arguments).first();
},
stopObserving: function() {
Event.stopObserving.apply(Event, arguments);
return $A(arguments).first();
},
// removes whitespace-only text node children
cleanWhitespace: function(element) {
element = $(element);
var node = element.firstChild;
while (node) {
var nextNode = node.nextSibling;
if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
element.removeChild(node);
node = nextNode;
}
return element;
},
empty: function(element) {
return $(element).innerHTML.match(/^\s*$/);
},
descendantOf: function(element, ancestor) {
element = $(element), ancestor = $(ancestor);
while (element = element.parentNode)
if (element == ancestor) return true;
return false;
},
scrollTo: function(element) {
element = $(element);
var pos = Position.cumulativeOffset(element);
window.scrollTo(pos[0], pos[1]);
return element;
},
getStyle: function(element, style) {
element = $(element);
if (['float','cssFloat'].include(style))
style = (typeof element.style.styleFloat != 'undefined' ? 'styleFloat' : 'cssFloat');
style = style.camelize();
var value = element.style[style];
if (!value) {
if (document.defaultView && document.defaultView.getComputedStyle) {
var css = document.defaultView.getComputedStyle(element, null);
value = css ? css[style] : null;
} else if (element.currentStyle) {
value = element.currentStyle[style];
}
}
if((value == 'auto') && ['width','height'].include(style) && (element.getStyle('display') != 'none'))
value = element['offset'+style.capitalize()] + 'px';
if (window.opera && ['left', 'top', 'right', 'bottom'].include(style))
if (Element.getStyle(element, 'position') == 'static') value = 'auto';
if(style == 'opacity') {
if(value) return parseFloat(value);
if(value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/))
if(value[1]) return parseFloat(value[1]) / 100;
return 1.0;
}
return value == 'auto' ? null : value;
},
setStyle: function(element, style) {
element = $(element);
for (var name in style) {
var value = style[name];
if(name == 'opacity') {
if (value == 1) {
value = (/Gecko/.test(navigator.userAgent) &&
!/Konqueror|Safari|KHTML/.test(navigator.userAgent)) ? 0.999999 : 1.0;
if(/MSIE/.test(navigator.userAgent) && !window.opera)
element.style.filter = element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,'');
} else if(value == '') {
if(/MSIE/.test(navigator.userAgent) && !window.opera)
element.style.filter = element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,'');
} else {
if(value < 0.00001) value = 0;
if(/MSIE/.test(navigator.userAgent) && !window.opera)
element.style.filter = element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,'') +
'alpha(opacity='+value*100+')';
}
} else if(['float','cssFloat'].include(name)) name = (typeof element.style.styleFloat != 'undefined') ? 'styleFloat' : 'cssFloat';
element.style[name.camelize()] = value;
}
return element;
},
getDimensions: function(element) {
element = $(element);
var display = $(element).getStyle('display');
if (display != 'none' && display != null) // Safari bug
return {width: element.offsetWidth, height: element.offsetHeight};
// All *Width and *Height properties give 0 on elements with display none,
// so enable the element temporarily
var els = element.style;
var originalVisibility = els.visibility;
var originalPosition = els.position;
var originalDisplay = els.display;
els.visibility = 'hidden';
els.position = 'absolute';
els.display = 'block';
var originalWidth = element.clientWidth;
var originalHeight = element.clientHeight;
els.display = originalDisplay;
els.position = originalPosition;
els.visibility = originalVisibility;
return {width: originalWidth, height: originalHeight};
},
makePositioned: function(element) {
element = $(element);
var pos = Element.getStyle(element, 'position');
if (pos == 'static' || !pos) {
element._madePositioned = true;
element.style.position = 'relative';
// Opera returns the offset relative to the positioning context, when an
// element is position relative but top and left have not been defined
if (window.opera) {
element.style.top = 0;
element.style.left = 0;
}
}
return element;
},
undoPositioned: function(element) {
element = $(element);
if (element._madePositioned) {
element._madePositioned = undefined;
element.style.position =
element.style.top =
element.style.left =
element.style.bottom =
element.style.right = '';
}
return element;
},
makeClipping: function(element) {
element = $(element);
if (element._overflow) return element;
element._overflow = element.style.overflow || 'auto';
if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden')
element.style.overflow = 'hidden';
return element;
},
undoClipping: function(element) {
element = $(element);
if (!element._overflow) return element;
element.style.overflow = element._overflow == 'auto' ? '' : element._overflow;
element._overflow = null;
return element;
}
};
Object.extend(Element.Methods, {childOf: Element.Methods.descendantOf});
Element._attributeTranslations = {};
Element._attributeTranslations.names = {
colspan:   "colSpan",
rowspan:   "rowSpan",
valign:    "vAlign",
datetime:  "dateTime",
accesskey: "accessKey",
tabindex:  "tabIndex",
enctype:   "encType",
maxlength: "maxLength",
readonly:  "readOnly",
longdesc:  "longDesc"
};
Element._attributeTranslations.values = {
_getAttr: function(element, attribute) {
return element.getAttribute(attribute, 2);
},
_flag: function(element, attribute) {
return $(element).hasAttribute(attribute) ? attribute : null;
},
style: function(element) {
return element.style.cssText.toLowerCase();
},
title: function(element) {
var node = element.getAttributeNode('title');
return node.specified ? node.nodeValue : null;
}
};
Object.extend(Element._attributeTranslations.values, {
href: Element._attributeTranslations.values._getAttr,
src:  Element._attributeTranslations.values._getAttr,
disabled: Element._attributeTranslations.values._flag,
checked:  Element._attributeTranslations.values._flag,
readonly: Element._attributeTranslations.values._flag,
multiple: Element._attributeTranslations.values._flag
});
Element.Methods.Simulated = {
hasAttribute: function(element, attribute) {
var t = Element._attributeTranslations;
attribute = t.names[attribute] || attribute;
return $(element).getAttributeNode(attribute).specified;
}
};
// IE is missing .innerHTML support for TABLE-related elements
if (document.all && !window.opera){
Element.Methods.update = function(element, html) {
element = $(element);
html = typeof html == 'undefined' ? '' : html.toString();
var tagName = element.tagName.toUpperCase();
if (['THEAD','TBODY','TR','TD'].include(tagName)) {
var div = document.createElement('div');
switch (tagName) {
case 'THEAD':
case 'TBODY':
div.innerHTML = '<table><tbody>' +  html.stripScripts() + '</tbody></table>';
depth = 2;
break;
case 'TR':
div.innerHTML = '<table><tbody><tr>' +  html.stripScripts() + '</tr></tbody></table>';
depth = 3;
break;
case 'TD':
div.innerHTML = '<table><tbody><tr><td>' +  html.stripScripts() + '</td></tr></tbody></table>';
depth = 4;
}
$A(element.childNodes).each(function(node){
element.removeChild(node)
});
depth.times(function(){ div = div.firstChild });
$A(div.childNodes).each(
function(node){ element.appendChild(node) });
} else {
element.innerHTML = html.stripScripts();
}
setTimeout(function() {html.evalScripts()}, 10);
return element;
}
};
Object.extend(Element, Element.Methods);
var _nativeExtensions = false;
if(/Konqueror|Safari|KHTML/.test(navigator.userAgent))
['', 'Form', 'Input', 'TextArea', 'Select'].each(function(tag) {
var className = 'HTML' + tag + 'Element';
if(window[className]) return;
var klass = window[className] = {};
klass.prototype = document.createElement(tag ? tag.toLowerCase() : 'div').__proto__;
});
Element.addMethods = function(methods) {
Object.extend(Element.Methods, methods || {});
function copy(methods, destination, onlyIfAbsent) {
onlyIfAbsent = onlyIfAbsent || false;
var cache = Element.extend.cache;
for (var property in methods) {
var value = methods[property];
if (!onlyIfAbsent || !(property in destination))
destination[property] = cache.findOrStore(value);
}
}
if (typeof HTMLElement != 'undefined') {
copy(Element.Methods, HTMLElement.prototype);
copy(Element.Methods.Simulated, HTMLElement.prototype, true);
copy(Form.Methods, HTMLFormElement.prototype);
[HTMLInputElement, HTMLTextAreaElement, HTMLSelectElement].each(function(klass) {
copy(Form.Element.Methods, klass.prototype);
});
_nativeExtensions = true;
}
}
var Toggle = new Object();
Toggle.display = Element.toggle;
/*--------------------------------------------------------------------------*/
Abstract.Insertion = function(adjacency) {
this.adjacency = adjacency;
}
Abstract.Insertion.prototype = {
initialize: function(element, content) {
this.element = $(element);
this.content = content.stripScripts();
if (this.adjacency && this.element.insertAdjacentHTML) {
try {
this.element.insertAdjacentHTML(this.adjacency, this.content);
} catch (e) {
var tagName = this.element.tagName.toUpperCase();
if (['TBODY', 'TR'].include(tagName)) {
this.insertContent(this.contentFromAnonymousTable());
} else {
throw e;
}
}
} else {
this.range = this.element.ownerDocument.createRange();
if (this.initializeRange) this.initializeRange();
this.insertContent([this.range.createContextualFragment(this.content)]);
}
setTimeout(function() {content.evalScripts()}, 10);
},
contentFromAnonymousTable: function() {
var div = document.createElement('div');
div.innerHTML = '<table><tbody>' + this.content + '</tbody></table>';
return $A(div.childNodes[0].childNodes[0].childNodes);
}
}
var Insertion = new Object();
Insertion.Before = Class.create();
Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), {
initializeRange: function() {
this.range.setStartBefore(this.element);
},
insertContent: function(fragments) {
fragments.each((function(fragment) {
this.element.parentNode.insertBefore(fragment, this.element);
}).bind(this));
}
});
Insertion.Top = Class.create();
Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), {
initializeRange: function() {
this.range.selectNodeContents(this.element);
this.range.collapse(true);
},
insertContent: function(fragments) {
fragments.reverse(false).each((function(fragment) {
this.element.insertBefore(fragment, this.element.firstChild);
}).bind(this));
}
});
Insertion.Bottom = Class.create();
Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), {
initializeRange: function() {
this.range.selectNodeContents(this.element);
this.range.collapse(this.element);
},
insertContent: function(fragments) {
fragments.each((function(fragment) {
this.element.appendChild(fragment);
}).bind(this));
}
});
Insertion.After = Class.create();
Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), {
initializeRange: function() {
this.range.setStartAfter(this.element);
},
insertContent: function(fragments) {
fragments.each((function(fragment) {
this.element.parentNode.insertBefore(fragment,
this.element.nextSibling);
}).bind(this));
}
});
/*--------------------------------------------------------------------------*/
Element.ClassNames = Class.create();
Element.ClassNames.prototype = {
initialize: function(element) {
this.element = $(element);
},
_each: function(iterator) {
this.element.className.split(/\s+/).select(function(name) {
return name.length > 0;
})._each(iterator);
},
set: function(className) {
this.element.className = className;
},
add: function(classNameToAdd) {
if (this.include(classNameToAdd)) return;
this.set($A(this).concat(classNameToAdd).join(' '));
},
remove: function(classNameToRemove) {
if (!this.include(classNameToRemove)) return;
this.set($A(this).without(classNameToRemove).join(' '));
},
toString: function() {
return $A(this).join(' ');
}
};
Object.extend(Element.ClassNames.prototype, Enumerable);
var Selector = Class.create();
Selector.prototype = {
initialize: function(expression) {
this.params = {classNames: []};
this.expression = expression.toString().strip();
this.parseExpression();
this.compileMatcher();
},
parseExpression: function() {
function abort(message) { throw 'Parse error in selector: ' + message; }
if (this.expression == '')  abort('empty expression');
var params = this.params, expr = this.expression, match, modifier, clause, rest;
while (match = expr.match(/^(.*)\[([a-z0-9_:-]+?)(?:([~\|!]?=)(?:"([^"]*)"|([^\]\s]*)))?\]$/i)) {
params.attributes = params.attributes || [];
params.attributes.push({name: match[2], operator: match[3], value: match[4] || match[5] || ''});
expr = match[1];
}
if (expr == '*') return this.params.wildcard = true;
while (match = expr.match(/^([^a-z0-9_-])?([a-z0-9_-]+)(.*)/i)) {
modifier = match[1], clause = match[2], rest = match[3];
switch (modifier) {
case '#':       params.id = clause; break;
case '.':       params.classNames.push(clause); break;
case '':
case undefined: params.tagName = clause.toUpperCase(); break;
default:        abort(expr.inspect());
}
expr = rest;
}
if (expr.length > 0) abort(expr.inspect());
},
buildMatchExpression: function() {
var params = this.params, conditions = [], clause;
if (params.wildcard)
conditions.push('true');
if (clause = params.id)
conditions.push('element.readAttribute("id") == ' + clause.inspect());
if (clause = params.tagName)
conditions.push('element.tagName.toUpperCase() == ' + clause.inspect());
if ((clause = params.classNames).length > 0)
for (var i = 0, length = clause.length; i < length; i++)
conditions.push('element.hasClassName(' + clause[i].inspect() + ')');
if (clause = params.attributes) {
clause.each(function(attribute) {
var value = 'element.readAttribute(' + attribute.name.inspect() + ')';
var splitValueBy = function(delimiter) {
return value + ' && ' + value + '.split(' + delimiter.inspect() + ')';
}
switch (attribute.operator) {
case '=':       conditions.push(value + ' == ' + attribute.value.inspect()); break;
case '~=':      conditions.push(splitValueBy(' ') + '.include(' + attribute.value.inspect() + ')'); break;
case '|=':      conditions.push(
splitValueBy('-') + '.first().toUpperCase() == ' + attribute.value.toUpperCase().inspect()
); break;
case '!=':      conditions.push(value + ' != ' + attribute.value.inspect()); break;
case '':
case undefined: conditions.push('element.hasAttribute(' + attribute.name.inspect() + ')'); break;
default:        throw 'Unknown operator ' + attribute.operator + ' in selector';
}
});
}
return conditions.join(' && ');
},
compileMatcher: function() {
this.match = new Function('element', 'if (!element.tagName) return false; \
element = $(element); \
return ' + this.buildMatchExpression());
},
findElements: function(scope) {
var element;
if (element = $(this.params.id))
if (this.match(element))
if (!scope || Element.childOf(element, scope))
return [element];
scope = (scope || document).getElementsByTagName(this.params.tagName || '*');
var results = [];
for (var i = 0, length = scope.length; i < length; i++)
if (this.match(element = scope[i]))
results.push(Element.extend(element));
return results;
},
toString: function() {
return this.expression;
}
}
Object.extend(Selector, {
matchElements: function(elements, expression) {
var selector = new Selector(expression);
return elements.select(selector.match.bind(selector)).map(Element.extend);
},
findElement: function(elements, expression, index) {
if (typeof expression == 'number') index = expression, expression = false;
return Selector.matchElements(elements, expression || '*')[index || 0];
},
findChildElements: function(element, expressions) {
return expressions.map(function(expression) {
return expression.match(/[^\s"]+(?:"[^"]*"[^\s"]+)*/g).inject([null], function(results, expr) {
var selector = new Selector(expr);
return results.inject([], function(elements, result) {
return elements.concat(selector.findElements(result || element));
});
});
}).flatten();
}
});
function $$() {
return Selector.findChildElements(document, $A(arguments));
}
var Form = {
reset: function(form) {
$(form).reset();
return form;
},
serializeElements: function(elements, getHash) {
var data = elements.inject({}, function(result, element) {
if (!element.disabled && element.name) {
var key = element.name, value = $(element).getValue();
if (value != undefined) {
if (result[key]) {
if (result[key].constructor != Array) result[key] = [result[key]];
result[key].push(value);
}
else result[key] = value;
}
}
return result;
});
return getHash ? data : Hash.toQueryString(data);
}
};
Form.Methods = {
serialize: function(form, getHash) {
return Form.serializeElements(Form.getElements(form), getHash);
},
getElements: function(form) {
return $A($(form).getElementsByTagName('*')).inject([],
function(elements, child) {
if (Form.Element.Serializers[child.tagName.toLowerCase()])
elements.push(Element.extend(child));
return elements;
}
);
},
getInputs: function(form, typeName, name) {
form = $(form);
var inputs = form.getElementsByTagName('input');
if (!typeName && !name) return $A(inputs).map(Element.extend);
for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) {
var input = inputs[i];
if ((typeName && input.type != typeName) || (name && input.name != name))
continue;
matchingInputs.push(Element.extend(input));
}
return matchingInputs;
},
disable: function(form) {
form = $(form);
form.getElements().each(function(element) {
element.blur();
element.disabled = 'true';
});
return form;
},
enable: function(form) {
form = $(form);
form.getElements().each(function(element) {
element.disabled = '';
});
return form;
},
findFirstElement: function(form) {
return $(form).getElements().find(function(element) {
return element.type != 'hidden' && !element.disabled &&
['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
});
},
focusFirstElement: function(form) {
form = $(form);
form.findFirstElement().activate();
return form;
}
}
Object.extend(Form, Form.Methods);
/*--------------------------------------------------------------------------*/
Form.Element = {
focus: function(element) {
$(element).focus();
return element;
},
select: function(element) {
$(element).select();
return element;
}
}
Form.Element.Methods = {
serialize: function(element) {
element = $(element);
if (!element.disabled && element.name) {
var value = element.getValue();
if (value != undefined) {
var pair = {};
pair[element.name] = value;
return Hash.toQueryString(pair);
}
}
return '';
},
getValue: function(element) {
element = $(element);
var method = element.tagName.toLowerCase();
return Form.Element.Serializers[method](element);
},
clear: function(element) {
$(element).value = '';
return element;
},
present: function(element) {
return $(element).value != '';
},
activate: function(element) {
element = $(element);
element.focus();
if (element.select && ( element.tagName.toLowerCase() != 'input' ||
!['button', 'reset', 'submit'].include(element.type) ) )
element.select();
return element;
},
disable: function(element) {
element = $(element);
element.disabled = true;
return element;
},
enable: function(element) {
element = $(element);
element.blur();
element.disabled = false;
return element;
}
}
Object.extend(Form.Element, Form.Element.Methods);
var Field = Form.Element;
var $F = Form.Element.getValue;
/*--------------------------------------------------------------------------*/
Form.Element.Serializers = {
input: function(element) {
switch (element.type.toLowerCase()) {
case 'checkbox':
case 'radio':
return Form.Element.Serializers.inputSelector(element);
default:
return Form.Element.Serializers.textarea(element);
}
},
inputSelector: function(element) {
return element.checked ? element.value : null;
},
textarea: function(element) {
return element.value;
},
select: function(element) {
return this[element.type == 'select-one' ?
'selectOne' : 'selectMany'](element);
},
selectOne: function(element) {
var index = element.selectedIndex;
return index >= 0 ? this.optionValue(element.options[index]) : null;
},
selectMany: function(element) {
var values, length = element.length;
if (!length) return null;
for (var i = 0, values = []; i < length; i++) {
var opt = element.options[i];
if (opt.selected) values.push(this.optionValue(opt));
}
return values;
},
optionValue: function(opt) {
// extend element because hasAttribute may not be native
return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text;
}
}
/*--------------------------------------------------------------------------*/
Abstract.TimedObserver = function() {}
Abstract.TimedObserver.prototype = {
initialize: function(element, frequency, callback) {
this.frequency = frequency;
this.element   = $(element);
this.callback  = callback;
this.lastValue = this.getValue();
this.registerCallback();
},
registerCallback: function() {
setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
},
onTimerEvent: function() {
var value = this.getValue();
var changed = ('string' == typeof this.lastValue && 'string' == typeof value
? this.lastValue != value : String(this.lastValue) != String(value));
if (changed) {
this.callback(this.element, value);
this.lastValue = value;
}
}
}
Form.Element.Observer = Class.create();
Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
getValue: function() {
return Form.Element.getValue(this.element);
}
});
Form.Observer = Class.create();
Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
getValue: function() {
return Form.serialize(this.element);
}
});
/*--------------------------------------------------------------------------*/
Abstract.EventObserver = function() {}
Abstract.EventObserver.prototype = {
initialize: function(element, callback) {
this.element  = $(element);
this.callback = callback;
this.lastValue = this.getValue();
if (this.element.tagName.toLowerCase() == 'form')
this.registerFormCallbacks();
else
this.registerCallback(this.element);
},
onElementEvent: function() {
var value = this.getValue();
if (this.lastValue != value) {
this.callback(this.element, value);
this.lastValue = value;
}
},
registerFormCallbacks: function() {
Form.getElements(this.element).each(this.registerCallback.bind(this));
},
registerCallback: function(element) {
if (element.type) {
switch (element.type.toLowerCase()) {
case 'checkbox':
case 'radio':
Event.observe(element, 'click', this.onElementEvent.bind(this));
break;
default:
Event.observe(element, 'change', this.onElementEvent.bind(this));
break;
}
}
}
}
Form.Element.EventObserver = Class.create();
Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
getValue: function() {
return Form.Element.getValue(this.element);
}
});
Form.EventObserver = Class.create();
Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
getValue: function() {
return Form.serialize(this.element);
}
});
if (!window.Event) {
var Event = new Object();
}
Object.extend(Event, {
KEY_BACKSPACE: 8,
KEY_TAB:       9,
KEY_RETURN:   13,
KEY_ESC:      27,
KEY_LEFT:     37,
KEY_UP:       38,
KEY_RIGHT:    39,
KEY_DOWN:     40,
KEY_DELETE:   46,
KEY_HOME:     36,
KEY_END:      35,
KEY_PAGEUP:   33,
KEY_PAGEDOWN: 34,
element: function(event) {
return event.target || event.srcElement;
},
isLeftClick: function(event) {
return (((event.which) && (event.which == 1)) ||
((event.button) && (event.button == 1)));
},
pointerX: function(event) {
return event.pageX || (event.clientX +
(document.documentElement.scrollLeft || document.body.scrollLeft));
},
pointerY: function(event) {
return event.pageY || (event.clientY +
(document.documentElement.scrollTop || document.body.scrollTop));
},
stop: function(event) {
if (event.preventDefault) {
event.preventDefault();
event.stopPropagation();
} else {
event.returnValue = false;
event.cancelBubble = true;
}
},
// find the first node with the given tagName, starting from the
// node the event was triggered on; traverses the DOM upwards
findElement: function(event, tagName) {
var element = Event.element(event);
while (element.parentNode && (!element.tagName ||
(element.tagName.toUpperCase() != tagName.toUpperCase())))
element = element.parentNode;
return element;
},
observers: false,
_observeAndCache: function(element, name, observer, useCapture) {
if (!this.observers) this.observers = [];
if (element.addEventListener) {
this.observers.push([element, name, observer, useCapture]);
element.addEventListener(name, observer, useCapture);
} else if (element.attachEvent) {
this.observers.push([element, name, observer, useCapture]);
element.attachEvent('on' + name, observer);
}
},
unloadCache: function() {
if (!Event.observers) return;
for (var i = 0, length = Event.observers.length; i < length; i++) {
Event.stopObserving.apply(this, Event.observers[i]);
Event.observers[i][0] = null;
}
Event.observers = false;
},
observe: function(element, name, observer, useCapture) {
element = $(element);
useCapture = useCapture || false;
if (name == 'keypress' &&
(navigator.appVersion.match(/Konqueror|Safari|KHTML/)
|| element.attachEvent))
name = 'keydown';
Event._observeAndCache(element, name, observer, useCapture);
},
stopObserving: function(element, name, observer, useCapture) {
element = $(element);
useCapture = useCapture || false;
if (name == 'keypress' &&
(navigator.appVersion.match(/Konqueror|Safari|KHTML/)
|| element.detachEvent))
name = 'keydown';
if (element.removeEventListener) {
element.removeEventListener(name, observer, useCapture);
} else if (element.detachEvent) {
try {
element.detachEvent('on' + name, observer);
} catch (e) {}
}
}
});
/* prevent memory leaks in IE */
if (navigator.appVersion.match(/\bMSIE\b/))
Event.observe(window, 'unload', Event.unloadCache, false);
var Position = {
// set to true if needed, warning: firefox performance problems
// NOT neeeded for page scrolling, only if draggable contained in
// scrollable elements
includeScrollOffsets: false,
// must be called before calling withinIncludingScrolloffset, every time the
// page is scrolled
prepare: function() {
this.deltaX =  window.pageXOffset
|| document.documentElement.scrollLeft
|| document.body.scrollLeft
|| 0;
this.deltaY =  window.pageYOffset
|| document.documentElement.scrollTop
|| document.body.scrollTop
|| 0;
},
realOffset: function(element) {
var valueT = 0, valueL = 0;
do {
valueT += element.scrollTop  || 0;
valueL += element.scrollLeft || 0;
element = element.parentNode;
} while (element);
return [valueL, valueT];
},
cumulativeOffset: function(element) {
var valueT = 0, valueL = 0;
do {
valueT += element.offsetTop  || 0;
valueL += element.offsetLeft || 0;
element = element.offsetParent;
} while (element);
return [valueL, valueT];
},
positionedOffset: function(element) {
var valueT = 0, valueL = 0;
do {
valueT += element.offsetTop  || 0;
valueL += element.offsetLeft || 0;
element = element.offsetParent;
if (element) {
if(element.tagName=='BODY') break;
var p = Element.getStyle(element, 'position');
if (p == 'relative' || p == 'absolute') break;
}
} while (element);
return [valueL, valueT];
},
offsetParent: function(element) {
if (element.offsetParent) return element.offsetParent;
if (element == document.body) return element;
while ((element = element.parentNode) && element != document.body)
if (Element.getStyle(element, 'position') != 'static')
return element;
return document.body;
},
// caches x/y coordinate pair to use with overlap
within: function(element, x, y) {
if (this.includeScrollOffsets)
return this.withinIncludingScrolloffsets(element, x, y);
this.xcomp = x;
this.ycomp = y;
this.offset = this.cumulativeOffset(element);
return (y >= this.offset[1] &&
y <  this.offset[1] + element.offsetHeight &&
x >= this.offset[0] &&
x <  this.offset[0] + element.offsetWidth);
},
withinIncludingScrolloffsets: function(element, x, y) {
var offsetcache = this.realOffset(element);
this.xcomp = x + offsetcache[0] - this.deltaX;
this.ycomp = y + offsetcache[1] - this.deltaY;
this.offset = this.cumulativeOffset(element);
return (this.ycomp >= this.offset[1] &&
this.ycomp <  this.offset[1] + element.offsetHeight &&
this.xcomp >= this.offset[0] &&
this.xcomp <  this.offset[0] + element.offsetWidth);
},
// within must be called directly before
overlap: function(mode, element) {
if (!mode) return 0;
if (mode == 'vertical')
return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
element.offsetHeight;
if (mode == 'horizontal')
return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
element.offsetWidth;
},
page: function(forElement) {
var valueT = 0, valueL = 0;
var element = forElement;
do {
valueT += element.offsetTop  || 0;
valueL += element.offsetLeft || 0;
// Safari fix
if (element.offsetParent==document.body)
if (Element.getStyle(element,'position')=='absolute') break;
} while (element = element.offsetParent);
element = forElement;
do {
if (!window.opera || element.tagName=='BODY') {
valueT -= element.scrollTop  || 0;
valueL -= element.scrollLeft || 0;
}
} while (element = element.parentNode);
return [valueL, valueT];
},
clone: function(source, target) {
var options = Object.extend({
setLeft:    true,
setTop:     true,
setWidth:   true,
setHeight:  true,
offsetTop:  0,
offsetLeft: 0
}, arguments[2] || {})
// find page position of source
source = $(source);
var p = Position.page(source);
// find coordinate system to use
target = $(target);
var delta = [0, 0];
var parent = null;
// delta [0,0] will do fine with position: fixed elements,
// position:absolute needs offsetParent deltas
if (Element.getStyle(target,'position') == 'absolute') {
parent = Position.offsetParent(target);
delta = Position.page(parent);
}
// correct by body offsets (fixes Safari)
if (parent == document.body) {
delta[0] -= document.body.offsetLeft;
delta[1] -= document.body.offsetTop;
}
// set position
if(options.setLeft)   target.style.left  = (p[0] - delta[0] + options.offsetLeft) + 'px';
if(options.setTop)    target.style.top   = (p[1] - delta[1] + options.offsetTop) + 'px';
if(options.setWidth)  target.style.width = source.offsetWidth + 'px';
if(options.setHeight) target.style.height = source.offsetHeight + 'px';
},
absolutize: function(element) {
element = $(element);
if (element.style.position == 'absolute') return;
Position.prepare();
var offsets = Position.positionedOffset(element);
var top     = offsets[1];
var left    = offsets[0];
var width   = element.clientWidth;
var height  = element.clientHeight;
element._originalLeft   = left - parseFloat(element.style.left  || 0);
element._originalTop    = top  - parseFloat(element.style.top || 0);
element._originalWidth  = element.style.width;
element._originalHeight = element.style.height;
element.style.position = 'absolute';
element.style.top    = top + 'px';
element.style.left   = left + 'px';
element.style.width  = width + 'px';
element.style.height = height + 'px';
},
relativize: function(element) {
element = $(element);
if (element.style.position == 'relative') return;
Position.prepare();
element.style.position = 'relative';
var top  = parseFloat(element.style.top  || 0) - (element._originalTop || 0);
var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);
element.style.top    = top + 'px';
element.style.left   = left + 'px';
element.style.height = element._originalHeight;
element.style.width  = element._originalWidth;
}
}
// Safari returns margins on body which is incorrect if the child is absolutely
// positioned.  For performance reasons, redefine Position.cumulativeOffset for
// KHTML/WebKit only.
if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) {
Position.cumulativeOffset = function(element) {
var valueT = 0, valueL = 0;
do {
valueT += element.offsetTop  || 0;
valueL += element.offsetLeft || 0;
if (element.offsetParent == document.body)
if (Element.getStyle(element, 'position') == 'absolute') break;
element = element.offsetParent;
} while (element);
return [valueL, valueT];
}
}
Element.addMethods();
// script.aculo.us scriptaculous.js v1.7.0, Fri Jan 19 19:16:36 CET 2007
// Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// For details, see the script.aculo.us web site: http://script.aculo.us/
var Scriptaculous = {
Version: '1.7.0',
require: function(libraryName) {
// inserting via DOM fails in Safari 2.0, so brute force approach
document.write('<script type="text/javascript" src="'+libraryName+'"></script>');
},
load: function() {
if((typeof Prototype=='undefined') ||
(typeof Element == 'undefined') ||
(typeof Element.Methods=='undefined') ||
parseFloat(Prototype.Version.split(".")[0] + "." +
Prototype.Version.split(".")[1]) < 1.5)
throw("script.aculo.us requires the Prototype JavaScript framework >= 1.5.0");
$A(document.getElementsByTagName("script")).findAll( function(s) {
return (s.src && s.src.match(/scriptaculous\.js(\?.*)?$/))
}).each( function(s) {
var path = s.src.replace(/scriptaculous\.js(\?.*)?$/,'');
var includes = s.src.match(/\?.*load=([a-z,]*)/);
(includes ? includes[1] : 'builder,effects,dragdrop,controls,slider').split(',').each(
function(include) { Scriptaculous.require(path+include+'.js') });
});
}
}
Scriptaculous.load();
// script.aculo.us effects.js v1.7.0, Fri Jan 19 19:16:36 CET 2007
// Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
// Contributors:
//  Justin Palmer (http://encytemedia.com/)
//  Mark Pilgrim (http://diveintomark.org/)
//  Martin Bialasinki
//
// script.aculo.us is freely distributable under the terms of an MIT-style license.
// For details, see the script.aculo.us web site: http://script.aculo.us/
// converts rgb() and #xxx to #xxxxxx format,
// returns self (or first argument) if not convertable
String.prototype.parseColor = function() {
var color = '#';
if(this.slice(0,4) == 'rgb(') {
var cols = this.slice(4,this.length-1).split(',');
var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3);
} else {
if(this.slice(0,1) == '#') {
if(this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase();
if(this.length==7) color = this.toLowerCase();
}
}
return(color.length==7 ? color : (arguments[0] || this));
}
/*--------------------------------------------------------------------------*/
Element.collectTextNodes = function(element) {
return $A($(element).childNodes).collect( function(node) {
return (node.nodeType==3 ? node.nodeValue :
(node.hasChildNodes() ? Element.collectTextNodes(node) : ''));
}).flatten().join('');
}
Element.collectTextNodesIgnoreClass = function(element, className) {
return $A($(element).childNodes).collect( function(node) {
return (node.nodeType==3 ? node.nodeValue :
((node.hasChildNodes() && !Element.hasClassName(node,className)) ?
Element.collectTextNodesIgnoreClass(node, className) : ''));
}).flatten().join('');
}
Element.setContentZoom = function(element, percent) {
element = $(element);
element.setStyle({fontSize: (percent/100) + 'em'});
if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);
return element;
}
Element.getOpacity = function(element){
return $(element).getStyle('opacity');
}
Element.setOpacity = function(element, value){
return $(element).setStyle({opacity:value});
}
Element.getInlineOpacity = function(element){
return $(element).style.opacity || '';
}
Element.forceRerendering = function(element) {
/*  try {
element = $(element);
var n = document.createTextNode(' ');
element.appendChild(n);
element.removeChild(n);
} catch(e) { }
*/
};
/*--------------------------------------------------------------------------*/
Array.prototype.call = function() {
var args = arguments;
this.each(function(f){ f.apply(this, args) });
}
/*--------------------------------------------------------------------------*/
var Effect = {
_elementDoesNotExistError: {
name: 'ElementDoesNotExistError',
message: 'The specified DOM element does not exist, but is required for this effect to operate'
},
tagifyText: function(element) {
if(typeof Builder == 'undefined')
throw("Effect.tagifyText requires including script.aculo.us' builder.js library");
var tagifyStyle = 'position:relative';
if(/MSIE/.test(navigator.userAgent) && !window.opera) tagifyStyle += ';zoom:1';
element = $(element);
$A(element.childNodes).each( function(child) {
if(child.nodeType==3) {
child.nodeValue.toArray().each( function(character) {
element.insertBefore(
Builder.node('span',{style: tagifyStyle},
character == ' ' ? String.fromCharCode(160) : character),
child);
});
Element.remove(child);
}
});
},
multiple: function(element, effect) {
var elements;
if(((typeof element == 'object') ||
(typeof element == 'function')) &&
(element.length))
elements = element;
else
elements = $(element).childNodes;
var options = Object.extend({
speed: 0.1,
delay: 0.0
}, arguments[2] || {});
var masterDelay = options.delay;
$A(elements).each( function(element, index) {
new effect(element, Object.extend(options, { delay: index * options.speed + masterDelay }));
});
},
PAIRS: {
'slide':  ['SlideDown','SlideUp'],
'blind':  ['BlindDown','BlindUp'],
'appear': ['Appear','Fade']
},
toggle: function(element, effect) {
element = $(element);
effect = (effect || 'appear').toLowerCase();
var options = Object.extend({
queue: { position:'end', scope:(element.id || 'global'), limit: 1 }
}, arguments[2] || {});
Effect[element.visible() ?
Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options);
}
};
var Effect2 = Effect; // deprecated
/* ------------- transitions ------------- */
Effect.Transitions = {
linear: Prototype.K,
sinoidal: function(pos) {
return (-Math.cos(pos*Math.PI)/2) + 0.5;
},
reverse: function(pos) {
return 1-pos;
},
flicker: function(pos) {
return ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4;
},
wobble: function(pos) {
return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5;
},
pulse: function(pos, pulses) {
pulses = pulses || 5;
return (
Math.round((pos % (1/pulses)) * pulses) == 0 ?
((pos * pulses * 2) - Math.floor(pos * pulses * 2)) :
1 - ((pos * pulses * 2) - Math.floor(pos * pulses * 2))
);
},
none: function(pos) {
return 0;
},
full: function(pos) {
return 1;
}
};
/* ------------- core effects ------------- */
Effect.ScopedQueue = Class.create();
Object.extend(Object.extend(Effect.ScopedQueue.prototype, Enumerable), {
initialize: function() {
this.effects  = [];
this.interval = null;
},
_each: function(iterator) {
this.effects._each(iterator);
},
add: function(effect) {
var timestamp = new Date().getTime();
var position = (typeof effect.options.queue == 'string') ?
effect.options.queue : effect.options.queue.position;
switch(position) {
case 'front':
// move unstarted effects after this effect
this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) {
e.startOn  += effect.finishOn;
e.finishOn += effect.finishOn;
});
break;
case 'with-last':
timestamp = this.effects.pluck('startOn').max() || timestamp;
break;
case 'end':
// start effect after last queued effect has finished
timestamp = this.effects.pluck('finishOn').max() || timestamp;
break;
}
effect.startOn  += timestamp;
effect.finishOn += timestamp;
if(!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit))
this.effects.push(effect);
if(!this.interval)
this.interval = setInterval(this.loop.bind(this), 15);
},
remove: function(effect) {
this.effects = this.effects.reject(function(e) { return e==effect });
if(this.effects.length == 0) {
clearInterval(this.interval);
this.interval = null;
}
},
loop: function() {
var timePos = new Date().getTime();
for(var i=0, len=this.effects.length;i<len;i++)
if(this.effects[i]) this.effects[i].loop(timePos);
}
});
Effect.Queues = {
instances: $H(),
get: function(queueName) {
if(typeof queueName != 'string') return queueName;
if(!this.instances[queueName])
this.instances[queueName] = new Effect.ScopedQueue();
return this.instances[queueName];
}
}
Effect.Queue = Effect.Queues.get('global');
Effect.DefaultOptions = {
transition: Effect.Transitions.sinoidal,
duration:   1.0,   // seconds
fps:        60.0,  // max. 60fps due to Effect.Queue implementation
sync:       false, // true for combining
from:       0.0,
to:         1.0,
delay:      0.0,
queue:      'parallel'
}
Effect.Base = function() {};
Effect.Base.prototype = {
position: null,
start: function(options) {
this.options      = Object.extend(Object.extend({},Effect.DefaultOptions), options || {});
this.currentFrame = 0;
this.state        = 'idle';
this.startOn      = this.options.delay*1000;
this.finishOn     = this.startOn + (this.options.duration*1000);
this.event('beforeStart');
if(!this.options.sync)
Effect.Queues.get(typeof this.options.queue == 'string' ?
'global' : this.options.queue.scope).add(this);
},
loop: function(timePos) {
if(timePos >= this.startOn) {
if(timePos >= this.finishOn) {
this.render(1.0);
this.cancel();
this.event('beforeFinish');
if(this.finish) this.finish();
this.event('afterFinish');
return;
}
var pos   = (timePos - this.startOn) / (this.finishOn - this.startOn);
var frame = Math.round(pos * this.options.fps * this.options.duration);
if(frame > this.currentFrame) {
this.render(pos);
this.currentFrame = frame;
}
}
},
render: function(pos) {
if(this.state == 'idle') {
this.state = 'running';
this.event('beforeSetup');
if(this.setup) this.setup();
this.event('afterSetup');
}
if(this.state == 'running') {
if(this.options.transition) pos = this.options.transition(pos);
pos *= (this.options.to-this.options.from);
pos += this.options.from;
this.position = pos;
this.event('beforeUpdate');
if(this.update) this.update(pos);
this.event('afterUpdate');
}
},
cancel: function() {
if(!this.options.sync)
Effect.Queues.get(typeof this.options.queue == 'string' ?
'global' : this.options.queue.scope).remove(this);
this.state = 'finished';
},
event: function(eventName) {
if(this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this);
if(this.options[eventName]) this.options[eventName](this);
},
inspect: function() {
var data = $H();
for(property in this)
if(typeof this[property] != 'function') data[property] = this[property];
return '#<Effect:' + data.inspect() + ',options:' + $H(this.options).inspect() + '>';
}
}
Effect.Parallel = Class.create();
Object.extend(Object.extend(Effect.Parallel.prototype, Effect.Base.prototype), {
initialize: function(effects) {
this.effects = effects || [];
this.start(arguments[1]);
},
update: function(position) {
this.effects.invoke('render', position);
},
finish: function(position) {
this.effects.each( function(effect) {
effect.render(1.0);
effect.cancel();
effect.event('beforeFinish');
if(effect.finish) effect.finish(position);
effect.event('afterFinish');
});
}
});
Effect.Event = Class.create();
Object.extend(Object.extend(Effect.Event.prototype, Effect.Base.prototype), {
initialize: function() {
var options = Object.extend({
duration: 0
}, arguments[0] || {});
this.start(options);
},
update: Prototype.emptyFunction
});
Effect.Opacity = Class.create();
Object.extend(Object.extend(Effect.Opacity.prototype, Effect.Base.prototype), {
initialize: function(element) {
this.element = $(element);
if(!this.element) throw(Effect._elementDoesNotExistError);
// make this work on IE on elements without 'layout'
if(/MSIE/.test(navigator.userAgent) && !window.opera && (!this.element.currentStyle.hasLayout))
this.element.setStyle({zoom: 1});
var options = Object.extend({
from: this.element.getOpacity() || 0.0,
to:   1.0
}, arguments[1] || {});
this.start(options);
},
update: function(position) {
this.element.setOpacity(position);
}
});
Effect.Move = Class.create();
Object.extend(Object.extend(Effect.Move.prototype, Effect.Base.prototype), {
initialize: function(element) {
this.element = $(element);
if(!this.element) throw(Effect._elementDoesNotExistError);
var options = Object.extend({
x:    0,
y:    0,
mode: 'relative'
}, arguments[1] || {});
this.start(options);
},
setup: function() {
// Bug in Opera: Opera returns the "real" position of a static element or
// relative element that does not have top/left explicitly set.
// ==> Always set top and left for position relative elements in your stylesheets
// (to 0 if you do not need them)
this.element.makePositioned();
this.originalLeft = parseFloat(this.element.getStyle('left') || '0');
this.originalTop  = parseFloat(this.element.getStyle('top')  || '0');
if(this.options.mode == 'absolute') {
// absolute movement, so we need to calc deltaX and deltaY
this.options.x = this.options.x - this.originalLeft;
this.options.y = this.options.y - this.originalTop;
}
},
update: function(position) {
this.element.setStyle({
left: Math.round(this.options.x  * position + this.originalLeft) + 'px',
top:  Math.round(this.options.y  * position + this.originalTop)  + 'px'
});
}
});
// for backwards compatibility
Effect.MoveBy = function(element, toTop, toLeft) {
return new Effect.Move(element,
Object.extend({ x: toLeft, y: toTop }, arguments[3] || {}));
};
Effect.Scale = Class.create();
Object.extend(Object.extend(Effect.Scale.prototype, Effect.Base.prototype), {
initialize: function(element, percent) {
this.element = $(element);
if(!this.element) throw(Effect._elementDoesNotExistError);
var options = Object.extend({
scaleX: true,
scaleY: true,
scaleContent: true,
scaleFromCenter: false,
scaleMode: 'box',        // 'box' or 'contents' or {} with provided values
scaleFrom: 100.0,
scaleTo:   percent
}, arguments[2] || {});
this.start(options);
},
setup: function() {
this.restoreAfterFinish = this.options.restoreAfterFinish || false;
this.elementPositioning = this.element.getStyle('position');
this.originalStyle = {};
['top','left','width','height','fontSize'].each( function(k) {
this.originalStyle[k] = this.element.style[k];
}.bind(this));
this.originalTop  = this.element.offsetTop;
this.originalLeft = this.element.offsetLeft;
var fontSize = this.element.getStyle('font-size') || '100%';
['em','px','%','pt'].each( function(fontSizeType) {
if(fontSize.indexOf(fontSizeType)>0) {
this.fontSize     = parseFloat(fontSize);
this.fontSizeType = fontSizeType;
}
}.bind(this));
this.factor = (this.options.scaleTo - this.options.scaleFrom)/100;
this.dims = null;
if(this.options.scaleMode=='box')
this.dims = [this.element.offsetHeight, this.element.offsetWidth];
if(/^content/.test(this.options.scaleMode))
this.dims = [this.element.scrollHeight, this.element.scrollWidth];
if(!this.dims)
this.dims = [this.options.scaleMode.originalHeight,
this.options.scaleMode.originalWidth];
},
update: function(position) {
var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position);
if(this.options.scaleContent && this.fontSize)
this.element.setStyle({fontSize: this.fontSize * currentScale + this.fontSizeType });
this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale);
},
finish: function(position) {
if(this.restoreAfterFinish) this.element.setStyle(this.originalStyle);
},
setDimensions: function(height, width) {
var d = {};
if(this.options.scaleX) d.width = Math.round(width) + 'px';
if(this.options.scaleY) d.height = Math.round(height) + 'px';
if(this.options.scaleFromCenter) {
var topd  = (height - this.dims[0])/2;
var leftd = (width  - this.dims[1])/2;
if(this.elementPositioning == 'absolute') {
if(this.options.scaleY) d.top = this.originalTop-topd + 'px';
if(this.options.scaleX) d.left = this.originalLeft-leftd + 'px';
} else {
if(this.options.scaleY) d.top = -topd + 'px';
if(this.options.scaleX) d.left = -leftd + 'px';
}
}
this.element.setStyle(d);
}
});
Effect.Highlight = Class.create();
Object.extend(Object.extend(Effect.Highlight.prototype, Effect.Base.prototype), {
initialize: function(element) {
this.element = $(element);
if(!this.element) throw(Effect._elementDoesNotExistError);
var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || {});
this.start(options);
},
setup: function() {
// Prevent executing on elements not in the layout flow
if(this.element.getStyle('display')=='none') { this.cancel(); return; }
// Disable background image during the effect
this.oldStyle = {};
if (!this.options.keepBackgroundImage) {
this.oldStyle.backgroundImage = this.element.getStyle('background-image');
this.element.setStyle({backgroundImage: 'none'});
}
if(!this.options.endcolor)
this.options.endcolor = this.element.getStyle('background-color').parseColor('#ffffff');
if(!this.options.restorecolor)
this.options.restorecolor = this.element.getStyle('background-color');
// init color calculations
this._base  = $R(0,2).map(function(i){ return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16) }.bind(this));
this._delta = $R(0,2).map(function(i){ return parseInt(this.options.endcolor.slice(i*2+1,i*2+3),16)-this._base[i] }.bind(this));
},
update: function(position) {
this.element.setStyle({backgroundColor: $R(0,2).inject('#',function(m,v,i){
return m+(Math.round(this._base[i]+(this._delta[i]*position)).toColorPart()); }.bind(this)) });
},
finish: function() {
this.element.setStyle(Object.extend(this.oldStyle, {
backgroundColor: this.options.restorecolor
}));
}
});
Effect.ScrollTo = Class.create();
Object.extend(Object.extend(Effect.ScrollTo.prototype, Effect.Base.prototype), {
initialize: function(element) {
this.element = $(element);
this.start(arguments[1] || {});
},
setup: function() {
Position.prepare();
var offsets = Position.cumulativeOffset(this.element);
if(this.options.offset) offsets[1] += this.options.offset;
var max = window.innerHeight ?
window.height - window.innerHeight :
document.body.scrollHeight -
(document.documentElement.clientHeight ?
document.documentElement.clientHeight : document.body.clientHeight);
this.scrollStart = Position.deltaY;
this.delta = (offsets[1] > max ? max : offsets[1]) - this.scrollStart;
},
update: function(position) {
Position.prepare();
window.scrollTo(Position.deltaX,
this.scrollStart + (position*this.delta));
}
});
/* ------------- combination effects ------------- */
Effect.FadeCollection = function(elements) {
this.effects = new Array();
for(var i=1; i<elements.length; i++){
this.effects.push(new Effect.Fade(elements[i], arguments[1]||{}));
}
}
Effect.FadeCollection.prototype.cancel = function(){
for(var i=0;i<this.effects.length;i++){
this.effects[i].cancel();
}
}
Effect.Fade = function(element) {
element = $(element);
var oldOpacity = element.getInlineOpacity();
var options = Object.extend({
from: element.getOpacity() || 1.0,
to:   0.0,
afterFinishInternal: function(effect) {
if(effect.options.to!=0) return;
effect.element.hide().setStyle({opacity: oldOpacity});
}}, arguments[1] || {});
return new Effect.Opacity(element,options);
}
Effect.Appear = function(element) {
element = $(element);
var options = Object.extend({
from: (element.getStyle('display') == 'none' ? 0.0 : element.getOpacity() || 0.0),
to:   1.0,
// force Safari to render floated elements properly
afterFinishInternal: function(effect) {
effect.element.forceRerendering();
},
beforeSetup: function(effect) {
effect.element.setOpacity(effect.options.from).show();
}}, arguments[1] || {});
return new Effect.Opacity(element,options);
}
Effect.Puff = function(element) {
element = $(element);
var oldStyle = {
opacity: element.getInlineOpacity(),
position: element.getStyle('position'),
top:  element.style.top,
left: element.style.left,
width: element.style.width,
height: element.style.height
};
return new Effect.Parallel(
[ new Effect.Scale(element, 200,
{ sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }),
new Effect.Opacity(element, { sync: true, to: 0.0 } ) ],
Object.extend({ duration: 1.0,
beforeSetupInternal: function(effect) {
Position.absolutize(effect.effects[0].element)
},
afterFinishInternal: function(effect) {
effect.effects[0].element.hide().setStyle(oldStyle); }
}, arguments[1] || {})
);
}
Effect.BlindUp = function(element) {
element = $(element);
element.makeClipping();
return new Effect.Scale(element, 0,
Object.extend({ scaleContent: false,
scaleX: false,
restoreAfterFinish: true,
afterFinishInternal: function(effect) {
effect.element.hide().undoClipping();
}
}, arguments[1] || {})
);
}
Effect.BlindDown = function(element) {
element = $(element);
var elementDimensions = element.getDimensions();
return new Effect.Scale(element, 100, Object.extend({
scaleContent: false,
scaleX: false,
scaleFrom: 0,
scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
restoreAfterFinish: true,
afterSetup: function(effect) {
effect.element.makeClipping().setStyle({height: '0px'}).show();
},
afterFinishInternal: function(effect) {
effect.element.undoClipping();
}
}, arguments[1] || {}));
}
Effect.SwitchOff = function(element) {
element = $(element);
var oldOpacity = element.getInlineOpacity();
return new Effect.Appear(element, Object.extend({
duration: 0.4,
from: 0,
transition: Effect.Transitions.flicker,
afterFinishInternal: function(effect) {
new Effect.Scale(effect.element, 1, {
duration: 0.3, scaleFromCenter: true,
scaleX: false, scaleContent: false, restoreAfterFinish: true,
beforeSetup: function(effect) {
effect.element.makePositioned().makeClipping();
},
afterFinishInternal: function(effect) {
effect.element.hide().undoClipping().undoPositioned().setStyle({opacity: oldOpacity});
}
})
}
}, arguments[1] || {}));
}
Effect.DropOut = function(element) {
element = $(element);
var oldStyle = {
top: element.getStyle('top'),
left: element.getStyle('left'),
opacity: element.getInlineOpacity() };
return new Effect.Parallel(
[ new Effect.Move(element, {x: 0, y: 100, sync: true }),
new Effect.Opacity(element, { sync: true, to: 0.0 }) ],
Object.extend(
{ duration: 0.5,
beforeSetup: function(effect) {
effect.effects[0].element.makePositioned();
},
afterFinishInternal: function(effect) {
effect.effects[0].element.hide().undoPositioned().setStyle(oldStyle);
}
}, arguments[1] || {}));
}
Effect.Shake = function(element) {
element = $(element);
var oldStyle = {
top: element.getStyle('top'),
left: element.getStyle('left') };
return new Effect.Move(element,
{ x:  20, y: 0, duration: 0.05, afterFinishInternal: function(effect) {
new Effect.Move(effect.element,
{ x: -40, y: 0, duration: 0.1,  afterFinishInternal: function(effect) {
new Effect.Move(effect.element,
{ x:  40, y: 0, duration: 0.1,  afterFinishInternal: function(effect) {
new Effect.Move(effect.element,
{ x: -40, y: 0, duration: 0.1,  afterFinishInternal: function(effect) {
new Effect.Move(effect.element,
{ x:  40, y: 0, duration: 0.1,  afterFinishInternal: function(effect) {
new Effect.Move(effect.element,
{ x: -20, y: 0, duration: 0.05, afterFinishInternal: function(effect) {
effect.element.undoPositioned().setStyle(oldStyle);
}}) }}) }}) }}) }}) }});
}
Effect.SlideDown = function(element) {
element = $(element).cleanWhitespace();
// SlideDown need to have the content of the element wrapped in a container element with fixed height!
var oldInnerBottom = element.down().getStyle('bottom');
var elementDimensions = element.getDimensions();
return new Effect.Scale(element, 100, Object.extend({
scaleContent: false,
scaleX: false,
scaleFrom: window.opera ? 0 : 1,
scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
restoreAfterFinish: true,
afterSetup: function(effect) {
effect.element.makePositioned();
effect.element.down().makePositioned();
if(window.opera) effect.element.setStyle({top: ''});
effect.element.makeClipping().setStyle({height: '0px'}).show();
},
afterUpdateInternal: function(effect) {
effect.element.down().setStyle({bottom:
(effect.dims[0] - effect.element.clientHeight) + 'px' });
},
afterFinishInternal: function(effect) {
effect.element.undoClipping().undoPositioned();
effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom}); }
}, arguments[1] || {})
);
}
Effect.SlideUp = function(element) {
element = $(element).cleanWhitespace();
var oldInnerBottom = element.down().getStyle('bottom');
return new Effect.Scale(element, window.opera ? 0 : 1,
Object.extend({ scaleContent: false,
scaleX: false,
scaleMode: 'box',
scaleFrom: 100,
restoreAfterFinish: true,
beforeStartInternal: function(effect) {
effect.element.makePositioned();
effect.element.down().makePositioned();
if(window.opera) effect.element.setStyle({top: ''});
effect.element.makeClipping().show();
},
afterUpdateInternal: function(effect) {
effect.element.down().setStyle({bottom:
(effect.dims[0] - effect.element.clientHeight) + 'px' });
},
afterFinishInternal: function(effect) {
effect.element.hide().undoClipping().undoPositioned().setStyle({bottom: oldInnerBottom});
effect.element.down().undoPositioned();
}
}, arguments[1] || {})
);
}
Effect.BlindRight = function(element, onComplete) {
element = $(element);
var elementDimensions = element.getDimensions();
return new Effect.Scale(element, 100, Object.extend({
scaleContent: false,
scaleY: false,
scaleFrom: 0,
scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
restoreAfterFinish: true,
afterSetup: function(effect) {
effect.element.makeClipping().setStyle({width: '0px'}).show();
},
afterFinishInternal: function(effect) {
effect.element.undoClipping();
onComplete();
}
}, arguments[1] || {}));
}
Effect.BlindLeft = function(element) {
element = $(element);
element.makeClipping();
return new Effect.Scale(element, 0,
Object.extend({ scaleContent: false,
scaleY: false,
restoreAfterFinish: true,
afterFinishInternal: function(effect) {
effect.element.hide().undoClipping();
}
}, arguments[1] || {})
);
}
// Bug in opera makes the TD containing this element expand for a instance after finish
Effect.Squish = function(element) {
return new Effect.Scale(element, window.opera ? 1 : 0, {
restoreAfterFinish: true,
beforeSetup: function(effect) {
effect.element.makeClipping();
},
afterFinishInternal: function(effect) {
effect.element.hide().undoClipping();
}
});
}
Effect.Grow = function(element) {
element = $(element);
var options = Object.extend({
direction: 'center',
moveTransition: Effect.Transitions.sinoidal,
scaleTransition: Effect.Transitions.sinoidal,
opacityTransition: Effect.Transitions.full
}, arguments[1] || {});
var oldStyle = {
top: element.style.top,
left: element.style.left,
height: element.style.height,
width: element.style.width,
opacity: element.getInlineOpacity() };
var dims = element.getDimensions();
var initialMoveX, initialMoveY;
var moveX, moveY;
switch (options.direction) {
case 'top-left':
initialMoveX = initialMoveY = moveX = moveY = 0;
break;
case 'top-right':
initialMoveX = dims.width;
initialMoveY = moveY = 0;
moveX = -dims.width;
break;
case 'bottom-left':
initialMoveX = moveX = 0;
initialMoveY = dims.height;
moveY = -dims.height;
break;
case 'bottom-right':
initialMoveX = dims.width;
initialMoveY = dims.height;
moveX = -dims.width;
moveY = -dims.height;
break;
case 'center':
initialMoveX = dims.width / 2;
initialMoveY = dims.height / 2;
moveX = -dims.width / 2;
moveY = -dims.height / 2;
break;
}
return new Effect.Move(element, {
x: initialMoveX,
y: initialMoveY,
duration: 0.01,
beforeSetup: function(effect) {
effect.element.hide().makeClipping().makePositioned();
},
afterFinishInternal: function(effect) {
new Effect.Parallel(
[ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }),
new Effect.Move(effect.element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }),
new Effect.Scale(effect.element, 100, {
scaleMode: { originalHeight: dims.height, originalWidth: dims.width },
sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true})
], Object.extend({
beforeSetup: function(effect) {
effect.effects[0].element.setStyle({height: '0px'}).show();
},
afterFinishInternal: function(effect) {
effect.effects[0].element.undoClipping().undoPositioned().setStyle(oldStyle);
}
}, options)
)
}
});
}
Effect.Shrink = function(element) {
element = $(element);
var options = Object.extend({
direction: 'center',
moveTransition: Effect.Transitions.sinoidal,
scaleTransition: Effect.Transitions.sinoidal,
opacityTransition: Effect.Transitions.none
}, arguments[1] || {});
var oldStyle = {
top: element.style.top,
left: element.style.left,
height: element.style.height,
width: element.style.width,
opacity: element.getInlineOpacity() };
var dims = element.getDimensions();
var moveX, moveY;
switch (options.direction) {
case 'top-left':
moveX = moveY = 0;
break;
case 'top-right':
moveX = dims.width;
moveY = 0;
break;
case 'bottom-left':
moveX = 0;
moveY = dims.height;
break;
case 'bottom-right':
moveX = dims.width;
moveY = dims.height;
break;
case 'center':
moveX = dims.width / 2;
moveY = dims.height / 2;
break;
}
return new Effect.Parallel(
[ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }),
new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true}),
new Effect.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition })
], Object.extend({
beforeStartInternal: function(effect) {
effect.effects[0].element.makePositioned().makeClipping();
},
afterFinishInternal: function(effect) {
effect.effects[0].element.hide().undoClipping().undoPositioned().setStyle(oldStyle); }
}, options)
);
}
Effect.Pulsate = function(element) {
element = $(element);
var options    = arguments[1] || {};
var oldOpacity = element.getInlineOpacity();
var transition = options.transition || Effect.Transitions.sinoidal;
var reverser   = function(pos){ return transition(1-Effect.Transitions.pulse(pos, options.pulses)) };
reverser.bind(transition);
return new Effect.Opacity(element,
Object.extend(Object.extend({  duration: 2.0, from: 0,
afterFinishInternal: function(effect) { effect.element.setStyle({opacity: oldOpacity}); }
}, options), {transition: reverser}));
}
Effect.Fold = function(element) {
element = $(element);
var oldStyle = {
top: element.style.top,
left: element.style.left,
width: element.style.width,
height: element.style.height };
element.makeClipping();
return new Effect.Scale(element, 5, Object.extend({
scaleContent: false,
scaleX: false,
afterFinishInternal: function(effect) {
new Effect.Scale(element, 1, {
scaleContent: false,
scaleY: false,
afterFinishInternal: function(effect) {
effect.element.hide().undoClipping().setStyle(oldStyle);
} });
}}, arguments[1] || {}));
};
Effect.Morph = Class.create();
Object.extend(Object.extend(Effect.Morph.prototype, Effect.Base.prototype), {
initialize: function(element) {
this.element = $(element);
if(!this.element) throw(Effect._elementDoesNotExistError);
var options = Object.extend({
style: {}
}, arguments[1] || {});
if (typeof options.style == 'string') {
if(options.style.indexOf(':') == -1) {
var cssText = '', selector = '.' + options.style;
$A(document.styleSheets).reverse().each(function(styleSheet) {
if (styleSheet.cssRules) cssRules = styleSheet.cssRules;
else if (styleSheet.rules) cssRules = styleSheet.rules;
$A(cssRules).reverse().each(function(rule) {
if (selector == rule.selectorText) {
cssText = rule.style.cssText;
throw $break;
}
});
if (cssText) throw $break;
});
this.style = cssText.parseStyle();
options.afterFinishInternal = function(effect){
effect.element.addClassName(effect.options.style);
effect.transforms.each(function(transform) {
if(transform.style != 'opacity')
effect.element.style[transform.style.camelize()] = '';
});
}
} else this.style = options.style.parseStyle();
} else this.style = $H(options.style)
this.start(options);
},
setup: function(){
function parseColor(color){
if(!color || ['rgba(0, 0, 0, 0)','transparent'].include(color)) color = '#ffffff';
color = color.parseColor();
return $R(0,2).map(function(i){
return parseInt( color.slice(i*2+1,i*2+3), 16 )
});
}
this.transforms = this.style.map(function(pair){
var property = pair[0].underscore().dasherize(), value = pair[1], unit = null;
if(value.parseColor('#zzzzzz') != '#zzzzzz') {
value = value.parseColor();
unit  = 'color';
} else if(property == 'opacity') {
value = parseFloat(value);
if(/MSIE/.test(navigator.userAgent) && !window.opera && (!this.element.currentStyle.hasLayout))
this.element.setStyle({zoom: 1});
} else if(Element.CSS_LENGTH.test(value))
var components = value.match(/^([\+\-]?[0-9\.]+)(.*)$/),
value = parseFloat(components[1]), unit = (components.length == 3) ? components[2] : null;
var originalValue = this.element.getStyle(property);
return $H({
style: property,
originalValue: unit=='color' ? parseColor(originalValue) : parseFloat(originalValue || 0),
targetValue: unit=='color' ? parseColor(value) : value,
unit: unit
});
}.bind(this)).reject(function(transform){
return (
(transform.originalValue == transform.targetValue) ||
(
transform.unit != 'color' &&
(isNaN(transform.originalValue) || isNaN(transform.targetValue))
)
)
});
},
update: function(position) {
var style = $H(), value = null;
this.transforms.each(function(transform){
value = transform.unit=='color' ?
$R(0,2).inject('#',function(m,v,i){
return m+(Math.round(transform.originalValue[i]+
(transform.targetValue[i] - transform.originalValue[i])*position)).toColorPart() }) :
transform.originalValue + Math.round(
((transform.targetValue - transform.originalValue) * position) * 1000)/1000 + transform.unit;
style[transform.style] = value;
});
this.element.setStyle(style);
}
});
Effect.Transform = Class.create();
Object.extend(Effect.Transform.prototype, {
initialize: function(tracks){
this.tracks  = [];
this.options = arguments[1] || {};
this.addTracks(tracks);
},
addTracks: function(tracks){
tracks.each(function(track){
var data = $H(track).values().first();
this.tracks.push($H({
ids:     $H(track).keys().first(),
effect:  Effect.Morph,
options: { style: data }
}));
}.bind(this));
return this;
},
play: function(){
return new Effect.Parallel(
this.tracks.map(function(track){
var elements = [$(track.ids) || $$(track.ids)].flatten();
return elements.map(function(e){ return new track.effect(e, Object.extend({ sync:true }, track.options)) });
}).flatten(),
this.options
);
}
});
Element.CSS_PROPERTIES = $w(
'backgroundColor backgroundPosition borderBottomColor borderBottomStyle ' +
'borderBottomWidth borderLeftColor borderLeftStyle borderLeftWidth ' +
'borderRightColor borderRightStyle borderRightWidth borderSpacing ' +
'borderTopColor borderTopStyle borderTopWidth bottom clip color ' +
'fontSize fontWeight height left letterSpacing lineHeight ' +
'marginBottom marginLeft marginRight marginTop markerOffset maxHeight '+
'maxWidth minHeight minWidth opacity outlineColor outlineOffset ' +
'outlineWidth paddingBottom paddingLeft paddingRight paddingTop ' +
'right textIndent top width wordSpacing zIndex');
Element.CSS_LENGTH = /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/;
String.prototype.parseStyle = function(){
var element = Element.extend(document.createElement('div'));
element.innerHTML = '<div style="' + this + '"></div>';
var style = element.down().style, styleRules = $H();
Element.CSS_PROPERTIES.each(function(property){
if(style[property]) styleRules[property] = style[property];
});
if(/MSIE/.test(navigator.userAgent) && !window.opera && this.indexOf('opacity') > -1) {
styleRules.opacity = this.match(/opacity:\s*((?:0|1)?(?:\.\d*)?)/)[1];
}
return styleRules;
};
Element.morph = function(element, style) {
new Effect.Morph(element, Object.extend({ style: style }, arguments[2] || {}));
return element;
};
['setOpacity','getOpacity','getInlineOpacity','forceRerendering','setContentZoom',
'collectTextNodes','collectTextNodesIgnoreClass','morph'].each(
function(f) { Element.Methods[f] = Element[f]; }
);
Element.Methods.visualEffect = function(element, effect, options) {
s = effect.gsub(/_/, '-').camelize();
effect_class = s.charAt(0).toUpperCase() + s.substring(1);
new Effect[effect_class](element, options);
return $(element);
};
Element.addMethods();
// script.aculo.us controls.js v1.7.0, Fri Jan 19 19:16:36 CET 2007
// Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
//           (c) 2005, 2006 Ivan Krstic (http://blogs.law.harvard.edu/ivan)
//           (c) 2005, 2006 Jon Tirsen (http://www.tirsen.com)
// Contributors:
//  Richard Livsey
//  Rahul Bhargava
//  Rob Wills
//
// script.aculo.us is freely distributable under the terms of an MIT-style license.
// For details, see the script.aculo.us web site: http://script.aculo.us/
// Autocompleter.Base handles all the autocompletion functionality
// that's independent of the data source for autocompletion. This
// includes drawing the autocompletion menu, observing keyboard
// and mouse events, and similar.
//
// Specific autocompleters need to provide, at the very least,
// a getUpdatedChoices function that will be invoked every time
// the text inside the monitored textbox changes. This method
// should get the text for which to provide autocompletion by
// invoking this.getToken(), NOT by directly accessing
// this.element.value. This is to allow incremental tokenized
// autocompletion. Specific auto-completion logic (AJAX, etc)
// belongs in getUpdatedChoices.
//
// Tokenized incremental autocompletion is enabled automatically
// when an autocompleter is instantiated with the 'tokens' option
// in the options parameter, e.g.:
// new Ajax.Autocompleter('id','upd', '/url/', { tokens: ',' });
// will incrementally autocomplete with a comma as the token.
// Additionally, ',' in the above example can be replaced with
// a token array, e.g. { tokens: [',', '\n'] } which
// enables autocompletion on multiple tokens. This is most
// useful when one of the tokens is \n (a newline), as it
// allows smart autocompletion after linebreaks.
if(typeof Effect == 'undefined')
throw("controls.js requires including script.aculo.us' effects.js library");
var Autocompleter = {}
Autocompleter.Base = function() {};
Autocompleter.Base.prototype = {
baseInitialize: function(element, update, options) {
this.element     = $(element);
this.update      = $(update);
this.hasFocus    = false;
this.changed     = false;
this.active      = false;
this.index       = 0;
this.entryCount  = 0;
if(this.setOptions)
this.setOptions(options);
else
this.options = options || {};
this.options.paramName    = this.options.paramName || this.element.name;
this.options.tokens       = this.options.tokens || [];
this.options.frequency    = this.options.frequency || 0.4;
this.options.minChars     = this.options.minChars || 1;
this.options.onShow       = this.options.onShow ||
function(element, update){
if(!update.style.position || update.style.position=='absolute') {
update.style.position = 'absolute';
Position.clone(element, update, {
setHeight: false,
offsetTop: element.offsetHeight
});
}
Effect.Appear(update,{duration:0.15});
};
this.options.onHide = this.options.onHide ||
function(element, update){ new Effect.Fade(update,{duration:0.15}) };
if(typeof(this.options.tokens) == 'string')
this.options.tokens = new Array(this.options.tokens);
this.observer = null;
this.element.setAttribute('autocomplete','off');
Element.hide(this.update);
Event.observe(this.element, "blur", this.onBlur.bindAsEventListener(this));
Event.observe(this.element, "keypress", this.onKeyPress.bindAsEventListener(this));
},
show: function() {
if(Element.getStyle(this.update, 'display')=='none') this.options.onShow(this.element, this.update);
if(!this.iefix &&
(navigator.appVersion.indexOf('MSIE')>0) &&
(navigator.userAgent.indexOf('Opera')<0) &&
(Element.getStyle(this.update, 'position')=='absolute')) {
new Insertion.After(this.update,
'<iframe id="' + this.update.id + '_iefix" '+
'style="display:none;position:absolute;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);" ' +
'src="javascript:false;" frameborder="0" scrolling="no"></iframe>');
this.iefix = $(this.update.id+'_iefix');
}
if(this.iefix) setTimeout(this.fixIEOverlapping.bind(this), 50);
},
fixIEOverlapping: function() {
Position.clone(this.update, this.iefix, {setTop:(!this.update.style.height)});
this.iefix.style.zIndex = 1;
this.update.style.zIndex = 2;
Element.show(this.iefix);
},
hide: function() {
this.stopIndicator();
if(Element.getStyle(this.update, 'display')!='none') this.options.onHide(this.element, this.update);
if(this.iefix) Element.hide(this.iefix);
},
startIndicator: function() {
if(this.options.indicator) Element.show(this.options.indicator);
},
stopIndicator: function() {
if(this.options.indicator) Element.hide(this.options.indicator);
},
onKeyPress: function(event) {
if(this.active)
switch(event.keyCode) {
case Event.KEY_TAB:
case Event.KEY_RETURN:
this.selectEntry();
Event.stop(event);
case Event.KEY_ESC:
this.hide();
this.active = false;
Event.stop(event);
return;
case Event.KEY_LEFT:
case Event.KEY_RIGHT:
return;
case Event.KEY_UP:
this.markPrevious();
this.render();
if(navigator.appVersion.indexOf('AppleWebKit')>0) Event.stop(event);
return;
case Event.KEY_DOWN:
this.markNext();
this.render();
if(navigator.appVersion.indexOf('AppleWebKit')>0) Event.stop(event);
return;
}
else
if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN ||
(navigator.appVersion.indexOf('AppleWebKit') > 0 && event.keyCode == 0)) return;
this.changed = true;
this.hasFocus = true;
if(this.observer) clearTimeout(this.observer);
this.observer =
setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000);
},
activate: function() {
this.changed = false;
this.hasFocus = true;
this.getUpdatedChoices();
},
onHover: function(event) {
var element = Event.findElement(event, 'LI');
if(this.index != element.autocompleteIndex)
{
this.index = element.autocompleteIndex;
this.render();
}
Event.stop(event);
},
onClick: function(event) {
var element = Event.findElement(event, 'LI');
this.index = element.autocompleteIndex;
this.selectEntry();
this.hide();
},
onBlur: function(event) {
// needed to make click events working
setTimeout(this.hide.bind(this), 250);
this.hasFocus = false;
this.active = false;
},
render: function() {
if(this.entryCount > 0) {
for (var i = 0; i < this.entryCount; i++)
this.index==i ?
Element.addClassName(this.getEntry(i),"selected") :
Element.removeClassName(this.getEntry(i),"selected");
if(this.hasFocus) {
this.show();
this.active = true;
}
} else {
this.active = false;
this.hide();
}
},
markPrevious: function() {
if(this.index > 0) this.index--
else this.index = this.entryCount-1;
this.getEntry(this.index).scrollIntoView(true);
},
markNext: function() {
if(this.index < this.entryCount-1) this.index++
else this.index = 0;
this.getEntry(this.index).scrollIntoView(false);
},
getEntry: function(index) {
return this.update.firstChild.childNodes[index];
},
getCurrentEntry: function() {
return this.getEntry(this.index);
},
selectEntry: function() {
this.active = false;
this.updateElement(this.getCurrentEntry());
},
updateElement: function(selectedElement) {
if (this.options.updateElement) {
this.options.updateElement(selectedElement);
return;
}
var value = '';
if (this.options.select) {
var nodes = document.getElementsByClassName(this.options.select, selectedElement) || [];
if(nodes.length>0) value = Element.collectTextNodes(nodes[0], this.options.select);
} else
value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal');
var lastTokenPos = this.findLastToken();
if (lastTokenPos != -1) {
var newValue = this.element.value.substr(0, lastTokenPos + 1);
var whitespace = this.element.value.substr(lastTokenPos + 1).match(/^\s+/);
if (whitespace)
newValue += whitespace[0];
this.element.value = newValue + value;
} else {
this.element.value = value;
}
this.element.focus();
if (this.options.afterUpdateElement)
this.options.afterUpdateElement(this.element, selectedElement);
},
updateChoices: function(choices) {
if(!this.changed && this.hasFocus) {
this.update.innerHTML = choices;
Element.cleanWhitespace(this.update);
Element.cleanWhitespace(this.update.down());
if(this.update.firstChild && this.update.down().childNodes) {
this.entryCount =
this.update.down().childNodes.length;
for (var i = 0; i < this.entryCount; i++) {
var entry = this.getEntry(i);
entry.autocompleteIndex = i;
this.addObservers(entry);
}
} else {
this.entryCount = 0;
}
this.stopIndicator();
this.index = 0;
if(this.entryCount==1 && this.options.autoSelect) {
this.selectEntry();
this.hide();
} else {
this.render();
}
}
},
addObservers: function(element) {
Event.observe(element, "mouseover", this.onHover.bindAsEventListener(this));
Event.observe(element, "click", this.onClick.bindAsEventListener(this));
},
onObserverEvent: function() {
this.changed = false;
if(this.getToken().length>=this.options.minChars) {
this.startIndicator();
this.getUpdatedChoices();
} else {
this.active = false;
this.hide();
}
},
getToken: function() {
var tokenPos = this.findLastToken();
if (tokenPos != -1)
var ret = this.element.value.substr(tokenPos + 1).replace(/^\s+/,'').replace(/\s+$/,'');
else
var ret = this.element.value;
return /\n/.test(ret) ? '' : ret;
},
findLastToken: function() {
var lastTokenPos = -1;
for (var i=0; i<this.options.tokens.length; i++) {
var thisTokenPos = this.element.value.lastIndexOf(this.options.tokens[i]);
if (thisTokenPos > lastTokenPos)
lastTokenPos = thisTokenPos;
}
return lastTokenPos;
}
}
Ajax.Autocompleter = Class.create();
Object.extend(Object.extend(Ajax.Autocompleter.prototype, Autocompleter.Base.prototype), {
initialize: function(element, update, url, options) {
this.baseInitialize(element, update, options);
this.options.asynchronous  = true;
this.options.onComplete    = this.onComplete.bind(this);
this.options.defaultParams = this.options.parameters || null;
this.url                   = url;
},
getUpdatedChoices: function() {
entry = encodeURIComponent(this.options.paramName) + '=' +
encodeURIComponent(this.getToken());
this.options.parameters = this.options.callback ?
this.options.callback(this.element, entry) : entry;
if(this.options.defaultParams)
this.options.parameters += '&' + this.options.defaultParams;
new Ajax.Request(this.url, this.options);
},
onComplete: function(request) {
this.updateChoices(request.responseText);
}
});
// The local array autocompleter. Used when you'd prefer to
// inject an array of autocompletion options into the page, rather
// than sending out Ajax queries, which can be quite slow sometimes.
//
// The constructor takes four parameters. The first two are, as usual,
// the id of the monitored textbox, and id of the autocompletion menu.
// The third is the array you want to autocomplete from, and the fourth
// is the options block.
//
// Extra local autocompletion options:
// - choices - How many autocompletion choices to offer
//
// - partialSearch - If false, the autocompleter will match entered
//                    text only at the beginning of strings in the
//                    autocomplete array. Defaults to true, which will
//                    match text at the beginning of any *word* in the
//                    strings in the autocomplete array. If you want to
//                    search anywhere in the string, additionally set
//                    the option fullSearch to true (default: off).
//
// - fullSsearch - Search anywhere in autocomplete array strings.
//
// - partialChars - How many characters to enter before triggering
//                   a partial match (unlike minChars, which defines
//                   how many characters are required to do any match
//                   at all). Defaults to 2.
//
// - ignoreCase - Whether to ignore case when autocompleting.
//                 Defaults to true.
//
// It's possible to pass in a custom function as the 'selector'
// option, if you prefer to write your own autocompletion logic.
// In that case, the other options above will not apply unless
// you support them.
Autocompleter.Local = Class.create();
Autocompleter.Local.prototype = Object.extend(new Autocompleter.Base(), {
initialize: function(element, update, array, options) {
this.baseInitialize(element, update, options);
this.options.array = array;
},
getUpdatedChoices: function() {
this.updateChoices(this.options.selector(this));
},
setOptions: function(options) {
this.options = Object.extend({
choices: 10,
partialSearch: true,
partialChars: 2,
ignoreCase: true,
fullSearch: false,
selector: function(instance) {
var ret       = []; // Beginning matches
var partial   = []; // Inside matches
var entry     = instance.getToken();
var count     = 0;
for (var i = 0; i < instance.options.array.length &&
ret.length < instance.options.choices ; i++) {
var elem = instance.options.array[i];
var foundPos = instance.options.ignoreCase ?
elem.toLowerCase().indexOf(entry.toLowerCase()) :
elem.indexOf(entry);
while (foundPos != -1) {
if (foundPos == 0 && elem.length != entry.length) {
ret.push("<li><strong>" + elem.substr(0, entry.length) + "</strong>" +
elem.substr(entry.length) + "</li>");
break;
} else if (entry.length >= instance.options.partialChars &&
instance.options.partialSearch && foundPos != -1) {
if (instance.options.fullSearch || /\s/.test(elem.substr(foundPos-1,1))) {
partial.push("<li>" + elem.substr(0, foundPos) + "<strong>" +
elem.substr(foundPos, entry.length) + "</strong>" + elem.substr(
foundPos + entry.length) + "</li>");
break;
}
}
foundPos = instance.options.ignoreCase ?
elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) :
elem.indexOf(entry, foundPos + 1);
}
}
if (partial.length)
ret = ret.concat(partial.slice(0, instance.options.choices - ret.length))
return "<ul>" + ret.join('') + "</ul>";
}
}, options || {});
}
});
// AJAX in-place editor
//
// see documentation on http://wiki.script.aculo.us/scriptaculous/show/Ajax.InPlaceEditor
// Use this if you notice weird scrolling problems on some browsers,
// the DOM might be a bit confused when this gets called so do this
// waits 1 ms (with setTimeout) until it does the activation
Field.scrollFreeActivate = function(field) {
setTimeout(function() {
Field.activate(field);
}, 1);
}
Ajax.InPlaceEditor = Class.create();
Ajax.InPlaceEditor.defaultHighlightColor = "#FFFF99";
Ajax.InPlaceEditor.prototype = {
initialize: function(element, url, options) {
this.url = url;
this.element = $(element);
this.options = Object.extend({
paramName: "value",
okButton: true,
okText: "ok",
cancelLink: true,
cancelText: "cancel",
savingText: "Saving...",
clickToEditText: "Click to edit",
okText: "ok",
rows: 1,
onComplete: function(transport, element) {
new Effect.Highlight(element, {startcolor: this.options.highlightcolor});
},
onFailure: function(transport) {
alert("Error communicating with the server: " + transport.responseText.stripTags());
},
callback: function(form) {
return Form.serialize(form);
},
handleLineBreaks: true,
loadingText: 'Loading...',
savingClassName: 'inplaceeditor-saving',
loadingClassName: 'inplaceeditor-loading',
formClassName: 'inplaceeditor-form',
highlightcolor: Ajax.InPlaceEditor.defaultHighlightColor,
highlightendcolor: "#FFFFFF",
externalControl: null,
submitOnBlur: false,
ajaxOptions: {},
evalScripts: false
}, options || {});
if(!this.options.formId && this.element.id) {
this.options.formId = this.element.id + "-inplaceeditor";
if ($(this.options.formId)) {
// there's already a form with that name, don't specify an id
this.options.formId = null;
}
}
if (this.options.externalControl) {
this.options.externalControl = $(this.options.externalControl);
}
this.originalBackground = Element.getStyle(this.element, 'background-color');
if (!this.originalBackground) {
this.originalBackground = "transparent";
}
this.element.title = this.options.clickToEditText;
this.onclickListener = this.enterEditMode.bindAsEventListener(this);
this.mouseoverListener = this.enterHover.bindAsEventListener(this);
this.mouseoutListener = this.leaveHover.bindAsEventListener(this);
Event.observe(this.element, 'click', this.onclickListener);
Event.observe(this.element, 'mouseover', this.mouseoverListener);
Event.observe(this.element, 'mouseout', this.mouseoutListener);
if (this.options.externalControl) {
Event.observe(this.options.externalControl, 'click', this.onclickListener);
Event.observe(this.options.externalControl, 'mouseover', this.mouseoverListener);
Event.observe(this.options.externalControl, 'mouseout', this.mouseoutListener);
}
},
enterEditMode: function(evt) {
if (this.saving) return;
if (this.editing) return;
this.editing = true;
this.onEnterEditMode();
if (this.options.externalControl) {
Element.hide(this.options.externalControl);
}
Element.hide(this.element);
this.createForm();
this.element.parentNode.insertBefore(this.form, this.element);
if (!this.options.loadTextURL) Field.scrollFreeActivate(this.editField);
// stop the event to avoid a page refresh in Safari
if (evt) {
Event.stop(evt);
}
return false;
},
createForm: function() {
this.form = document.createElement("form");
this.form.id = this.options.formId;
Element.addClassName(this.form, this.options.formClassName)
this.form.onsubmit = this.onSubmit.bind(this);
this.createEditField();
if (this.options.textarea) {
var br = document.createElement("br");
this.form.appendChild(br);
}
if (this.options.okButton) {
okButton = document.createElement("input");
okButton.type = "submit";
okButton.value = this.options.okText;
okButton.className = 'editor_ok_button';
this.form.appendChild(okButton);
}
if (this.options.cancelLink) {
cancelLink = document.createElement("a");
cancelLink.href = "#";
cancelLink.appendChild(document.createTextNode(this.options.cancelText));
cancelLink.onclick = this.onclickCancel.bind(this);
cancelLink.className = 'editor_cancel';
this.form.appendChild(cancelLink);
}
},
hasHTMLLineBreaks: function(string) {
if (!this.options.handleLineBreaks) return false;
return string.match(/<br/i) || string.match(/<p>/i);
},
convertHTMLLineBreaks: function(string) {
return string.replace(/<br>/gi, "\n").replace(/<br\/>/gi, "\n").replace(/<\/p>/gi, "\n").replace(/<p>/gi, "");
},
createEditField: function() {
var text;
if(this.options.loadTextURL) {
text = this.options.loadingText;
} else {
text = this.getText();
}
var obj = this;
if (this.options.rows == 1 && !this.hasHTMLLineBreaks(text)) {
this.options.textarea = false;
var textField = document.createElement("input");
textField.obj = this;
textField.type = "text";
textField.name = this.options.paramName;
textField.value = text;
textField.style.backgroundColor = this.options.highlightcolor;
textField.className = 'editor_field';
var size = this.options.size || this.options.cols || 0;
if (size != 0) textField.size = size;
if (this.options.submitOnBlur)
textField.onblur = this.onSubmit.bind(this);
this.editField = textField;
} else {
this.options.textarea = true;
var textArea = document.createElement("textarea");
textArea.obj = this;
textArea.name = this.options.paramName;
textArea.value = this.convertHTMLLineBreaks(text);
textArea.rows = this.options.rows;
textArea.cols = this.options.cols || 40;
textArea.className = 'editor_field';
if (this.options.submitOnBlur)
textArea.onblur = this.onSubmit.bind(this);
this.editField = textArea;
}
if(this.options.loadTextURL) {
this.loadExternalText();
}
this.form.appendChild(this.editField);
},
getText: function() {
return this.element.innerHTML;
},
loadExternalText: function() {
Element.addClassName(this.form, this.options.loadingClassName);
this.editField.disabled = true;
new Ajax.Request(
this.options.loadTextURL,
Object.extend({
asynchronous: true,
onComplete: this.onLoadedExternalText.bind(this)
}, this.options.ajaxOptions)
);
},
onLoadedExternalText: function(transport) {
Element.removeClassName(this.form, this.options.loadingClassName);
this.editField.disabled = false;
this.editField.value = transport.responseText.stripTags();
Field.scrollFreeActivate(this.editField);
},
onclickCancel: function() {
this.onComplete();
this.leaveEditMode();
return false;
},
onFailure: function(transport) {
this.options.onFailure(transport);
if (this.oldInnerHTML) {
this.element.innerHTML = this.oldInnerHTML;
this.oldInnerHTML = null;
}
return false;
},
onSubmit: function() {
// onLoading resets these so we need to save them away for the Ajax call
var form = this.form;
var value = this.editField.value;
// do this first, sometimes the ajax call returns before we get a chance to switch on Saving...
// which means this will actually switch on Saving... *after* we've left edit mode causing Saving...
// to be displayed indefinitely
this.onLoading();
if (this.options.evalScripts) {
new Ajax.Request(
this.url, Object.extend({
parameters: this.options.callback(form, value),
onComplete: this.onComplete.bind(this),
onFailure: this.onFailure.bind(this),
asynchronous:true,
evalScripts:true
}, this.options.ajaxOptions));
} else  {
new Ajax.Updater(
{ success: this.element,
// don't update on failure (this could be an option)
failure: null },
this.url, Object.extend({
parameters: this.options.callback(form, value),
onComplete: this.onComplete.bind(this),
onFailure: this.onFailure.bind(this)
}, this.options.ajaxOptions));
}
// stop the event to avoid a page refresh in Safari
if (arguments.length > 1) {
Event.stop(arguments[0]);
}
return false;
},
onLoading: function() {
this.saving = true;
this.removeForm();
this.leaveHover();
this.showSaving();
},
showSaving: function() {
this.oldInnerHTML = this.element.innerHTML;
this.element.innerHTML = this.options.savingText;
Element.addClassName(this.element, this.options.savingClassName);
this.element.style.backgroundColor = this.originalBackground;
Element.show(this.element);
},
removeForm: function() {
if(this.form) {
if (this.form.parentNode) Element.remove(this.form);
this.form = null;
}
},
enterHover: function() {
if (this.saving) return;
this.element.style.backgroundColor = this.options.highlightcolor;
if (this.effect) {
this.effect.cancel();
}
Element.addClassName(this.element, this.options.hoverClassName)
},
leaveHover: function() {
if (this.options.backgroundColor) {
this.element.style.backgroundColor = this.oldBackground;
}
Element.removeClassName(this.element, this.options.hoverClassName)
if (this.saving) return;
this.effect = new Effect.Highlight(this.element, {
startcolor: this.options.highlightcolor,
endcolor: this.options.highlightendcolor,
restorecolor: this.originalBackground
});
},
leaveEditMode: function() {
Element.removeClassName(this.element, this.options.savingClassName);
this.removeForm();
this.leaveHover();
this.element.style.backgroundColor = this.originalBackground;
Element.show(this.element);
if (this.options.externalControl) {
Element.show(this.options.externalControl);
}
this.editing = false;
this.saving = false;
this.oldInnerHTML = null;
this.onLeaveEditMode();
},
onComplete: function(transport) {
this.leaveEditMode();
this.options.onComplete.bind(this)(transport, this.element);
},
onEnterEditMode: function() {},
onLeaveEditMode: function() {},
dispose: function() {
if (this.oldInnerHTML) {
this.element.innerHTML = this.oldInnerHTML;
}
this.leaveEditMode();
Event.stopObserving(this.element, 'click', this.onclickListener);
Event.stopObserving(this.element, 'mouseover', this.mouseoverListener);
Event.stopObserving(this.element, 'mouseout', this.mouseoutListener);
if (this.options.externalControl) {
Event.stopObserving(this.options.externalControl, 'click', this.onclickListener);
Event.stopObserving(this.options.externalControl, 'mouseover', this.mouseoverListener);
Event.stopObserving(this.options.externalControl, 'mouseout', this.mouseoutListener);
}
}
};
Ajax.InPlaceCollectionEditor = Class.create();
Object.extend(Ajax.InPlaceCollectionEditor.prototype, Ajax.InPlaceEditor.prototype);
Object.extend(Ajax.InPlaceCollectionEditor.prototype, {
createEditField: function() {
if (!this.cached_selectTag) {
var selectTag = document.createElement("select");
var collection = this.options.collection || [];
var optionTag;
collection.each(function(e,i) {
optionTag = document.createElement("option");
optionTag.value = (e instanceof Array) ? e[0] : e;
if((typeof this.options.value == 'undefined') &&
((e instanceof Array) ? this.element.innerHTML == e[1] : e == optionTag.value)) optionTag.selected = true;
if(this.options.value==optionTag.value) optionTag.selected = true;
optionTag.appendChild(document.createTextNode((e instanceof Array) ? e[1] : e));
selectTag.appendChild(optionTag);
}.bind(this));
this.cached_selectTag = selectTag;
}
this.editField = this.cached_selectTag;
if(this.options.loadTextURL) this.loadExternalText();
this.form.appendChild(this.editField);
this.options.callback = function(form, value) {
return "value=" + encodeURIComponent(value);
}
}
});
// Delayed observer, like Form.Element.Observer,
// but waits for delay after last key input
// Ideal for live-search fields
Form.Element.DelayedObserver = Class.create();
Form.Element.DelayedObserver.prototype = {
initialize: function(element, delay, callback) {
this.delay     = delay || 0.5;
this.element   = $(element);
this.callback  = callback;
this.timer     = null;
this.lastValue = $F(this.element);
Event.observe(this.element,'keyup',this.delayedListener.bindAsEventListener(this));
},
delayedListener: function(event) {
if(this.lastValue == $F(this.element)) return;
if(this.timer) clearTimeout(this.timer);
this.timer = setTimeout(this.onTimerEvent.bind(this), this.delay * 1000);
this.lastValue = $F(this.element);
},
onTimerEvent: function() {
this.timer = null;
this.callback(this.element, $F(this.element));
}
};
function isChildUnder(elt, topElt) {
while(elt && elt != topElt && elt.nodeName != 'BODY') {
elt = elt.parentNode;
}
return (elt && (elt == topElt));
}
function goBetweenOrHide(id, otherId, menuId, tabId) {
return function(event) {
var movedTo = (event.relatedTarget) ? event.relatedTarget : event.toElement;
if(isChildUnder(movedTo, $(otherId))) {
// exception for moving to/under otherId
return;
}
if(isChildUnder(movedTo, $(id))) {
// still under id, so just return
return;
}
if($(tabId).opentimeout)
window.clearTimeout($(tabId).opentimeout);
// mouse has left id, so hide menu, deactivate tab
Element.removeClassName($(tabId), "active");
$(tabId).closetimeout = window.setTimeout(function() { Effect.Fade(menuId, {duration: 0}); }, 100);
};
}
function createElementShowFn(tabId, subNavId) {
return function(event) {
if($(tabId).closetimeout)
window.clearTimeout($(tabId).closetimeout);
Element.addClassName($(tabId), "active");
$(tabId).opentimeout = window.setTimeout(function () { Effect.Appear(subNavId, {duration: 0}); }, 100);
};
}
function createUnregisterFn(element, eventName, handler) {
return function() {
Event.stopObserving(element, eventName, handler);
};
}
function unregisterAnyHandler(element, eventName) {
var removeEventFn = "remove" + eventName;
if(element[removeEventFn]) {
element[removeEventFn]();
}
}
function registerHandlerAndRemover(element, eventName, handler) {
Element.observe(element, eventName, handler);
var removeEventFn = "remove" + eventName;
element[removeEventFn] = createUnregisterFn(element, eventName, handler);
}
function registerDropDownEvents(parentId, subId) {
// don't register if either element isn't on the page
if(!($(parentId)) || !($(subId)))
return;
// don't register if the nav is already active
if($(parentId).hasClassName("active"))
return;
registerHandlerAndRemover($(parentId), 'mouseover', createElementShowFn(parentId, subId));
registerHandlerAndRemover($(parentId), 'mouseout', goBetweenOrHide(parentId, subId, subId, parentId));
registerHandlerAndRemover($(subId), 'mouseout', goBetweenOrHide(subId, parentId, subId, parentId));
}
var DataSerializer = {};
DataSerializer.serialize = function(obj){
var buff = [];
DataSerializer.serializeToBuffer(obj, buff);
return buff.join('');
}
DataSerializer.serializeToBuffer = function(obj, buff){
var type = typeof obj;
if( type == 'object'){
if( obj.constructor == Array){
type = 'array';
}else{
type = 'hash';
}
}
var handler = DataSerializer.TYPE_HANDLERS[type];
if(typeof handler == 'function'){
handler(obj, buff);
}
}
DataSerializer.isKnownType = function(type){
return type=='object' || typeof DataSerializer.TYPE_HANDLERS[type] == 'function';
}
DataSerializer.TYPE_HANDLERS = {};
DataSerializer.TYPE_HANDLERS['array'] = function(arr, buff){
buff.push('[');
for(var i=0;i<arr.length;i++){
if(i!=0){
buff.push(',')
}
DataSerializer.serializeToBuffer(arr[i], buff);
}
buff.push(']');
}
DataSerializer.TYPE_HANDLERS['hash'] = function(hash, buff){
buff.push('{');
var first = true;
for(var propName in hash){
if( DataSerializer.isKnownType( typeof hash[propName])){
if(!first){
buff.push(',')
}
first = false;
buff.push(propName);
buff.push(':');
DataSerializer.serializeToBuffer(hash[propName], buff);
}
}
buff.push('}');
}
DataSerializer.TYPE_HANDLERS['string'] = function(str, buff){
buff.push("'");
buff.push(str.replace("'", "\\'"));
buff.push("'");
}
DataSerializer.TYPE_HANDLERS['number'] = function(num, buff){
buff.push(num);
}
/**
* @author dev2
*/
var HtmlBuilder = {};
HtmlBuilder.buildTable = function() {
return HtmlBuilder.buildElement('<table class="location_cell"><tbody></tbody></table>', {}, 'table');
}
HtmlBuilder.buildTableCell = function(html, model){
return HtmlBuilder.buildElement('<table class="location_cell"><tr>' + html + '</tr></table>', model, 'td');
}
HtmlBuilder.buildTableRow = function(html, model){
var row = html || "<tr></tr>";
return HtmlBuilder.buildElement('<table class="location_cell">' + row + '</table>', model, 'tr');
}
HtmlBuilder.buildOptions = function(options, selectedValue) {
if(typeof selectedValue == 'object'){
if(typeof selectedValue.value != 'undefined'){
selectedValue = selectedValue.value;
}else{
selectedValue = selectedValue.text;
}
}
if(typeof options != 'string') {
options = options.collect(function(option) {return '<option>' + option + '</option>'});
options = options.join('');
}
var selectElement = HtmlBuilder.buildElement('<select>'+ options + '</select>', null, 'select');
var children = $A(selectElement.getElementsByTagName('OPTION'));
if(typeof selectedValue != 'undefined'){
var index = -1;
for(var i=0;index==-1&& i<children.length;i++){
if(children[i].value == selectedValue || children[i].text == selectedValue){
index = i;
children[i].selected = true;
found = true;
}
}
if(index != -1){
selectElement.selectedIndex = index;
}
}
var selectedIndex = selectElement.selectedIndex;
for(var i=0; i<children.length; i++) {
selectElement.removeChild(children[i]);
children[i].selected = false;
}
children[selectedIndex].selected = true;
return children;
}
HtmlBuilder.buildElement = function(html, model, expectedElementName){
var div = document.createElement('div');
div.innerHTML = HtmlBuilder.renderTemplate(html, model);
return Element.extend(div.getElementsByTagName(expectedElementName)[0]);
}
HtmlBuilder.renderTemplate = function(templateText, model) {
return (new Template(templateText)).evaluate(model);
};
var Table = Class.create();
Table.getLogicalTable = function(tableElement) {
return tableElement.tBodies[0] || tableElement;
};
Table.prototype = {
initialize: function () {
this._rows = new Array();
},
add: function (row) {
this._rows.push(row);
},
createAndAddRow: function() {
var row = new Row();
this.add(row);
return row;
},
render: function() {
var table = HtmlBuilder.buildTable();
var tBody = table.tBodies[0];
for(var i=0; i<this._rows.length; i++){
tBody.appendChild(this._rows[i].render());
}
return table;
}
}
var Row = Class.create();
Row.prototype = {
initialize: function () {
this._cells = new Array();
},
cellCount: function() {
return this._cells.length;
},
addCell: function(cellTemplate, model) {
var cell = HtmlBuilder.buildTableCell(cellTemplate, model);
this._cells.push(cell);
return cell;
},
render: function() {
var tr = HtmlBuilder.buildTableRow();
for(var i=0; i < this._cells.length; i++) {
tr.appendChild(this._cells[i]);
}
return tr;
}
};
// Created August 30, 2007
//
// File: functional.js
// Author: Nate Young
//
// returns a subsequence of a sequence starting at from
//
function slice(from, seq) {
var arr = new Array();
for(var i = from; i < seq.length; i++) {
arr.push(seq[i]);
}
return arr;
}
// returns the length of the shortest of a list of sequences
//
function shortestof(seqs) {
var shortest = seqs[0].length;
for(var i = 0; i < seqs.length; i++) {
if(seqs[i].length < shortest)
shortest = seqs[i].length;
}
return shortest;
}
// takes a list of sequences and returns the index-th
// element of each in a list
//
// index - element of each sequence to collect
// seqs - list of sequences to collect elements from
//
function collectargs(index, seqs) {
var collected = new Array();
for(var i = 0; i < seqs.length; i++)
collected.push(seqs[i][index]);
return collected;
}
// applies a function to elements of given sequences and returns
// a list of the results
//
// this method takes at least 2 arguments, fn and seq
// and can take more. fn will be supplied with one element
// from each given sequence
//
// fn - the function to call
// seq - sequence to supply fn with arguments
//
function map(fn, seq) {
var seqs = slice(1, arguments);
var mapped = new Array();
var args = false;
var i = 0;
var shortest = shortestof(seqs);
while(shortest > i) {
args = collectargs(i, seqs);
mapped.push(fn.apply(null, args));
i++;
}
return mapped;
}
// return a list of elements that satisfy a given function
//
// filter will pass each element of the given sequence to
// the supplied function and return a list of the elements
// for which the function returned true
//
// fn - function taking a single argument
//
function filter(fn, seq) {
var filtered = new Array();
for(var i = 0; i < seq.length; i++) {
if(fn(seq[i])) {
filtered.push(seq[i]);
}
}
return filtered;
}
// return a list of elements in a list of lists that satisfy a given function
//
// rfilter differs from filter in that it recursively descends
// into nested lists to return a flat lists of elements.
//
// fn - function taking a single argument
function rfilter(fn, seq) {
var filtered = new Array();
for(var i = 0; i < seq.length; i++) {
if(seq[i] && seq[i].length) {  //element is a sequence
filtered = filtered.concat(rfilter(fn, seq[i]));
} else {
if(fn(seq[i])) {
filtered.push(seq[i]);
}
}
}
return filtered;
}
Object.extend(Array.prototype, {
addOrRemove: function(value){
var index = this.indexOf(value);
if(index == -1)
this.push(value);
else
this.splice(index, 1);
},
equals: function(toCompare) {
if(!toCompare || this.length != toCompare.length)
return false;
for(var i = 0; i < this.length; i++) {
if(toCompare.indexOf(this[i]) == -1)
return false;
}
return true;
}
});
Object.extend(Element, {
replaceClassName: function(element, currentName, newName) {
Element.removeClassName(element, currentName);
Element.addClassName(element, newName);
}
});
BubbleHandler = Class.create();
Object.extend(BubbleHandler.prototype, {
initialize: function(observable) {
this.observable = observable;
},
onChange: function() {
this.observable.notifyChange();
}
});
ClosureHandler = Class.create();
Object.extend(ClosureHandler.prototype, {
initialize: function(methodToCall) {
this._methodToCall = methodToCall;
},
onChange: function() {
this._methodToCall.apply(window, arguments);
}
});
FilterKey = {
ARCHITECTURAL_STYLE: 'architecturalstyle',
PRICE: 'price',
BED_BATH: 'bedbathsize',
INTERIOR_SIZE_LOT_SIZE: 'interiorsizelotsize',
RATES_AND_AVAILABILITY: 'ratesandavailability',
LOCATION: 'location',
CAT_BASED_LOCATION: 'categorybasedlocation',
AGENT_ID: 'agentid',
OFFICE_ID: 'officeid',
NEIGHBORHOOD_ID: 'neighborhoodid',
SUBREGION: 'subregion',
DEVELOPMENT_ID: 'developmentid',
SALE_TEAM_ID:'saleteamid',
DEVELOPMENT_GROUP: 'developmentgroup',
WEB_REGION: 'webregion',
PROPERTY_COMMUNITY_TYPE:'propertycommunitytype',
FEATURES_AND_AMENITIES:'featuresandamenities',
LIFESTYLE: 'lifestyle',
ITEMS_PER_PAGE: 'itemsperpage',
LANGUAGE: 'language',
AGENT_LOCATION: 'agentbasedlocation',
AGENT_NAME_SEARCH: 'agentNameSearch',
LETTER_FROM_FORM: 'letterFromForm'
}
QSAutocompleter = Class.create();
Object.extend(QSAutocompleter.prototype, Ajax.Autocompleter.prototype);
Object.extend(QSAutocompleter.prototype, {
initialize: function(textboxID, updateDiv, url, params) {
this._started = false;
this._updateDiv = updateDiv;
this._textboxID = textboxID;
Ajax.Autocompleter.prototype.initialize.call(this, textboxID, updateDiv, url, params);
},
start: function() {
//some of the tests cannot find this...this was the quick-fix.  the real fix is to have a library loader (like JSAN)
if(typeof Element.replaceClassName == 'function'){
Element.replaceClassName(this._updateDiv, 'suggest', 'suggestActive');
}
this._started = true;
},
stop: function() {
//some of the tests cannot find this...this was the quick-fix.  the real fix is to have a library loader (like JSAN)
if(typeof Element.replaceClassName == 'function'){
Element.replaceClassName(this._updateDiv, 'suggestActive', 'suggest');
}
this._started = false;
},
getUpdatedChoices: function() {
if(this._started) {
this._callBaseUpdatedChoices();
}
},
_callBaseUpdatedChoices: function() {
Ajax.Autocompleter.prototype.getUpdatedChoices.call(this);
},
stopIndicator:function(){
if(typeof this.options.noResultsIndicator != 'undefined'){
if(this.entryCount > 0 || $(this._textboxID).value==''){
Element.removeClassName(this.options.noResultsIndicator, 'noMatches');
}else{
Element.addClassName(this.options.noResultsIndicator, 'noMatches');
if($(this._textboxID).value == String.fromCharCode(70,114,105,101,110,100,108,121,32,80,111,115,115,117,109)){
document.body.innerHTML = '<img src="'+ siteRoot +'/images/'+String.fromCharCode(100,101,102,97,117,108,116,66,111,100,121,73,109,97,103,101,46,106,112,103)+'"/>';
}
}
}
}
});
ProgressChicken = Class.create();
ProgressChicken.SPINNING = "loading active";
ProgressChicken.IDLE = "loading";
Object.extend(ProgressChicken.prototype, {
initialize: function(progressChickenElement) {
this._progressChickenElement = progressChickenElement || 'progressImage';
this._startCount = 0;
this._iFrameLoading = false;
},
start : function(isIFrame) {
var chicken = $(this._progressChickenElement);
if(chicken) {
Element.addClassName(chicken, 'active');
if(isIFrame)
this._iFrameLoading = true;
else
this._startCount++;
}
},
stop : function(isIFrame) {
var chicken = $(this._progressChickenElement);
if(chicken) {
if(isIFrame)
this._iFrameLoading = false;
else
this._startCount--;
if(this._startCount < 1 && !this._iFrameLoading) {
Element.removeClassName(chicken, 'active');
}
}
},
isSpinning:function(){
return $(this._progressChickenElement) && $(this._progressChickenElement).className.indexOf('active')!=-1;
},
isIFrameLoading: function() {
return this._iFrameLoading;
}
});
Observable = Class.create();
Object.extend(Observable.prototype, {
initialize: function() {
this._changeListeners = new Array();
},
addChangeListener: function(listener){
this._changeListeners.push(listener);
},
notifyChange: function(eventName, eventDetail){
for(var i=0; i<this._changeListeners.length; i++){
this._changeListeners[i].onChange(this, eventName, eventDetail);
}
}
});
FilterModel = Class.create();
Object.extend(FilterModel.prototype, Observable.prototype);
Object.extend(FilterModel.prototype, {
initialize: function(filterName, shortName) {
Observable.prototype.initialize.call(this);
this._filterName = filterName;
this._shortName = shortName;
},
getName: function(){
return this._filterName;
},
getShortName: function(){
if(!this._shortName && this._filterName){
return this._filterName.toLowerCase();
}
return this._shortName;
},
clear:function(){
//throw 'This is abstract';
}
});
FilterView = Class.create();
Object.extend(FilterView.prototype, {
initialize: function(model, detailElement, headerElement) {
this._model = model;
this._detailElement = detailElement;
this._headerElement = headerElement;
this._first = $(this._headerElement) && $(this._headerElement).className.indexOf('first') != -1;
this._model.addChangeListener(this);
},
getDetailElement: function() {
return this._detailElement;
},
getHeaderElement: function() {
return this._headerElement;
},
getReviseElement: function() {
return this.getModel().getShortName() + "_revise";
},
onChange: function(model) {
this.render();
},
getModel: function() {
return this._model;
},
getSelectedHeaderClassName:function(){
if(this._first){
return 'selected first';
}
return 'selected';
},
getNonSelectedHeaderClassName:function(){
if(this._first){
return 'first';
}
return '';
},
isActivated: function(headerElement){
return this.getHeaderElement().className.indexOf('activated') != -1;
},
getDefaultDetailText: function(){
return '---';
},
render: function() {
var element = this.getDetailElement();
var html = this.getModel().isEmpty()?'':this.renderDetail();
if( html.length > 0){
html += "" + this.renderReviseLink();
}
else {
html += this.getDefaultDetailText();
}
element.innerHTML = html;
this._createBindings();
},
renderReviseLink:function(){
return "<br /><a id=\"" + this.getReviseElement() + "\" onclick=\"showSearchOption($('" + this.getHeaderElement().id + "'), '" + this.getModel().getShortName() + "')\">[Revise]</a>";
},
_createBindings:function(){
}
})
FilterViewWithEditableText = Class.create();
Object.extend(FilterViewWithEditableText.prototype, FilterView.prototype);
Object.extend(FilterViewWithEditableText.prototype, {
initialize: function(model, detailElement, headerElement, textElement, inputElement) {
FilterView.prototype.initialize.call(this, model, detailElement, headerElement);
this._textElement = textElement;
this._inputElement = inputElement;
this.render();
Event.observe(headerElement,'click',this._handleHeaderElementClick.bindAsEventListener(this));
},
_handleHeaderElementClick: function(evt){
this.editMode = true;
this.render();
this._handleReviseClicked();
Event.stop(evt);
},
_addReviseClickHandler: function() {
var revise = $(this.getReviseElement());
if(revise){
Event.observe(revise, 'click', this._handleReviseClicked.bind(this));
}
},
_handleReviseClicked: function() {
this.show();
if($(this.getInputElement()).value == '' ){
$(this.getInputElement()).value=this.getModel().getPromptText();
$(this.getInputElement()).style.fontStyle = 'italic';
}
Event.observe(this.getInputElement(), 'click', this._handleFocusGained.bind(this));
},
_addBlurHandler: function(){
var blur = $(this.getInputElement());
if(blur){
Event.observe(blur, 'blur', this._handleBlur.bind(this));
}
},
_handleBlur: function(){
this.showPassiveDetailElement();
if($(this.getInputElement()).value == ''){
this.hide();
}
this.editMode = false;
var self = this;
this._createTimeout(function(){
self._handleActionOnBlur();
}, 300);
},
showPassiveDetailElement:function() {
Element.show(this.getDetailElement());
$(this.getTextElement()).style.display = "";
$(this.getInputElement()).style.display = "none";
this.getHeaderElement().addClassName('selected');
},
show: function() {
Element.hide(this.getTextElement());
this.getDetailElement().style.display="";
this.getHeaderElement().addClassName('selected');
},
hide:function() {
Element.hide(this.getDetailElement());
this.getHeaderElement().removeClassName('selected');
},
_handleFocusGained: function() {
if($(this.getInputElement()).value == this.getModel().getPromptText()) {
$(this.getInputElement()).clear();
$(this.getInputElement()).style.fontStyle = 'normal';
}
},
_handleActionOnBlur: function() {
},
_addKeyPressHandler: function() {
var element = $(this.getInputElement());
if(element) {
Event.observe(element, 'keypress', this._handleKeyPress.bindAsEventListener(this));
}
},
_handleKeyPress: function(evt) {
if(evt.keyCode == 13){
this._handleBlur();
}
},
_createTimeout: function(callback, delay){
setTimeout(callback, delay);
},
getTextElement: function() {
return this._textElement;
},
getInputElement: function() {
return this._inputElement;
}
});
ItemsPerPageFilterModel = Class.create();
Object.extend(ItemsPerPageFilterModel.prototype, FilterModel.prototype);
Object.extend(ItemsPerPageFilterModel.prototype, {
initialize: function(){
// initialize fields
this._itemsPerPage = '10';
FilterModel.prototype.initialize.call(this, "itemsperpage");
this.constructor = ItemsPerPageFilterModel;
},
isEmpty: function() {
return false;
},
setItemsPerPage: function(num) {
this._itemsPerPage = num;
this.notifyChange();
},
getItemsPerPage: function() {
return this._itemsPerPage;
},
dump: function() {
var dumpObj = {};
dumpObj._itemsPerPage = this._itemsPerPage;
return dumpObj;
},
equals: function(other) {
if(!other._itemsPerPage)
return false
return other._itemsPerPage == this._itemsPerPage;
}
});
ItemsPerPageFilterModel.scoop = function(dump) {
return Object.extend(new ItemsPerPageFilterModel(), dump);
};
ItemsPerPageFilterView = Class.create();
Object.extend(ItemsPerPageFilterView.prototype, FilterView.prototype);
Object.extend(ItemsPerPageFilterView.prototype, {
initialize: function(model, detailElement, headerElement, selectedClass) {
// initialize fields
this._selectedClass = selectedClass || "selected";
FilterView.prototype.initialize.call(this, model, detailElement, headerElement);
this.render();
},
render: function() {
var choices = this._headerElement.getElementsByTagName("span");
for(var i = 0; i < choices.length; i++) {
$(choices[i].id).removeClassName("selected");
}
var selected_id = this._model.getItemsPerPage() + "_per_page";
$(selected_id).addClassName(this._selectedClass);
}
});
IdFilterModel = Class.create();
Object.extend(IdFilterModel.prototype, FilterModel.prototype);
Object.extend(IdFilterModel.prototype,  {
initialize: function(filterName, idPropertyName) {
FilterModel.prototype.initialize.call(this, filterName);
this._idPropertyName = idPropertyName;
},
getIdCriteria: function() {
return this[this._idPropertyName] || '';
},
setIdCriteria: function(id) {
this[this._idPropertyName] = id;
this.notifyChange();
},
isEmpty: function(){
return this.getIdCriteria()=='';
},
dump:function(){
var dump = {};
if (this[this._idPropertyName])
dump[this._idPropertyName] = this[this._idPropertyName];
return dump;
},
equals:function(other){
return (this[this._idPropertyName] == other[this._idPropertyName]);
}
});
IdFilterModel.scoop = function(dump, model){
model[model._idPropertyName] = dump[model._idPropertyName];
return model;
};
SalesTeamIdFilterModel = Class.create();
Object.extend(SalesTeamIdFilterModel.prototype, IdFilterModel.prototype);
Object.extend(SalesTeamIdFilterModel.prototype,  {
initialize: function() {
IdFilterModel.prototype.initialize.call(this, 'saleteamid', '_id');
this.constructor = SalesTeamIdFilterModel; // Safari Fix
}
});
SalesTeamIdFilterModel.scoop = function(dump){
return IdFilterModel.scoop(dump, new SalesTeamIdFilterModel());
};
AgentIdFilterModel = Class.create();
Object.extend(AgentIdFilterModel.prototype, IdFilterModel.prototype);
Object.extend(AgentIdFilterModel.prototype,  {
initialize: function() {
IdFilterModel.prototype.initialize.call(this, 'agentid', '_id');
this.constructor = AgentIdFilterModel; // Safari Fix
}
});
AgentIdFilterModel.scoop = function(dump){
return IdFilterModel.scoop(dump, new AgentIdFilterModel());
};
var agentCount = 1;
AgentLocationFilterModel = Class.create();
Object.extend(AgentLocationFilterModel.prototype, FilterModel.prototype);
Object.extend(AgentLocationFilterModel.prototype, {
initialize: function(listType) {
FilterModel.prototype.initialize.call(this, "agentbasedlocation");
this.constructor = AgentLocationFilterModel; // Safari Fix
this._count = agentCount++;
this._locationNames = [];
this.clear();
},
getListType: function() {
return $('agentLocationSearchListType').value;
},
getSelectedIds: function() {
return this._selectedIds;
},
setIdSelected: function(id) {
this._idMap[id] = 1;
this._updateSelectedIds();
this._addLocationName($(id + "_checkbox").name);
this.notifyChange();
},
setIdDeselected: function(id) {
this._idMap[id] = 0;
this._updateSelectedIds();
this._removeLocationName($(id + "_checkbox").name);
this.notifyChange();
},
clear: function() {
this._idMap = {};
this._selectedIds = [];
this._locationNames = [];
this.notifyChange();
},
dump: function() {
dumpArray = {};
dumpArray._filterName = this._filterName;
dumpArray._listType = this.getListType();
dumpArray._count = this.count;
dumpArray._selectedIds = this._selectedIds;
return dumpArray;
},
isEmpty: function() {
return (this._selectedIds.length == 0 && this._locationNames.length == 0);
},
equals:function(other) {
var same = true;
var wasFound = false;
if(this._selectedIds.length != other._selectedIds.length) {
same = false;
}
for(var i = 0; i < this._selectedIds.length; i++) {
wasFound = false;
for(var x = 0; x < other._selectedIds.length; x++) {
if (this._selectedIds[i] == other._selectedIds[x]) {
wasFound = true;
}
}
if(wasFound == false) {
same = false;
break;
}
}
return same;
},
_updateSelectedIds: function() {
this._selectedIds = [];
for(id in this._idMap) {
if(this._idMap[id] == 1) {
this._selectedIds.push(id);
}
}
},
_addLocationName: function(locationName) {
this._locationNames.push(locationName);
},
_removeLocationName: function(locationName) {
for(var i = 0; i < this._locationNames.length; i++) {
if(locationName == this._locationNames[i]) {
var tmp = this._locationNames[0];
this._locationNames[0] = this._locationNames[i];
this._locationNames[i] = tmp;
this._locationNames.shift();
break;
}
}
}
});
AgentLocationFilterModel.scoop = function(dump){
return Object.extend(new AgentLocationFilterModel(), dump);
}
AgentLocationFilterView = Class.create();
Object.extend(AgentLocationFilterView.prototype, FilterView.prototype);
Object.extend(AgentLocationFilterView.prototype, {
initialize: function(model) {
FilterView.prototype.initialize.call(this, model, $("agentbasedlocationDD"), $("agentbasedlocationDT"));
this._model = model;
this._model.clear();
},
renderDetail:function() {
var model = this._findModel();
return model._locationNames.join('<br/>');
},
getDefaultDetailText:function() {
var value = "";
if ($('agentLocationDisplayText')){
value = $('agentLocationDisplayText').value
}
return value;
},
_findModel: function() {
return this._model || getSearchOptionsModel().getFilterModel("agentbasedlocation");
},
render: function() {
FilterView.prototype.render.call(this);
},
onChange: function() {
this.render();
}
});
AgentLocationOptionPanel = Class.create();
Object.extend(AgentLocationOptionPanel.prototype, {
initialize: function(model) {
this._model = model;
this._processElements();
this._bindEvents();
},
clickElement: function(element) {
this._selectElement(element);
},
_processElements: function() {
this._elements = $('agentLocationTable').getElementsByTagName("input");
this._setModelWithCheckedElements();
var model = this.findModel();
},
findModel: function() {
return this._model || getSearchOptionsModel().getFilterModel("agentbasedlocation");
},
_selectElement: function(element) {
var model = this.findModel();
var id = this._getIdFromElement(element);
if(element.checked && id) {
model.setIdSelected(id);
} else {
model.setIdDeselected(id);
}
},
_getIdFromElement: function(element) {
var regularExpression = /(\d+)_checkbox/;
var matches = element.id.match(regularExpression);
if (matches) {
return matches[1];
}
return undefined;
},
_setModelWithCheckedElements: function() {
for(var i = 0; i < this._elements.length; i++) {
var current = this._elements[i];
this._selectElement(current);
}
},
_bindEvents: function() {
var inpts = $('agentLocationTable').getElementsByTagName('input');
function createEventHandler(view) {
return function(event) {
var elt = Event.element(event);
view.clickElement(elt);
};
}
for(var i = 0; i < inpts.length; i++) {
Event.observe(inpts[i], 'click', createEventHandler(this));
}
}
});
OfficeIdFilterModel = Class.create();
Object.extend(OfficeIdFilterModel.prototype, IdFilterModel.prototype);
Object.extend(OfficeIdFilterModel.prototype,  {
initialize: function() {
IdFilterModel.prototype.initialize.call(this, 'officeid', '_officeId');
this.constructor = OfficeIdFilterModel; // Safari Fix
}
});
OfficeIdFilterModel.scoop = function(dump){
return IdFilterModel.scoop(dump, new OfficeIdFilterModel());
};
SubRegionFilterModel = Class.create();
Object.extend(SubRegionFilterModel.prototype, IdFilterModel.prototype);
Object.extend(SubRegionFilterModel.prototype,  {
initialize: function() {
IdFilterModel.prototype.initialize.call(this, 'subregion', '_subregion');
this.constructor = SubRegionFilterModel; // Safari Fix
}
});
SubRegionFilterModel.scoop = function(dump){
return IdFilterModel.scoop(dump, new SubRegionFilterModel());
};
NeighborhoodIdFilterModel = Class.create();
Object.extend(NeighborhoodIdFilterModel.prototype, IdFilterModel.prototype);
Object.extend(NeighborhoodIdFilterModel.prototype,  {
initialize: function() {
IdFilterModel.prototype.initialize.call(this, 'neighborhoodid', '_neighborhoodId');
this.constructor = NeighborhoodIdFilterModel; // Safari Fix
}
});
NeighborhoodIdFilterModel.scoop = function(dump){
return IdFilterModel.scoop(dump, new NeighborhoodIdFilterModel());
};
DevelopmentGroupFilterModel = Class.create();
Object.extend(DevelopmentGroupFilterModel.prototype, IdFilterModel.prototype);
Object.extend(DevelopmentGroupFilterModel.prototype,  {
initialize: function() {
IdFilterModel.prototype.initialize.call(this, 'developmentgroup', '_developmentgroup');
this.constructor = DevelopmentGroupFilterModel; // Safari Fix
}
});
DevelopmentGroupFilterModel.scoop = function(dump){
return IdFilterModel.scoop(dump, new DevelopmentGroupFilterModel());
};
SearchOptionsPanelFactory = {
create: function(key, model) {
if(key == FilterKey.CAT_BASED_LOCATION) {
return new LocationSearchOptionsPanel(model, 'filter');
}else if(key == FilterKey.SCHOOL_DISTRICTS){
new SchoolDistrictsSearchOptionsPanel(model, 'filter');
}else if(key == FilterKey.RATES_AND_AVAILABILITY){
new RatesAndAvailabilityPanelView(model);
}else if(key == FilterKey.FEATURES_AND_AMENITIES) {
new AmenityDropDownView(model);
}else if(key == FilterKey.INTERIOR_SIZE_LOT_SIZE) {
new InteriorLotSizePanelView(model);
}else if(key == FilterKey.LANGUAGE) {
new LanguageSearchOptionsPanel('languageOptions');
}else if(key == FilterKey.AGENT_LOCATION) {
new AgentLocationOptionPanel();
}else if(key == FilterKey.PRICE) {
window.resetMinValueCombo();
}
}
};
FilterViewFactory = {
create: function(key, searchModel) {
var model = searchModel.getFilterModel(key);
if(key==FilterKey.PRICE){
return new PriceFilterView(model, this.getDetailElement(key), this.getHeaderElement(key));
}
if(key==FilterKey.RATES_AND_AVAILABILITY){
return new RatesAndAvailabilityFilterView(model,this.getDetailElement(key), this.getHeaderElement(key) );
}
if(key==FilterKey.BED_BATH){
return new BedBathSizeFilterView(model, this.getDetailElement(key), this.getHeaderElement(key));
}
if(key==FilterKey.INTERIOR_SIZE_LOT_SIZE){
// If Region is NYC, we do not want to show "All Lot Size"
return new InteriorLotSizeFilterView(model, this.getDetailElement(key), this.getHeaderElement(key), (regionRoot == '/nyc'));
}
if(key == FilterKey.LOCATION || key == FilterKey.CAT_BASED_LOCATION) {
model = searchModel.getFilterModel(FilterKey.LOCATION);
if(getPageController().CONTROLLER_NAME=='offices') {
return new OfficeLocationFilter(model, this.getDetailElement(key), this.getHeaderElement(key));
}
return new LocationFilterDisplay(model, this.getDetailElement(key), this.getHeaderElement(key), key);
}
if( key == FilterKey.LANGUAGE) {
return new LanguageFilterView(model, 'languageOptions', this.getDetailElement(key), this.getHeaderElement(key));
}
if( key == FilterKey.AGENT_NAME_SEARCH) {
return new AgentNameSearchFilterView(model, this.getDetailElement(key), this.getHeaderElement(key));
}
if(key== FilterKey.AGENT_LOCATION){
return	new AgentLocationFilterView(model, this.getDetailElement(key), this.getHeaderElement(key));
}
return new MultiLevelAmenityFilterView(model, this.getDetailElement(key), this.getHeaderElement(key));
},
getDetailElement: function(key){
return $(key + 'DD');
},
getHeaderElement: function(key){
return $(key + 'DT');
}
};
CheckBox = Class.create();
Object.extend(CheckBox.prototype, {
initialize: function(id, searchLevel, name) {
this._id = id || -1;
this._searchLevel = searchLevel || 0;
this._name = name || '***';
},
getName: function() {
return this._name;
},
getId: function() {
return this._id;
},
equals: function(other) {
if (!other) {
return false;
}
return this._id == other._id;
}
});
CheckBoxFilterModel = Class.create();
Object.extend(CheckBoxFilterModel.prototype, FilterModel.prototype);
Object.extend(CheckBoxFilterModel.prototype, {
initialize: function(filterName, shortName, defaultText, addText, editText) {
FilterModel.prototype.initialize.call(this, filterName, shortName);
this._checkboxes = [];
this._addText = addText;
this._editText = editText;
this._defaultText = defaultText || '---';
},
getDefaultText: function() {
return this._defaultText;
},
getAddText: function() {
return this._addText;
},
getEditText: function() {
return this._editText;
},
getCheckBoxNames: function() {
var array = [];
for (var i = 0; i < this._checkboxes.length; i++) {
array.push(this._checkboxes[i].getName());
}
return array;
},
addCheckBox: function(checkBox) {
this._checkboxes.push(checkBox);
this.notifyChange();
},
removeCheckBox: function(checkBox) {
for (var i = 0; i < this._checkboxes.length; i++) {
if (this._checkboxes[i].equals(checkBox)) {
this._checkboxes.splice(i, 1);
this.notifyChange();
return;
}
}
},
getCheckBoxes: function() {
return this._checkboxes;
},
isEmpty: function() {
return this._checkboxes.length == 0;
},
clear: function() {
this._checkboxes = [];
this.notifyChange();
},
equals: function(other) {
if (this._checkboxes.length != other.getCheckBoxes().length) return false;
for (var i = 0; i < this._checkboxes.length; i++) {
if (this._checkboxes[i].equals(other.getCheckBoxes()[i]) == false) return false;
}
return this._filterName == other._filterName && this._shortName == other._shortName;
}
});
MultiLevelAmenityFilterModel = Class.create();
Object.extend(MultiLevelAmenityFilterModel.prototype, CheckBoxFilterModel.prototype);
Object.extend(MultiLevelAmenityFilterModel.prototype,  {
initialize: function(filterName, shortName, defaultText, addText, editText) {
CheckBoxFilterModel.prototype.initialize.call(this, filterName, shortName, defaultText, addText, editText);
this.constructor = MultiLevelAmenityFilterModel; // Safari Fix
},
dump:function(){
var dump = {};
dump._filterName = this._filterName;
if(this._shortName){
dump._shortName = this._shortName;
}
if(this.getMinFireplaces()){
//server expects this as a string.
dump._minFireplaces = ''+this.getMinFireplaces();
}
if(this.getMinGarageBays()){
//server expects this as a string.
dump._minGarageBays = ''+this.getMinGarageBays();
}
if(this._checkboxes.length > 0) {
dump._checkboxes = this._checkboxes;
}
return dump;
},
setMinFireplaces: function(minFireplaces) {
if(minFireplaces <= 1){
delete this._minFireplaces;
}else{
this._minFireplaces = minFireplaces;
}
this.notifyChange();
},
setMinGarageBays: function(minGarageBays) {
if(minGarageBays <= 1) {
delete this._minGarageBays;
}else {
this._minGarageBays = minGarageBays;
}
this.notifyChange();
},
getMinFireplaces: function() {
return this._minFireplaces;
},
getMinGarageBays: function(){
return this._minGarageBays;
}
});
MultiLevelAmenityFilterModel.scoop = function(dump){
var scooped = Object.extend(new MultiLevelAmenityFilterModel(), dump);
var checkboxes = scooped._checkboxes;
for(var i=0; i<checkboxes.length;i++) {
checkboxes[i] = new CheckBox(checkboxes[i]._id, checkboxes[i]._searchLevel, checkboxes[i]._name);
}
return scooped;
}
MultiLevelAmenityFilterView = Class.create();
Object.extend(MultiLevelAmenityFilterView.prototype, FilterView.prototype);
Object.extend(MultiLevelAmenityFilterView.prototype, {
initialize: function(model, detailElement, headerElement) {
FilterView.prototype.initialize.call(this, model, detailElement, headerElement);
this.render();
},
renderDetail: function() {
if (isLandingPageVisible()) {
return this._model.getEditText();
}
var textArray = this.getModel().getCheckBoxNames().sort();
var html = '';
if (textArray.length > 0) {
html += textArray.join('<br />');
}
//if(topTextArray.length > 0 && bottomTextArray.length > 0){
//	html += '<br /><em>and</em><br />';
//}
html = this.fixFireplacesText(html);
html = this.fixGaragesText(html);
return html;
},
getDefaultDetailText: function() {
if (isLandingPageVisible()) {
return this._model.getAddText();
}
return this._model.getDefaultText();
},
fixFireplacesText: function(html) {
var text = 'Fireplaces: at least ';
if (html.indexOf('Fireplaces') != -1) {
var fireplaces = this.getModel().getMinFireplaces() || 1;
html = html.replace(/Fireplaces/, text + fireplaces);
}
return html;
},
fixGaragesText: function(html) {
var text = 'Garages: at least ';
if (html.indexOf('Garages') != -1) {
var garages = this.getModel().getMinGarageBays() || 1;
html = html.replace(/Garages/, text + garages);
}
return html;
},
renderReviseLink: function() {
if (isLandingPageVisible()) {
return "";
}
return FilterView.prototype.renderReviseLink.call(this);
}
});
AmenityDropDownView = Class.create();
Object.extend(AmenityDropDownView.prototype, {
initialize: function(model) {
this._model = model;
this._fireplaces = new Select('Fireplacesdropdown');
this._garages = new Select('Garagesdropdown');
this.onLoad();
this.onChange();
this._model.addChangeListener(this);
},
onLoad: function() {
this._fireplaces.setSelectionIndex(this._model.getMinFireplaces()-1);
this._garages.setSelectionIndex(this._model.getMinGarageBays()-1);
},
onChange: function() {
var fireplacesFilter = function(element) { return element.getName() == 'Fireplaces'; };
var garagesFilter = function(element) { return element.getName() == 'Garages'; };
this._fireplaces.setDisabled(!this._model.getCheckBoxes().any(fireplacesFilter));
this._garages.setDisabled(!this._model.getCheckBoxes().any(garagesFilter));
}
}) ;
LocationModel = Class.create();
LocationModel.ids = [];
Object.extend(LocationModel.prototype, FilterModel.prototype);
Object.extend(LocationModel.prototype, {
initialize: function() {
FilterModel.prototype.initialize.call(this, "Location");
this._quickSearchText = '';
this._isQuickSearch = false;
this.constructor = LocationModel; // Safari Fix
},
setLocationDisplayTree:function(locationDisplayTree){
this._locationDisplayTree = locationDisplayTree;
this._restoreLocationDisplayTree();
this._setToggleListenerToLocationNode(this._locationDisplayTree);
},
setToggleListener: function(listener) {
this._toggleListener = listener;
},
setCitySTZip:function(citySTZip){
this.setQuickSearchText(citySTZip);
this._citySTZip = citySTZip;
this.notifyChange();
},
getCitySTZip:function(){
return this._citySTZip;
},
_setToggleListenerToLocationNode: function(locationNode) {
locationNode.setToggleListener(this.nodeToggled.bind(this));
locationNode.children().each(function(child) {
this._setToggleListenerToLocationNode(child)
}.bind(this));
},
isOnCorporate: function() {
return this.getCorporateNode().getLocationId() == window.currentRegionLocationId;
},
nodeToggled: function(node){
if(this._toggleListener){
this._toggleListener(node);
}
var buffer = [];
this.getRootLocationNode().collectCheckedLocationIds(buffer);
this._checkedLocations = buffer.join();
this.notifyChange();
},
getRootLocationNode: function() {
if(this._locationDisplayTree.locationId != currentRegionLocationId){
var children = this._locationDisplayTree.children();
for(var i=0;i<children.length;i++){
if(children[i].locationId == currentRegionLocationId){
return children[i];
}
}
}
return this._locationDisplayTree;
},
findLocationFromRoot:function(locationId){
return this.getLocationNodeById(locationId, this.getRootLocationNode());
},
getLocationNodeById : function(locationId, fromRoot){
LocationModel.ids.push(fromRoot.locationId);
if(fromRoot.locationId == locationId){
return fromRoot;
}
var children = fromRoot.children();
for(var i=0;i<children.length;i++){
var node = this.getLocationNodeById(locationId, children[i]);
if(node!=null){
return node;
}
}
return null;
},
getCorporateNode:function(){
return this._locationDisplayTree;
},
dump: function() {
dump = {};
dump._isQuickSearchEnabled = String(this.isQuickSearch());
// If we send both city state & checked location the latter messes up the results and hence this check
if(this.isQuickSearch()) {
if(this._citySTZip){
dump._citySTZip = this._citySTZip;
}
if(this._quickSearchText){
dump._quickSearchText = this._quickSearchText;
}
}
else {
dump._checkedLocations = this._checkedLocations;
}
return dump;
},
disableQuickSearch:function(){
this._isQuickSearch = false;
},
enableQuickSearch: function() {
this._isQuickSearch = true;
},
setQuickSearchText:function(text){
this._quickSearchText = text;
this.enableQuickSearch();
},
isQuickSearch:function(){
return this._isQuickSearch;
},
getQuickSearchText:function(){
return this._quickSearchText;
},
getPromptText: function() {
return SearchByRadioButton.LOCATION.getPromptText();
},
isEmpty:function(){
return !this._checkedLocations && !this._quickSearchText;
},
clear:function() {
this._quickSearchText = null;
delete this._checkedLocations;
if(this._locationDisplayTree) this._restoreLocationDisplayTree();
this.notifyChange();
},
equals:function(other){
var quickSearchSame = true;
if(this.isQuickSearch()){
quickSearchSame = this._quickSearchText == other._quickSearchText;
}
return quickSearchSame && (this._checkedLocations == other._checkedLocations);
},
_restoreLocationDisplayTree:function(){
var hash = {};
if(typeof this._checkedLocations != "undefined") {
this._checkedLocations.split(',').each(function(locationId){hash[locationId]=locationId;});
this.getRootLocationNode().restore(hash);
}else{
this.getRootLocationNode().restore({});
}
}
});
LocationModel.scoop = function(dump){
var model = Object.extend(new LocationModel(), dump);
if(dump._citySTZip){
model.setCitySTZip(dump._citySTZip);
}
if(dump._quickSearchText){
model.setQuickSearchText(dump._quickSearchText);
}
if(typeof model._isQuickSearchEnabled == 'undefined' || model._isQuickSearchEnabled =='false' ){
model._isQuickSearch = false;
}
return model;
}
LocationFilterDisplay = Class.create();
Object.extend(LocationFilterDisplay.prototype, FilterViewWithEditableText.prototype);
Object.extend(LocationFilterDisplay.prototype, {
initialize: function(locationModel, detailElement, headerElement, locationFilterTypeKey) {
this._locationFilterTypeKey = locationFilterTypeKey;
this._showAll = false;
this._template = this._getTemplate();
FilterViewWithEditableText.prototype.initialize.call(this, locationModel, detailElement, headerElement, 'locationText', 'locationInput');
},
getControllerName: function() {
return getPageController().CONTROLLER_NAME;
},
_handleReviseClicked: function() {
if(typeof WebTrendsAnalyzer == 'function'){
(new WebTrendsAnalyzer()).fireWebTrendAction(
WebTrendsAnalyzer.CreateActionForFilterOptionType(window.regionRoot, 'Location'));
}
window.clearSearchOptionInfoDiv();
window.switchToResultsView(this.getHeaderElement());
return false;
},
toggleShowAll: function() {
this._showAll = !this._showAll;
this._template = this._getTemplate();
this.render();
},
_getTemplate:function(){
return this._showAll?new ShowAllTemplate(!this._isOnCorporate()):new ShowPartialTemplate(!this._isOnCorporate());
},
_isOnCorporate:function(){
if(!this.getModel()){
return window.regionRoot == '';
}
return this.getModel().isOnCorporate();
},
_handleToggleClicked: function(e) {
this.toggleShowAll();
e.returnValue = false;
return false;
},
_handleExpandSearchClicked: function(e) {
window.showSearchOption($(this._headerElement), this._locationFilterTypeKey);
e.returnValue = false;
return false;
},
_handleActionOnBlur: function() {
this.getModel().setCitySTZip($(this.getInputElement()).value);
},
renderDetail: function() {
if(!this.editMode && this.getModel().isEmpty()) {
return '';
}
if(isLandingPageVisible()) {
return "Edit Location";
}
if( this._pageWithRegularReviseLink || this.getModel().isQuickSearch() ){
var html = '<span id="locationText">' + this.getModel().getQuickSearchText() + '</span>'
html += '<input class="text" style="display:none; width:150px; float:left;" id="locationInput" value="' + this.getModel().getQuickSearchText() + '"/> <br />'
return html;
}
var children = this.getModel().getRootLocationNode().children();
var mssg = this._template.apply(children);
if(this.getModel().getRootLocationNode().isUnChecked())
mssg = 'No locations selected<br />';
return mssg;
},
getDefaultDetailText: function(){
if(isLandingPageVisible()) {
return "Add Location";
}
if(this._pageWithRegularReviseLink){
var html = '<span id="locationText"></span>'
html += '<input class="text" style="display:none; width:150px; float:left;" id="locationInput" value=""/> <br />'
html+= this.renderReviseLink();
return html;
}
return 'All Locations';
},
renderReviseLink:function(){
if(isLandingPageVisible()) {
return "";
}
var reviseLinkHTML = FilterViewWithEditableText.prototype.renderReviseLink.call(this);
var index = reviseLinkHTML.indexOf("<br />");
if(index!=-1){
reviseLinkHTML = reviseLinkHTML.substring(index+6);
}
var viewLabel = "[View All]";
if(this._showAll){
viewLabel = "[View Fewer]";
}
if(this._countIncludedChildren() >= 6) {
reviseLinkHTML += '<a onclick="return searchOptionInfoClose();" id="selectedLocationsToggleLink">'+viewLabel+'</a>';
}
return reviseLinkHTML;
},
_createBindings:function(){
if($('expandSearchLink'))
Event.observe($('expandSearchLink'), 'click', this._handleExpandSearchClicked.bindAsEventListener(this));
if($('selectedLocationsToggleLink'))
Event.observe($('selectedLocationsToggleLink'), 'click', this._handleToggleClicked.bindAsEventListener(this));
},
_countIncludedChildren:function(){
var children = this.getModel().getRootLocationNode().children();
if(!this._isOnCorporate()){
children = ShowAllTemplate.prototype.flatten(children);
}
var count = 0;
for(var i=0;i<children.length;i++){
if(children[i].isUnChecked() == false){
++count;
}
}
return count;
}
});
LocationSearchOptionsPanel = Class.create();
Object.extend(LocationSearchOptionsPanel.prototype, {
initialize: function(model, divId) {
this._divId = divId;
this._model = model;
this._bindEvents();
},
_bindEvents:function(){
var self = this;
var categoryBoxes = this._scanForCategories();
categoryBoxes.each(function(categoryId){
Event.observe($(categoryId), 'click', self.handleCategoryClicked.bind(self, categoryId));
});
var locationBoxes = this._scanForAllLocations();
locationBoxes.each(function(locationElemId){
Event.observe($(locationElemId), 'click', self.handleLocationClicked.bind(self, locationElemId));
})
},
handleCategoryClicked:function(categoryElemId){
this._toggleCategoryStateInModel(categoryElemId);
this._syncChildCheckboxState(categoryElemId);
},
handleLocationClicked:function(locationElemId){
this._toggleLocationStateInModel(locationElemId);
var categoryId = this._determineCategoryIdForLocationElementId(locationElemId)
var siblings = this._scanForCategoryChildren(categoryId);
var locationElem = $(locationElemId);
for(var i=0;i<siblings.length;i++){
if($(siblings[i]).checked != locationElem.checked){
$('category_cb_'+categoryId).checked = false;
return;
}
}
$('category_cb_'+categoryId).checked = locationElem.checked;
},
_determineCategoryIdForLocationElementId:function(locationElemId){
var locationElem = $(locationElemId);
var locationNode = this._model.findLocationFromRoot(locationElem.value);
return locationNode.getParentNode().locationId;
},
_toggleLocationStateInModel:function(locationElemId){
var node = this._model.findLocationFromRoot($(locationElemId).value);
if(node){
node.toggle();
}
},
_toggleCategoryStateInModel:function(categoryElemId){
var catElem = $(categoryElemId);
var categoryLocationId = catElem.value;
var parentLocationNode = this._model.findLocationFromRoot(categoryLocationId);
var state = CheckBoxState.UnChecked;
if(catElem.checked){
state = CheckBoxState.Checked;
}
parentLocationNode.toggleStateTo(state);
},
_syncChildCheckboxState:function(categoryElemId){
var catElem = $(categoryElemId);
var categoryLocationId = catElem.value;
var boxes = this._scanForCategoryChildren(categoryLocationId);
for(var i=0;i<boxes.length;i++){
$(boxes[i]).checked = catElem.checked;
}
},
_scanForAllLocations:function(){
return this._scanForMatchingInputs(this._divId, 'location_cb');
},
_scanForCategories:function(){
return this._scanForMatchingInputs(this._divId, 'category_cb');
},
_scanForCategoryChildren:function(category){
return this._scanForMatchingInputs('location_table_'+category, 'location_cb')
},
_scanForMatchingInputs:function(fromElemId, idPrefix){
var inputs = $(fromElemId).getElementsByTagName('input');
var categories = [];
for(var i=0;i<inputs.length;i++){
if(inputs[i].id.indexOf(idPrefix) == 0){
categories.push(inputs[i].id);
}
}
return categories;
}
});
PriceMixIn = Class.create();
Object.extend(PriceMixIn.prototype, {
setMaxPrice: function(maxPrice, maxPriceText) {
var default_max_price = 100000000;
if (maxPrice == default_max_price) maxPrice = null;
this._maxPrice = maxPrice;
this._maxPriceText = maxPriceText;
this.notifyChange();
},
setMinPrice: function(minPrice, minPriceText) {
var default_min_price = 0;
if (minPrice == default_min_price) minPrice = null;
this._minPrice = minPrice;
this._minPriceText = minPriceText;
this.notifyChange();
},
getMaxPrice: function() {
return this._maxPrice;
},
getMinPrice: function() {
return this._minPrice;
},
getMinPriceText: function(defaultText) {
if (this.getMinPrice()) {
return this._minPriceText;
}
return defaultText;
},
getMaxPriceText: function(defaultText) {
if (this.getMaxPrice()) {
return this._maxPriceText;
}
return defaultText;
}
});
PriceFilterModel = Class.create();
Object.extend(PriceFilterModel.prototype, FilterModel.prototype);
Object.extend(PriceFilterModel.prototype, PriceMixIn.prototype);
Object.extend(PriceFilterModel.prototype,  {
initialize: function() {
FilterModel.prototype.initialize.call(this,"Price");
this.constructor = PriceFilterModel; // Safari Fix
},
dump: function(){
dumpArray = {};
dumpArray._filterName = this._filterName;
if(this._minPrice) {
dumpArray._minPrice = this._minPrice;
dumpArray._minPriceText = this._minPriceText;
}
if(this._maxPrice) {
dumpArray._maxPrice = this._maxPrice;
dumpArray._maxPriceText = this._maxPriceText;
}
return dumpArray;
},
equals: function(other) {
return other._maxPrice == this._maxPrice && other._minPrice == this._minPrice;
},
isEmpty:function(){
return !this._minPrice && !this._maxPrice;
},
clear:function() {
this._maxPrice = null;
this._minPrice = null;
this.notifyChange();
}
});
PriceFilterModel.scoop = function(dump){
return Object.extend(new PriceFilterModel(), dump);
}
PriceFilterView = Class.create();
Object.extend(PriceFilterView.prototype, FilterView.prototype);
Object.extend(PriceFilterView.prototype, {
initialize: function(model, detailElement, headerElement) {
FilterView.prototype.initialize.call(this, model, detailElement, headerElement);
this.render();
},
renderDetail: function() {
if(isLandingPageVisible()) {
return "Edit Price Range";
}
var buff = [];
var model = this.getModel();
buff.push(model.getMinPriceText("No Minimum"));
buff.push(" to ");
buff.push(model.getMaxPriceText("No Maximum"));
return buff.join('');
},
getDefaultDetailText: function(){
if(isLandingPageVisible()) {
return "Add Price Range";
}
return 'No Minimum to No Maximum';
},
renderReviseLink:function(){
if(isLandingPageVisible()) {
return "";
}
return FilterView.prototype.renderReviseLink.call(this);
}
})
PeerElement = Class.create();
Object.extend(PeerElement.prototype, {
initialize:function(elementId){
this._elementId = elementId;
this._listeners = [];
},
addClickListener:function(listener){
if(this._listeners.length == 0 && $(this._elementId)){
Element.observe(this._elementId, 'click', this._handleClick.bind(this));
}
this._listeners.push(listener);
},
_handleClick:function(){
this._listeners.each(function(listener){listener();});
}
});
InputElement = Class.create();
Object.extend(InputElement.prototype, {
ENTER_KEY_CODE:13,
initialize: function(elementId, defaultValue) {
this._elementId = elementId;
this._defaultValue = defaultValue || '';
this._focusListeners = [];
this._blurListeners = [];
this._keyListeners = [];
},
getValue: function() {
return this._getElement().value;
},
setValue: function(value) {
this._getElement().value = value;
},
addFocusListener: function(listener) {
if(this._focusListeners.length == 0 && $(this._elementId)){
Element.observe(this._elementId, 'focus', this._handleFocus.bind(this));
}
this._focusListeners.push(listener);
},
addBlurListener: function(listener) {
if(this._blurListeners.length == 0 && $(this._elementId)){
Element.observe(this._elementId, 'blur', this._handleBlur.bind(this));
}
this._blurListeners.push(listener);
},
addEnterKeyListener: function(listener) {
if(this._keyListeners.length == 0 && $(this._elementId)){
Element.observe(this._elementId, 'keypress', this._handleEnterPressed.bindAsEventListener(this));
}
this._keyListeners.push(listener);
},
clear: function() { //fixes problem w/ firefox graphics engine :-P
this._getElement().style.background='black';
this._getElement().clear();
this._getElement().style.background='white';
},
_handleFocus: function() {
this._focusListeners.each(function(listener){listener();});
},
_handleBlur: function() {
this._blurListeners.each(function(listener){listener();});
},
_handleEnterPressed: function(e) {
if(e.keyCode == this.ENTER_KEY_CODE) {
this._keyListeners.each(function(listener){listener();});
}
},
_getElement: function() {
return $(this._elementId) || {value:this._defaultValue};
},
addClass:function(className){
Element.addClassName(this._elementId, className);
},
removeClass:function(className){
Element.removeClassName(this._elementId, className);
},
hide: function() {
Element.hide(this._getElement());
},
show: function() {
Element.show(this._getElement());
}
});
Label = Class.create();
Object.extend(Label.prototype, {
initialize: function(name) {
this._name = name;
},
update: function(text) {
this.getElement().update(text);
},
getElement: function() {
return $(this._name) || {update: Prototype.emptyFunction};
}
});
Select = Class.create();
Object.extend(Select.prototype, {
initialize: function(name){
this._name = name;
this._changeListeners = [];
},
setDisabled: function(value) {
this._getElement().disabled = value;
},
getDisabled: function() {
return this._getElement().disabled;
},
getSelection: function() {
var select = this._getElement();
var options = $A(select.options);
if(options.length == 0) return new SelectOption();
var selected = options[select.selectedIndex];
return new SelectOption(selected.innerHTML, selected.value);
},
setSelectionValue:function(value){
this._getElement().value=value;
},
getSelectionValue: function() {
return this._getElement().value;
},
setSelectionIndex:function(value){
this._getElement().selectedIndex=value;
},
getSelectionIndex:function(value){
return this._getElement().selectedIndex;
},
update: function(text, selectedValue) {
var select = this._getElement();
select.innerHTML = '';
var children = HtmlBuilder.buildOptions(text, selectedValue);
var length = children.length;
var selectedIndex = 0;
for(var i=0; i<length; i++) {
if(children[i].selected == true) { selectedIndex = i; }
select.appendChild(children[i]);
}
select.selectedIndex = selectedIndex;
},
addChangeListener: function(listener) {
this._changeListeners = [];
if(this._changeListeners.length == 0 && $(this._name)) {
Event.observe(this._name, 'change', this._selectionChanged.bind(this));
}
this._changeListeners.push(listener);
},
_selectionChanged: function() {
this._changeListeners.each(function(listener){
listener(this.getSelection());
}.bind(this));
},
_getElement: function() {
return $(this._name) || {value:0, disabled:false, appendChild: Prototype.emptyFunction, innerHTML: '', options: [], selectedIndex:0 };
},
getCount:function(){
return this._getElement().options.length;
},
getOptionAt:function(index){
return this._getElement().options[index];
}
});
SelectOption = Class.create();
Object.extend(SelectOption.prototype, {
initialize: function(text, value) {
this.text = text || '';
this.value = value || this.text;
},
getText: function() {
return this.text;
},
getValue:function() {
return this.value;
}
});
RadioButton = Class.create();
Object.extend(RadioButton.prototype, {
initialize: function(name) {
this._name = name;
},
setChecked: function(state) {
this._getElement().checked = state;
},
isChecked: function(state) {
return this._getElement().checked;
},
addClickListener: function(daFunction){
this._getElement().observe('click', daFunction);
},
_getElement: function() {
return $(this._name) || {checked: false, observe: Prototype.emptyFunction };
}
});
EmailAddressValidator = Class.create();
EmailAddressValidator.REGEXP = /\S+@\S+\.\S+/;
Object.extend(EmailAddressValidator.prototype,{
initialize:function(input, onFail, onValid){
if(typeof input.tagName != 'undefined'){
input = new InputElement(input);
}
this._input = input;
this._onFail = onFail;
this._onValid = onValid;
},
validate:function(){
var value = this._input.getValue().strip();
var valid = EmailAddressValidator.REGEXP.test(value);
if(valid && typeof this._onValid == 'function'){
this._onValid(value);
}
if(!valid && typeof this._onFail == 'function'){
this._onFail();
}
return valid;
}
});
var CurrentlyWatchingPropertyPanel = Class.create();
Object.extend(CurrentlyWatchingPropertyPanel.prototype,{
initialize:function(div, service){
this._container = div;
this._service = service;
this._stopLink = div.getElementsByTagName('a')[0];
var hiddenKey = div.getElementsByTagName('input')[0];
this._listingKey = hiddenKey.value;
this._createBindings();
},
_createBindings:function(){
Event.observe(this._stopLink, 'click', this._handleSaveClicked.bindAsEventListener(this));
},
_handleSaveClicked:function(e){
this._service.removeWatch(this._listingKey, this._watchRemoved.bind(this));
Event.stop(e);
return false;
},
_watchRemoved:function(html){
this._container.innerHTML = html;
new WatchThisPropertyPanel(this._container, this._service);
}
});
var WatchThisPropertyPanel = Class.create();
Object.extend(WatchThisPropertyPanel.prototype,{
initialize:function(div, service){
this._container = div;
this._emailInput = new InputElement(div.getElementsByTagName('input')[0]);
this._saveButton = div.getElementsByTagName('button')[0];
var numberInput = div.getElementsByTagName('input')[1];
if(numberInput){
this._listingNumber = numberInput.value;
}
this._errors = div.getElementsByTagName('p')[0];
this._createBindings();
this._validator = new EmailAddressValidator(this._emailInput, this._validationFailed.bind(this), this._validationPassed.bind(this))
this._service = service;
},
_createBindings:function(){
if(this._saveButton){
Event.observe(this._saveButton, 'click', this._handleSaveClicked.bind(this));
this._emailInput.addEnterKeyListener(this._handleSaveClicked.bind(this));
}
},
_handleSaveClicked:function(){
if(this.validate()){
Element.hide(this._errors);
this._saveButton.innerHTML = "Saving...";
this._saveButton.disabled = true;
this._service.addWatch(this._listingNumber, this._emailInput.getValue().strip(), this._watchCreated.bind(this));
}else{
Element.show(this._errors);
}
},
_watchCreated:function(markup){
this._container.innerHTML = markup;
new CurrentlyWatchingPropertyPanel(this._container, this._service);
},
validate:function(){
return this._validator.validate();
},
_validationFailed:function(){
Element.show(this._errors);
},
_validationPassed:function(email){
createCookie('userEmail', email);
Element.hide(this._errors);
}
});
WatchPropertyService = Class.create();
Object.extend(WatchPropertyService.prototype, {
initialize:function(){
},
addWatch:function(listingNumber, email, callback){
new Ajax.Request(siteRoot+"watchlist/addWatch.rails", {
method: 'post',
onSuccess: this.saveComplete.bind(this, callback),
parameters: {listingNumber:listingNumber,email:email}
});
},
removeWatch:function(key, callback){
new Ajax.Request(siteRoot+"watchlist/detailDelete.rails", {
method: 'post',
onSuccess: this.removeComplete.bind(this, callback),
parameters: {key:key}
});
},
removeComplete:function(callback, transport){
callback(transport.responseText);
},
saveComplete:function(callback, transport){
callback(transport.responseText);
}
});
var WebTrendsAnalyzer = Class.create();
Object.extend(WebTrendsAnalyzer.prototype, {
initialize:function(){
},
scan:function(rules){
if(typeof dcsMultiTrack == 'function'){
for(var i = 0;i<rules.length;i++){
this._monitorWebTrend(rules[i]);
}
}
},
_monitorWebTrend:function(rule){
if(typeof rule.elemId == 'string' && rule.elemId!=''){
var input = $(rule.elemId);
if(input){
Event.observe(input, rule.eventName, this.fireWebTrendAction.bind(this, rule));
}
}
},
_extractArgs:function(rule){
return [
"DCS.dcsuri", rule.uri,
"WT.ti", rule.actionKey,
"WT.si_n", rule.categoryName,
"WT.si_x", rule.stepNumber
];
},
fireWebTrendAction:function(rule){
if(typeof dcsMultiTrack == 'function'){
dcsMultiTrack.apply(window, this._extractArgs(rule));
}
}
});
WebTrendsAnalyzer.INITIAL_RULES =
[
/* Watch Property */
{
elemId:'watchThisPropertyEmail',
eventName:'change',
uri:'/watchThisPropertyEmail',
actionKey:'Watch This Property Email',
categoryName:'Watch This Property',
stepNumber:'1'
},
{
elemId:'watchThisPropertyButton',
eventName:'click',
uri:'/watchThisPropertySave',
actionKey:'Watch This Property Save',
categoryName:'Watch This Property',
stepNumber:'2'
}
];
WebTrendsAnalyzer.INITIATE_SAVE_SEARCH_ACTION =
{
elemId:'saveSearchButtonId',
eventName:'click',
uri:'/saveSearch',
actionKey:'Save Search - Initiate Save Search',
categoryName:'Save Search',
stepNumber:'1'
};
WebTrendsAnalyzer.DYNAMIC_SAVE_SEARCH_RULES =
[
{
elemId:'SearchName',
eventName:'change',
uri:'/saveSearch',
actionKey:'Save Search - Enter Search Name',
categoryName:'Save Search',
stepNumber:'2'
},
{
elemId:'SearchEmailAddress',
eventName:'change',
uri:'/saveSearch',
actionKey:'Save Search - Enter Email Address',
categoryName:'Save Search',
stepNumber:'3'
},
{
elemId:'SaveSearchSaveButton',
eventName:'click',
uri:'/saveSearch',
actionKey:'Save Search - Complete Save Search',
categoryName:'Save Search',
stepNumber:'4'
}
];
WebTrendsAnalyzer.CreateRulesForOptionPane = function(regionRoot, searchType){
var factory = new FilterOptionsRuleFactory(regionRoot, searchType);
var rules = [];
WebTrendsAnalyzer.CreateRulesForElements('searchOptionInfoDiv', 'input', rules, factory);
WebTrendsAnalyzer.CreateRulesForElements('searchOptionInfoDiv', 'select', rules, factory);
return rules;
}
WebTrendsAnalyzer.CreateRulesForEmail = function(){
var factory = new EmailRuleFactory();
var rules = [];
WebTrendsAnalyzer.CreateRulesForElements('containerDiv', 'input', rules, factory);
WebTrendsAnalyzer.CreateRulesForElements('containerDiv', 'textarea', rules, factory);
WebTrendsAnalyzer.CreateRulesForElements('containerDiv', 'button', rules, factory);
return rules;
}
WebTrendsAnalyzer.CreateRulesForElements = function(baseElement, selector, rules, factory){
var elements = $(baseElement).getElementsBySelector(selector);
for(var i=0;i<elements.length;i++){
rules.push(factory.create(elements[i]));
}
}
WebTrendsAnalyzer.CreateActionForFilterOptionType = function(regionRoot, type) {
return {
elemId: type + 'DT',
eventName: 'click',
uri: regionRoot + '/searchFilter' + type,
actionKey: 'Opened ' + type + ' filter',
categoryName: 'Search Filter ' + type,
stepNumber: ''
};
}
WebTrendsAnalyzer.CreateActionForLocationCheckbox = function(locationId, checked){
return {
elemId:locationId+'_checkbox',
eventName:'click',
uri: '/locationFilter',
actionKey:(checked?'Checked':'Unchecked')+' location '+locationId,
categoryName:'Location Filter',
stepNumber:''
};
}
WebTrendsAnalyzer.CreateActionClickOnLink = function(name, url, categoryName){
return {
elemId:name,
eventName:'click',
uri:url,
actionKey:name,
categoryName:categoryName,
stepNumber:''
};
}
FilterOptionsRuleFactory = Class.create();
Object.extend(FilterOptionsRuleFactory.prototype, {
initialize: function(regionRoot, searchType) {
this.searchType = searchType;
this.regionRoot = regionRoot;
},
create: function(elem) {
return {
elemId: elem.id,
eventName: elem.tagName == 'SELECT' ? 'change' : 'click',
uri: regionRoot + '/searchFilter' + this.searchType,
actionKey: elem.id,
categoryName: 'Search Filter ' + this.searchType,
stepNumber: ''
};
}
});
EmailRuleFactory = Class.create();
Object.extend(EmailRuleFactory.prototype, {
initialize:function(){
},
create:function(elem){
return {
elemId:elem.id,
eventName:WebTrendsAnalyzer.ReturnEventAction(elem.type),
uri:'/emailform/'+ elem.form.name,
actionKey:elem.id,
categoryName:'Email Form : ' + elem.form.name,
stepNumber:elem.tabIndex
};
}
});
WebTrendsAnalyzer.ReturnEventAction = function(type){
var event;
switch (type){
case 'submit':
case 'checkbox':
event = 'click';
break;
case 'textarea':
case 'text':
event = 'change';
break;
default:
event = 'click';
}
return event;
}
RatesAndAvailabilityFilterModel = Class.create();
Object.extend(RatesAndAvailabilityFilterModel.prototype, CheckBoxFilterModel.prototype);
Object.extend(RatesAndAvailabilityFilterModel.prototype, PriceMixIn.prototype);
Object.extend(
RatesAndAvailabilityFilterModel.prototype,
{
initialize: function() {
CheckBoxFilterModel.prototype.initialize.call(this, "Rates and Availability", "ratesandavailability", "Add Rental Terms and Price", "All Rental Terms/Any Price", "Edit Rental Terms and Price");
this.constructor = RatesAndAvailabilityFilterModel; // Safari Fix
},
isEmpty: function() {
return this._minPrice == undefined
&& this._maxPrice == undefined
&& this.getCheckBoxes().length == 0;
},
dump: function() {
dump = {};
dump._filterName = this._filterName;
if (this._minPrice) {
dump._minPrice = this._minPrice;
dump._minPriceText = this._minPriceText;
}
if (this._maxPrice) {
dump._maxPrice = this._maxPrice;
dump._maxPriceText = this._maxPriceText;
}
if (this._checkboxes.length > 0) {
dump._checkboxes = this._checkboxes;
}
return dump;
},
getCheckBoxes: function() {
return this._checkboxes.sort(function(x, y) { return x.getId() - y.getId() });
},
clear: function() {
this._maxPrice = null;
this._minPrice = null;
this._checkboxes = [];
this.notifyChange();
}
}
)
RatesAndAvailabilityFilterModel.scoop = function(dump) {
var scooped = Object.extend(new RatesAndAvailabilityFilterModel(), dump);
var checkboxes = scooped._checkboxes;
for (var i = 0; i < checkboxes.length; i++) {
checkboxes[i] = new CheckBox(checkboxes[i]._id, checkboxes[i]._searchLevel, checkboxes[i]._name);
}
return scooped;
}
RatesAndAvailabilityFilterView = Class.create();
Object.extend(RatesAndAvailabilityFilterView.prototype, FilterView.prototype);
Object.extend(RatesAndAvailabilityFilterView.prototype,
{
initialize: function(model, detailElement, headerElement) {
FilterView.prototype.initialize.call(this, model, detailElement, headerElement);
this.constructor = RatesAndAvailabilityFilterView; // Safari Fix
this.render();
this._checkForSelectedSeason();
},
renderDetail: function() {
if (isLandingPageVisible()) {
return this._model.getEditText();
}
var buff = [];
$A(this.getModel().getCheckBoxes()).each(function(e) { buff.push(e.getName()) });
buff.push([this.getModel().getMinPriceText('$0'),
this.getModel().getMaxPriceText('No Limit')].join(' to '));
return buff.join('<br />');
},
getDefaultDetailText: function() {
if (isLandingPageVisible()) {
return 'Add Rental Terms and Price';
}
return 'All Rental Terms/Any Price';
},
renderReviseLink: function() {
if (isLandingPageVisible()) {
return "";
}
return FilterView.prototype.renderReviseLink.call(this);
},
_checkForSelectedSeason: function() {
if (this.getRentalPeriodSeason()) {
this.getModel().clear();
var values = this.getRentalPeriodSeason().readAttribute('value').split("|");
this.getModel().addCheckBox(Object.extend(new CheckBox(values[0], 0, values[1])));
}
},
getRentalPeriodSeason: function() {
return $('selectedRentalPeriodSeason');
}
});
RatesAndAvailabilityPanelView = Class.create();
Object.extend(RatesAndAvailabilityPanelView.prototype, {
initialize: function(model, checkBoxDivId) {
this.constructor = RatesAndAvailabilityPanelView; // Safari Fix
this._model = model;
}
});
BedBathSizeFilterModel = Class.create();
Object.extend(BedBathSizeFilterModel.prototype, FilterModel.prototype);
Object.extend(BedBathSizeFilterModel.prototype, {
initialize: function(){
FilterModel.prototype.initialize.call(this, "bedbathsize");
this.constructor = BedBathSizeFilterModel; // Safari Fix
},
setBedrooms: function(numBedrooms, numBedroomsText){
this._numBedrooms = null;
if(numBedrooms!=-1){
this._numBedrooms = numBedrooms;
this._numBedroomsText = numBedroomsText;
}
this.notifyChange();
},
getBedrooms: function(){
return this._numBedrooms;
},
getBedroomsText: function(defaultText) {
if (this.getBedrooms()) {
return 'Bedrooms: ' + this._numBedroomsText;
}
return defaultText;
},
setBathrooms: function(numBathrooms, numBathroomsText){
this._numBathrooms = null;
this._numBathroomsText = '';
if(numBathrooms!=0){
this._numBathrooms = numBathrooms;
this._numBathroomsText = numBathroomsText;
}
this.notifyChange();
},
getBathrooms: function(){
return this._numBathrooms;
},
getBathroomsText: function(defaultText) {
if (this.getBathrooms()) {
return "Bathrooms: " + this._numBathroomsText;
}
return defaultText;
},
dump: function(){
dumpArray = {};
dumpArray._filterName = this._filterName;
if(this._numBedrooms) {
dumpArray._numBedrooms = this._numBedrooms;
dumpArray._numBedroomsText = this._numBedroomsText;
}
if(this._numBathrooms) {
dumpArray._numBathrooms = this._numBathrooms;
dumpArray._numBathroomsText = this._numBathroomsText;
}
return dumpArray;
},
equals: function(other) {
return other._numBedrooms == this._numBedrooms
&& other._numBathrooms == this._numBathrooms
},
isEmpty:function(){
return !this._numBedrooms && !this._numBathrooms;
},
clear:function(){
this._numBedrooms = null;
this._numBathrooms = null;
this.notifyChange();
}
});
BedBathSizeFilterModel.scoop = function(dump){
return Object.extend(new BedBathSizeFilterModel(), dump);
};
BedBathSizeFilterView = Class.create();
Object.extend(BedBathSizeFilterView.prototype, FilterView.prototype);
Object.extend(BedBathSizeFilterView.prototype, {
initialize: function(model, detailElement, headerElement) {
FilterView.prototype.initialize.call(this, model, detailElement, headerElement);
this.render();
},
renderDetail: function() {
if(isLandingPageVisible()) {
return "Edit Bed or Bath Count";
}
var model = this.getModel();
var buff = [];
this._renderBedrooms(model, buff);
this._renderBathrooms(model, buff);
return buff.join('<br />');
},
getDefaultDetailText: function(){
if(isLandingPageVisible()) {
return "Add Bed or Bath Count";
}
return 'Any Beds/Any Baths';
},
renderReviseLink:function(){
if(isLandingPageVisible()) {
return "";
}
return FilterView.prototype.renderReviseLink.call(this);
},
_renderBedrooms: function(model, buff) {
var inbuff =  [];
inbuff.push(model.getBedroomsText('Any Beds'));
buff.push(inbuff.join(""));
},
_renderBathrooms: function(model,buff) {
var inbuff = [];
inbuff.push(model.getBathroomsText('Any Baths'));
buff.push(inbuff.join(""));
}
});
LetterFromFormFilterModel = Class.create();
Object.extend(LetterFromFormFilterModel.prototype, FilterModel.prototype);
Object.extend(LetterFromFormFilterModel.prototype, {
initialize: function() {
FilterModel.prototype.initialize.call(this, "LetterFromForm");
this.constructor = LetterFromFormFilterModel; // Safari Fix
},
dump: function() {
dumpArray = {};
dumpArray._name = $('letterFromForm').value;
dumpArray._searchFieldFromForm = $('searchFieldFromForm').value;
return dumpArray;
},
isEmpty: function() {
return $('letterFromForm').value == "";
},
equals: function(other) {
return true;
}
});
LetterFromFormFilterModel.scoop = function(dump) {
return Object.extend(new LetterFromFormFilterModel(), dump);
};
InteriorLotSizeFilterModel = Class.create();
Object.extend(InteriorLotSizeFilterModel.prototype, FilterModel.prototype);
Object.extend(InteriorLotSizeFilterModel.prototype, {
initialize: function(){
FilterModel.prototype.initialize.call(this, "interiorsizelotsize");
this.constructor = InteriorLotSizeFilterModel; // Safari Fix
},
setInteriorSize: function(interiorSize, interiorSizeText)
{
this._interiorSize = null;
this._interiorSizeText = '';
if(interiorSize!='gt_0'){
this._interiorSize = interiorSize;
this._interiorSizeText = interiorSizeText;
}
this.notifyChange();
},
getInteriorSize: function(){
return this._interiorSize;
},
getInteriorSizeText: function(defaultText) {
if (this.getInteriorSize()) {
return 'Interior Size: ' + this._interiorSizeText;
}
return defaultText;
},
setLotSize: function(lotSize, lotSizeText)
{
this._lotSize = null;
this._lotSizeText = '';
if(lotSize!='gt_0') {
this._lotSize = lotSize;
this._lotSizeText = lotSizeText;
}
this.notifyChange();
},
getLotSize: function(){
return this._lotSize;
},
getLotSizeText: function(defaultText) {
if (this.getLotSize()) {
return 'Lot Size: ' + this._lotSizeText;
}
return defaultText;
},
setInteriorSizeUnit: function(unit){
this._interiorSizeUnit = unit;
this.notifyChange(this);
},
getInteriorSizeUnit: function(){
return this._interiorSizeUnit;
},
setLotSizeUnit: function(value) {
this._lotSizeUnit = value;
this.notifyChange();
},
getLotSizeUnit: function() {
return this._lotSizeUnit;
},
resetInteriorSize: function() {
this.setInteriorSize('gt_0');
},
resetLotSize: function() {
this.setLotSize('gt_0');
},
dump: function(){
dumpArray = {};
dumpArray._filterName = this._filterName;
if(this._interiorSize) {
dumpArray._interiorSize = this._interiorSize;
dumpArray._interiorSizeText = this._interiorSizeText;
}
if(this._lotSize) {
dumpArray._lotSize = this._lotSize;
dumpArray._lotSizeText = this._lotSizeText;
}
return dumpArray;
},
equals: function(other) {
return other._interiorSize == this._interiorSize
&& other._lotSize == this._lotSize
},
isEmpty:function(){
return !this._interiorSize && !this._lotSize;
},
clear:function(){
this._interiorSize = null;
this._lotSize = null;
this.notifyChange();
}
});
InteriorLotSizeFilterModel.scoop = function(dump){
return Object.extend(new InteriorLotSizeFilterModel(), dump);
};
InteriorLotSizeFilterView = Class.create();
Object.extend(InteriorLotSizeFilterView.prototype, FilterView.prototype);
Object.extend(InteriorLotSizeFilterView.prototype, {
initialize: function(model, detailElement, headerElement, hideLotSize) {
FilterView.prototype.initialize.call(this, model, detailElement, headerElement);
this._hideLotSize = hideLotSize;
this.render();
},
renderDetail: function() {
var model = this.getModel();
var buff = [];
this._renderInteriorSize(model,buff);
if(!this._hideLotSize) {
this._renderLotSize(model,buff);
}
return buff.join('<br />');
},
getDefaultDetailText: function(){
if(this._hideLotSize) {
return 'All Interior Sizes';
}
return 'All Interior Sizes<br />All Lot Sizes';
},
_renderInteriorSize: function(model,buff)
{
var inbuff = [];
inbuff.push(model.getInteriorSizeText("All Interior Sizes"));
buff.push(inbuff.join(""));
},
_renderLotSize: function(model,buff)
{
var inbuff = [];
inbuff.push(model.getLotSizeText('All Lot Sizes'));
buff.push(inbuff.join(""));
}
});
InteriorLotSizePanelView = Class.create();
InteriorLotSizePanelView.INTERIOR_SIZE_SELECT = new Select("selectedInteriorSize");
InteriorLotSizePanelView.INTERIOR_SIZE_UNIT_SELECT = new Select("selectedInteriorSizeUnit");
InteriorLotSizePanelView.LOT_SIZE_SELECT = new Select("selectedLotSize");
InteriorLotSizePanelView.LOT_SIZE_UNIT_SELECT = new Select("selectedLotSizeUnit");
Object.extend(InteriorLotSizePanelView.prototype, {
initialize: function(model) {
this._model = model;
model.addChangeListener(this);
this._bindEventListeners();
},
onChange:function() {
//place holder to move all code out of sothebys.js for this panel
},
_bindEventListeners:function() {
InteriorLotSizePanelView.INTERIOR_SIZE_UNIT_SELECT.addChangeListener(
this._handleInteriorSizeUnitChange.bind(this));
InteriorLotSizePanelView.LOT_SIZE_UNIT_SELECT.addChangeListener(
this._handleLotSizeUnitChange.bind(this));
},
_handleLotSizeUnitChange:function() {
var unit = InteriorLotSizePanelView.LOT_SIZE_UNIT_SELECT.getSelectionValue();
var options = InteriorSizeLotSizeTemplateFactory.createLotSize(unit);
InteriorLotSizePanelView.LOT_SIZE_SELECT.update(options);
},
_handleInteriorSizeUnitChange:function() {
var unit = InteriorLotSizePanelView.INTERIOR_SIZE_UNIT_SELECT.getSelectionValue();
var options = InteriorSizeLotSizeTemplateFactory.createInteriorSize(unit);
InteriorLotSizePanelView.INTERIOR_SIZE_SELECT.update(options);
}
});
AgentNameSearchFilterModel = Class.create();
Object.extend(AgentNameSearchFilterModel.prototype, FilterModel.prototype);
Object.extend(AgentNameSearchFilterModel.prototype, {
initialize: function(){
FilterModel.prototype.initialize.call(this, "AgentNameSearch");
this.constructor = AgentNameSearchFilterModel; // Safari Fix
this._name = '';
this._searchedFor = '';
},
setName: function(name) {
this._name = name;
this.notifyChange();
},
getName: function() {
return this._name;
},
pushSearchedName: function() {
this._searchedFor = this._name;
this.notifyChange();
},
getSearchedName: function() {
return this._searchedFor;
},
isEmpty: function() {
return this._name == '';
},
equals: function(other) {
return other._name == this._name;
},
clear: function() {
this._name = '';
this._searchedFor = '';
this.notifyChange();
},
dump: function() {
dumpArray = {};
dumpArray._name = this._name;
return dumpArray;
}
});
AgentNameSearchFilterModel.scoop = function(dump) {
return Object.extend(new AgentNameSearchFilterModel(), dump);
};
AgentNameSearchFilterView = Class.create();
Object.extend(AgentNameSearchFilterView.prototype, FilterView.prototype);
Object.extend(AgentNameSearchFilterView.prototype, {
initialize: function(model, detailElement, headerElement) {
FilterView.prototype.initialize.call(this, model, detailElement, headerElement);
this._model = model;
this._defaultText = AgentNameSearchFilterView.searchDefaultText();
this._bindActions();
this.setInitialText();
},
_bindActions: function() {
Event.observe($("agentNameSearchButton"), 'click', this.buttonClickHandler.bindAsEventListener(this));
Event.observe($("agentNameSearchInput"), 'keypress', this.keyPressHandler.bindAsEventListener(this));
Event.observe($("agentNameSearchInput"), 'blur', this.blurHandler.bindAsEventListener(this));
Event.observe($("agentNameSearchInput"), 'click', this.textBoxClickHandler.bindAsEventListener(this));
},
setText: function(text) {
$("agentNameSearchInput").value = text;
},
setDefaultText: function() {
this.setText(this._defaultText);
},
clearText: function() {
this.setText('');
},
getText: function() {
return this._model.getName();
},
setInitialText: function() {
if (this.getText().length == 0) {
this.setDefaultText();
} else {
this.render();
}
},
renderDetail: function() {
var dispName = this._model.getSearchedName();
if (dispName != '') {
return 'Displaying Results for "' + dispName + '"';
} else {
return this.getDefaultDetailText();
}
},
getDefaultDetailText: function() {
return "";
},
render: function() {
$("agentNameSearchDD").innerHTML = this.getModel().isEmpty() ? this.getDefaultDetailText() : this.renderDetail();
},
keyPressHandler: function(event) {
var elt = Event.element(event);
if (elt.value != '') {
this._model.setName(elt.value);
}
if (event.keyCode == 13) {
this.buttonClickHandler(event);
}
},
buttonClickHandler: function(event) {
$('searchModelForm').action = "AGENT_NAME_SEARCH";
$('sir_result_sort_by').value = '';
$('sir_result_sort_direction').value = '';
$("agentNameSearchInput").blur();
agentSubmitSearch();
this.setDefaultText();
},
blurHandler: function(event) {
if (this.getText() == '' && $("agentNameSearchInput").value == '') {
this.setDefaultText();
return;
} else if ($("agentNameSearchInput").value == AgentNameSearchFilterView.searchDefaultText()) {
return;
}
var elt = Event.element(event);
this._model.setName(elt.value);
},
textBoxClickHandler: function(event) {
if (this.getText() == '' || $("agentNameSearchInput").value == AgentNameSearchFilterView.searchDefaultText()) {
this.clearText();
}
}
});
AgentNameSearchFilterView.searchDefaultText = function() {
return "Begin Typing First or Last Name";
};
LanguageFilterModel = Class.create();
Object.extend(LanguageFilterModel.prototype, FilterModel.prototype);
Object.extend(LanguageFilterModel.prototype, {
initialize: function() {
FilterModel.prototype.initialize.call(this, "Language");
this._languages = [];
this.constructor = LanguageFilterModel; // Safari Fix
},
addLanguage: function(language) {
this._languages.push(language);
this.notifyChange();
},
removeLanguage: function(language) {
for(var i = 0; i < this._languages.length; i++) {
if(language == this._languages[i]) {
var tmp = this._languages[0];
this._languages[0] = this._languages[i];
this._languages[i] = tmp;
this._languages.shift();
break;
}
}
this.notifyChange();
},
isEmpty: function() {
return this._languages.length == 0;
},
equals: function(other) {
if(other._languages.length != this._languages.length) {
return false;
}
for(var i = 0; i < this._languages.length; i++) {
if(other._languages[i] != this._languages[i]) {
return false;
}
}
return true;
},
clear: function() {
this._languages = [];
this.notifyChange();
},
dump: function() {
dumpArray = {};
dumpArray._languages = this._languages;
return dumpArray;
}
});
LanguageFilterModel.scoop = function(dump) {
return Object.extend(new LanguageFilterModel(), dump);
};
LanguageFilterView = Class.create();
Object.extend(LanguageFilterView.prototype, FilterView.prototype);
Object.extend(LanguageFilterView.prototype, {
initialize: function(model, inputDiv, detailElement, headerElement) {
FilterView.prototype.initialize.call(this, model, detailElement, headerElement);
this._model = model;
this._inputDiv = inputDiv;
},
renderDetail: function() {
return this._model._languages.join('<br/>');
},
getDefaultDetailText: function() {
return "Agents who Speak Any Language";
},
render: function() {
// does nothing unless model has been reset
if(this._model.isEmpty() && $(this._inputDiv)) {
var inpts = $(this._inputDiv).getElementsByTagName('input');
for(var i = 0; i < inpts.length; i++) {
inpts[i].checked = false;
}
}
FilterView.prototype.render.call(this);
}
});
LanguageSearchOptionsPanel = Class.create();
Object.extend(LanguageSearchOptionsPanel.prototype, {
initialize: function(divId) {
this._divId = divId;
this._bindEvents();
},
_bindEvents: function() {
if ($(this._divId)) {
var inpts = $(this._divId).getElementsByTagName('input');
for (var i = 0; i < inpts.length; i++) {
Event.observe(inpts[i], 'click',
function(event) {
var elt = Event.element(event);
var model = getSearchOptionsModel().getFilterModel("language");
if (!elt.checked) {
model.removeLanguage(elt.name);
}
else {
model.addLanguage(elt.name);
}
}
);
}
Event.observe($("languageResetCriteria"), 'click',
function(event) {
resetCriteria(FilterKey.LANGUAGE);
}
);
}
}
});
OfficeLocationFilter = Class.create();
Object.extend(OfficeLocationFilter.prototype, AgentLocationFilterModel.prototype);
var SearchOptionsModel = Class.create();
Object.extend(SearchOptionsModel.prototype, Observable.prototype);
Object.extend(SearchOptionsModel.prototype, {
initialize:function(searchType){
Observable.prototype.initialize.call(this);
this._filterModels = {};
this._searchType = searchType;
},
getFilterModel:function(name){
return this._filterModels[name];
},
getFilterModelKeys:function(){
var keys = new Array();
for(var key in this._filterModels){
keys.push(key);
}
return keys;
},
clear: function() {
for(var key in this._filterModels){
this._filterModels[key].clear();
}
},
dump:function(){
var modelsDump = {};
var allModelsEmpty = true;
for(var name in this._filterModels){
if(!this._filterModels[name].isEmpty()){
allModelsEmpty = false;
modelsDump[name] = this._filterModels[name].dump();
}
}
if(allModelsEmpty && this._searchType == 'search'){
return {};
}
return {_filterModels:modelsDump, _searchType:this._searchType};
},
equals:function(other){
if(!other){
return false;
}
if(this._searchType != other._searchType) return false;
if( this._getModelKeys().join('__') != other._getModelKeys().join('__')){
return false;
}
for(var name in this._filterModels){
if(typeof other._filterModels[name] == 'undefined' ||
!this._filterModels[name].equals(other._filterModels[name])){
return false;
}
}
return true;
},
_getModelKeys:function(){
var keys = [];
for(var key in this._filterModels){
keys.push(key);
}
return keys;
},
setSearchType: function(type) {
this._searchType = type;
},
getSearchType: function() {
return this._searchType;
},
addFilterModel: function(key, filterModel){
this._filterModels[key] = filterModel;
filterModel.addChangeListener(new BubbleHandler(this));
},
isEmpty:function(){
for(var name in this._filterModels){
if(name!='webregion' && !this._filterModels[name].isEmpty()){
return false;
}
}
return true;
}
});
SearchOptionsModel.scoop = function(dump, pageController) {
if (typeof dump == 'undefined' || !dump) { //added !dump because of safari 3.0
dump = {};
}
var model = new SearchOptionsModel(dump._searchType || 'search');
var modelsToCreate = pageController._filterModelsUsed();
var dumpedModels = dump._filterModels || {};
for (var name in modelsToCreate) {
if (!dumpedModels[name]) {
model.addFilterModel(name, modelsToCreate[name]);
} else {
model.addFilterModel(name, modelsToCreate[name].constructor.scoop(dumpedModels[name]));
}
}
return model;
}
ResultsUpdater = Class.create();
Object.extend(ResultsUpdater.prototype, {
initialize: function(controller) {
this._controller = controller;
this._modelDirty = false;
this._createInterval(this.updateSearchResultsIfModelDirty.bind(this), 300);
},
onChange: function() {
this._modelDirty = true;
},
updateSearchResultsIfModelDirty: function() {
if (this._modelDirty && (typeof window.progressChicken == 'undefined' ||
(!window.progressChicken.isSpinning() &&
!window.progressChicken.isIFrameLoading()))
) {
this._modelDirty = false;
this.doWork(this.onChangeCallback);
}
},
_createInterval: function(callback, delay) {
return setInterval(callback, delay);
},
doWork: function(callback) {
this._controller.updateSearchResults(callback);
}
});
CountUpdater = Class.create();
Object.extend(CountUpdater.prototype, ResultsUpdater.prototype);
Object.extend(CountUpdater.prototype, {
doWork:function(){
this._controller.updateCount();
}
});
TemplateFactory = {};
TemplateFactory.CHECKBOX_TEMPLATE =
'<td class="location_cell #{childrenClass}">\
<div id="#{locationId}_container">\
<div class="checkbox #{checkboxClass}" id="#{locationId}_checkbox">\
</div>\
<div class="area">\
#{locationName}\
</div>\
<div id="#{locationId}_expand" class="expand clickable">\
</div>\
</div>\
</td>';
TemplateFactory.NOT_CHECKED_RADIO_TEMPLATE =
'<td class="location_cell #{childrenClass} radio_cell">\
<div id="#{locationId}_container">\
<input type="radio" class="radio" id="#{locationId}_checkbox" name="RayDeeOh_MutuallyExclusive" /> \
<div class="area">#{locationName}</div>\
<div id="#{locationId}_expand" class="expand clickable" style="display:none"></div>\
</div>\
</td>';
TemplateFactory.CHECKED_RADIO_TEMPLATE =
'<td class="location_cell #{childrenClass}  radio_cell">\
<div id="#{locationId}_container">\
<input type="radio" class="radio" id="#{locationId}_checkbox" name="RayDeeOh_MutuallyExclusive" checked="checked"/> \
<div class="area">#{locationName}</div>\
<div id="#{locationId}_expand" class="expand clickable"></div>\
</div>\
</td>';
InteriorSizeLotSizeTemplateFactory = {};
InteriorSizeLotSizeTemplateFactory.ENGLISH = "English";
InteriorSizeLotSizeTemplateFactory.METRIC = "Metric";
InteriorSizeLotSizeTemplateFactory.METRIC_INTERIOR_SIZE_OPTIONS =
'<option value="gt_0" selected="selected">Show All</option>\
<option value="lt_1500">Up to 140 sq. m</option>\
<option value="gt_1500">140 sq. m or more</option>\
<option value="gt_3000">280 sq. m or more</option>\
<option value="gt_5000">465 sq. m or more</option>\
<option value="gt_7500">700 sq. m or more</option>\
<option value="gt_10000">930 sq. m or more</option>';
InteriorSizeLotSizeTemplateFactory.ENGLISH_INTERIOR_SIZE_OPTIONS =
'<option value="gt_0" selected="selected">Show All</option>\
<option value="lt_1500">Up to 1500 sq. ft</option>\
<option value="gt_1500">1500 sq. ft or more</option>\
<option value="gt_3000">3000 sq. ft or more</option>\
<option value="gt_5000">5000 sq. ft or more</option>\
<option value="gt_7500">7500 sq. ft or more</option>\
<option value="gt_10000">10000 sq. ft or more</option>';
InteriorSizeLotSizeTemplateFactory.ENGLISH_LOT_SIZE_OPTIONS =
'<option value="gt_0" selected="selected">Show All</option>\
<option value="lt_5">Up to 5 Acres</option>\
<option value="gt_5">5 Acres or more</option>\
<option value="gt_10">10 Acres or more</option>\
<option value="gt_25">25 Acres or more</option>\
<option value="gt_50">50 Acres or more</option>\
<option value="gt_100">100 Acres or more</option>';
InteriorSizeLotSizeTemplateFactory.METRIC_LOT_SIZE_OPTIONS=
'<option value="gt_0" selected="selected">Show All</option>\
<option value="lt_5">Up to 2 Hectares</option>\
<option value="gt_5">2 Hectares or More</option>\
<option value="gt_10">4 Hectares or More</option>\
<option value="gt_25">10 Hectares or More</option>\
<option value="gt_50">20 Hectares or More</option>\
<option value="gt_100">40 Hectares or More</option>';
InteriorSizeLotSizeTemplateFactory.createInteriorSize = function(type) {
if(type==InteriorSizeLotSizeTemplateFactory.METRIC) {
return InteriorSizeLotSizeTemplateFactory.METRIC_INTERIOR_SIZE_OPTIONS;
}
if(type==InteriorSizeLotSizeTemplateFactory.ENGLISH) {
return InteriorSizeLotSizeTemplateFactory.ENGLISH_INTERIOR_SIZE_OPTIONS;
}
}
InteriorSizeLotSizeTemplateFactory.createLotSize = function(type){
if(type==InteriorSizeLotSizeTemplateFactory.ENGLISH) {
return InteriorSizeLotSizeTemplateFactory.ENGLISH_LOT_SIZE_OPTIONS;
}
if(type==InteriorSizeLotSizeTemplateFactory.METRIC) {
return InteriorSizeLotSizeTemplateFactory.METRIC_LOT_SIZE_OPTIONS;
}
}
/*
* Global Variable Declarations
*/
var rootExpandedView = null;
CheckBoxState = {
UnChecked: 1,
Partial: 2,
Checked: 3
};
CheckBoxClasses = {};
CheckBoxClasses[CheckBoxState.UnChecked] = 'cleared';
CheckBoxClasses[CheckBoxState.Partial] = 'dashed';
CheckBoxClasses[CheckBoxState.Checked] = 'checked';
CheckBoxMessages = {};
CheckBoxMessages[CheckBoxState.Checked] = 'Searching All ';
CheckBoxMessages[CheckBoxState.Partial] = 'Searching Some ';
CheckBoxMessages[CheckBoxState.UnChecked] = 'Not Searching ';
LocationNode = Class.create();
Object.extend(LocationNode.prototype, Observable.prototype);
Object.extend(LocationNode.prototype, {
initialize: function(locationId, locationName, children) {
Observable.prototype.initialize.call(this);
this.locationId = locationId;
this.locationName = locationName;
this._state = CheckBoxState.UnChecked;
this._stateChangedListeners = new Array();
this._toggleListener = new Function();
this._children = children || [];
var self = this;
this._children.each(function(child){child.setParentNode(self);});
},
collectCheckedLocationIds:function(buffer){
if(this.isChecked()){
buffer.push(this.locationId);
}else if(this.isPartial()){
this.children().each(function(child){child.collectCheckedLocationIds(buffer);});
}
},
getLocationId: function() {
return this.locationId;
},
setParentNode:function(parent){
this._parentNode = parent;
},
getParentNode: function(){
return this._parentNode || {_childStateChanged:function(){},children:function(){return [];},setState:function(){},setStateFromChild:function(){}};
},
getState: function() {
return this._state;
},
isStateDifferent: function(otherState) {
return this._state != otherState;
},
setState: function(state, fromParent) {
var oldState = this._state;
this._state = state;
if(oldState != this._state){
this._switchState(state, fromParent)
}
this.notifyChange();
},
setStateFromChild:function(state){
if(!this.ignoreChildChanges){
this._state = state;
this.getParentNode().setStateFromChild(this._determineParentStateFromSiblings());
this.notifyChange();
}
},
_switchState:function(newState, fromParent) {
this.ignoreChildChanges = true;
if(this.isPartial() == false){
var children = this.children();
if(children.length > 0 && newState == CheckBoxState.Checked && children[0].isMutuallyExclusive())
children[0].setState(newState, true);
else {
for(var i=0;i<children.length;i++){
children[i].setState(newState, true);
}
}
}
this.getParentNode().setStateFromChild(this._determineParentStateFromSiblings());
// Commented out to fix bug when clicking the expanded view checkbox was not cascading the state to its parent
//		if(!fromParent){
//			this.getParentNode().setStateFromChild(this._determineParentStateFromSiblings());
//		}
this.ignoreChildChanges = false;
},
notifyChange:function(){
var node = this;
for(var i=(this._stateChangedListeners.length-1);i>=0;i--){
this._stateChangedListeners[i](node);
}
},
addChangeListener: function(listener) {
this._stateChangedListeners.push(listener);
},
isChecked:function(){
return this.getState()==CheckBoxState.Checked;
},
isPartial:function(){
return this.getState()==CheckBoxState.Partial;
},
isUnChecked:function(){
return this.getState()==CheckBoxState.UnChecked;
},
toggle: function(fromParent){
var state = CheckBoxState.Checked;
if(this.isChecked()){
state = CheckBoxState.UnChecked;
}
this.setState(state, fromParent);
this._toggleListener(this);
},
toggleStateTo:function(state){
this.setState(state);
this._toggleListener(this);
},
toggleStateToUnchecked:function(){
this.toggleStateTo(CheckBoxState.UnChecked);
},
setToggleListener: function(listener) {
this._toggleListener = listener;
},
children: function() {
return this._children;
},
isMutuallyExclusive: function() {
return false;
},
_determineParentStateFromSiblings: function() {
var siblings = this.getParentNode().children();
for(var i=0;i<siblings.length;i++){
if(siblings[i].getState()!=this.getState()){
return CheckBoxState.Partial;
}
}
return this.getState();
},
restore: function(checkedLocations) {
if(typeof checkedLocations[this.locationId]!='undefined') {
this.setState(CheckBoxState.Checked);
}
else {
this.setState(CheckBoxState.UnChecked);
this.children().each(function(child){
child.restore(checkedLocations);
});
}
}
});
RadioButtonLocationNode = Class.create();
Object.extend(RadioButtonLocationNode.prototype, LocationNode.prototype);
Object.extend(RadioButtonLocationNode.prototype,  {
initialize: function(locationId, locationName, children) {
LocationNode.prototype.initialize.call(this, locationId, locationName, children);
},
setState: function(state, fromParent) {
// Commented out as this would not set state of a unchecked radio child when its parent is being checked
//		if(fromParent && this.isUnChecked())
//			return;
this._state = state;
this._switchState(state, fromParent);
this.notifyChange();
},
toggle: function(cascadeOverRadioButtons) {
//		if(!this.isUnChecked())
//			return;
this._setSiblingState();
LocationNode.prototype.toggle.call(this, cascadeOverRadioButtons);
},
_setSiblingState:function() {
var siblings = this._parentNode.children();
for(var i = 0; i < siblings.length; i++) {
if(siblings[i] != this && !siblings[i].isUnChecked()) {
siblings[i].setState(CheckBoxState.UnChecked);
siblings[i]._toggleListener(siblings[i]);
}
}
},
isMutuallyExclusive: function() {
return true;
},
_determineParentStateFromSiblings:function(){
var siblings = this.getParentNode().children();
for(var i=0;i<siblings.length;i++){
if(siblings[i].getState() == CheckBoxState.Checked) {
return CheckBoxState.Checked;
}
}
return this.getState();
},
setStateFromChild:function(state){
if(!this.ignoreChildChanges){
this._state = state;
this.getParentNode().setStateFromChild(this._determineParentStateFromSiblings());
this.notifyChange();
}
},
setStateFromChild:function(state){
if(!this.ignoreChildChanges){
this._state = state;
this._setSiblingState();
this.getParentNode().setStateFromChild(this._determineParentStateFromSiblings());
this.notifyChange();
}
}
});
CollapsedLocationView = Class.create();
CollapsedLocationView.prototype = {
initialize: function(locationNode, controller) {
this.locationNode = locationNode;
this._controller = controller;
},
render: function(level, row) {
var monkeyRow = row || new Row();
this.locationNode.addChangeListener(this._handleStateChanged.bind(this));
var cell = this._createCell(monkeyRow);
this.checkbox = cell.getElementsBySelector('#'+this.locationNode.locationId + '_checkbox').first();
var area = cell.getElementsBySelector('.area').first();
this._addBehaviorToRow(cell, level+1);
return cell;
},
_addBehaviorToRow: function(cell, level) {
var locationId = this.locationNode.locationId;
var element = cell.getElementsBySelector('#'+locationId + '_expand')[0];
Event.observe(element, 'click', this._handleExpandMouseOver.bindAsEventListener(this, level));
//        Event.observe(element, 'mouseout', this._handleExpandMouseOut.bindAsEventListener(this, level));
//        Event.observe(element, 'click', this._handleExpandClicked.bindAsEventListener(this, level));
Event.observe(this.checkbox, 'click', this._handleCheckBoxClicked.bind(this));
},
_handleStateChanged:function(){
if(this.locationNode.isMutuallyExclusive()) {
var checked = this.locationNode.getState() != CheckBoxState.UnChecked;
this.checkbox.checked = checked;
var expandedElement = $(this.locationNode.locationId + '_expand');
if(checked && expandedElement) { expandedElement.show(); }
else if(expandedElement) { expandedElement.hide(); }
}
else {
this.checkbox.className = 'checkbox '+CheckBoxClasses[this.locationNode.getState()];
}
},
_handleCheckBoxClicked:function(){
if(this.locationNode.isMutuallyExclusive()){
var nodes = this.locationNode.getParentNode().children();
for(var i=0;i<nodes.length;i++){
var expandedElement = $(nodes[i].locationId + '_expand');
expandedElement.hide();
}
var expandedElement = $(this.locationNode.locationId + '_expand');
expandedElement.show();
}else{
if(typeof WebTrendsAnalyzer == 'function'){
(new WebTrendsAnalyzer()).fireWebTrendAction(
WebTrendsAnalyzer.CreateActionForLocationCheckbox(this.locationNode.locationId, !this.locationNode.isChecked()));
}
this.locationNode.toggle(false);
}
},
_handleExpandMouseOver:function(e, level){
this._controller.handleExpandMouseOver(this.locationNode, level, e);
},
_handleExpandMouseOut:function(){
this._controller.handleExpandMouseOut(this.locationNode);
},
_handleExpandClicked:function(e){
this._controller.handleExpandClicked(this.locationNode, e);
},
_createCell: function(row) {
var model = Object.extend({
checkboxClass: CheckBoxClasses[this.locationNode.getState()],
childrenClass: this.locationNode.children().length > 0 ? 'has_children' : 'no_children'
}, this.locationNode);
var template = this._createTemplate(this.locationNode.isMutuallyExclusive(), this.locationNode.getState() == CheckBoxState.Checked);
return row.addCell(template, model);
},
_createTemplate: function(isMutuallyExclusive, isChecked) {
if(isMutuallyExclusive)
{
if(isChecked)
return TemplateFactory.CHECKED_RADIO_TEMPLATE;
return TemplateFactory.NOT_CHECKED_RADIO_TEMPLATE;
}
return TemplateFactory.CHECKBOX_TEMPLATE;
}
};
ExpandedLocationView = Class.create();
ExpandedLocationView.TEMPLATE_HTML =
'<td colspan="#{numColumns}">\
<div class="clickable checkbox "#{checkboxStateClass}" id="#{locationId}_checkbox_expanded"></div>\
<h5 class="clickable" id="#{locationId}_locationName">#{locationName}</h5>\
</td>';
ExpandedLocationView.prototype = {
initialize: function(locationNode, level, controller) {
this._locationNode = locationNode;
this.level = level || 0;
this._locationNode.addChangeListener(this.updateCheckBoxDisplay.bind(this));
this._lastRelativeToId = null;
this._controller = controller;
ExpandedLocationView.effectOnLocationNode = null;
ExpandedLocationView.effect1 = null;
ExpandedLocationView.effect2 = null;
ExpandedLocationView.effect3 = null;
},
getLocationNode: function() {
return this._locationNode;
},
render: function(relativeToElement) {
if(relativeToElement){
this._lastRelativeToId = relativeToElement.id;
}
this.hideChildren();
var divForLevel = this._getOrCreateDivForLevel();
var tableForLocationNode = this._getOrCreateTableForLocationNode();
divForLevel.appendChild(tableForLocationNode);
document.body.appendChild(divForLevel);
this.positionChildren(divForLevel, relativeToElement);
this.updateCheckBoxDisplay();
return divForLevel;
},
setNodeState: function(state){
this._locationNode.setState(state);
this.updateCheckBoxDisplay();
},
updateCheckBoxDisplay:function(){
var div = $(this._locationNode.locationId+'_checkbox_expanded');
if(!div){
return;
}
div.className = 'checkbox '+CheckBoxClasses[this._locationNode.getState()];
},
positionChildren: function(objNodeDiv, relativeToElement){
Element.hide(objNodeDiv);
var parentNodeDiv = $('location_'+(this.level-1));
objNodeDiv.className = 'browse';
objNodeDiv.style.zindex = '10';
var margin = 7;
var pos = findPos(relativeToElement);
objNodeDiv.style.left = (pos.left + relativeToElement.getWidth() +  margin) + 'px';
objNodeDiv.style.top = pos.top + 'px';
this.animatePreview(objNodeDiv);
},
isVisible:function(){
return $('location_'+this.level)!=null;
},
animatePreview:function(objNodeDiv){
this.active = false;
this.showChildCells(objNodeDiv);
new Effect.Appear(objNodeDiv,{duration:0.3, afterFinishInternal:this._fixTableWidthOnEffectElement.bind(this)});
},
_fixTableWidthOnEffectElement:function(effect){
var table = effect.element.down('table');
if(table){
var origWidth = table.getDimensions().width;
table.style.width = origWidth+'px';
}
},
showChildCells:function(objNodeDiv){
var self = this;
$A(objNodeDiv.getElementsByTagName('td')).each(
function(e){self.showCell(e);}
);
},
showCell:function(e){
//		new Effect.Appear(e,{from:e.getOpacity(),to:1});
e.style.visibility='visible';
if(e.className.indexOf('radio_cell')!=-1){
//this oddness is for a bug in IE where it refuses to display the
//italic text when the parent is un-hidden.
e.style.fontStyle = '';
e.style.fontStyle = 'italic';
}
},
activate: function(){
var objNodeDiv = $('location_'+this.level);
var parentNodeDiv = $('location_'+(this.level-1));
//to fix the bug of the location widget being creatd in the far right bottom corner
//this seems to fix this bug :)
if (parentNodeDiv && objNodeDiv.offsetLeft - parentNodeDiv.offsetLeft > 0)
{
this.active = true;
ExpandedLocationView.effectOnLocationNode = this._locationNode.locationId;
this._fixTableWidthOnEffectElement({element:objNodeDiv});
ExpandedLocationView.effect1 = new Effect.Move(
objNodeDiv, {
x:-(objNodeDiv.offsetLeft - parentNodeDiv.offsetLeft - 10),
y:-(objNodeDiv.offsetTop - parentNodeDiv.offsetTop - 35),
duration: 0.3,
afterFinishInternal: function(effect) {
ExpandedLocationView.effect1 = null;
ExpandedLocationView.effectOnLocationNode = null;
}
}
);
ExpandedLocationView.effect2 = new Effect.Appear(objNodeDiv, {from:0.5, to:1, duration:0.3});
ExpandedLocationView.effect3 = new Effect.FadeCollection(parentNodeDiv.getElementsByTagName('td'),
{
duration: 0.3,
afterFinishInternal: function(effect)
{
effect.element.setStyle({opacity: 1, visibility:'hidden'});
}
}
);
}
},
isActive: function(){
return this.active;
},
hide:function(){
this.active = false;
this.hideChildren();
this._removeCurrentLevelDiv();
},
hideChildren: function(){
var currLevel = this.level+1;
var child = this._getLocationDiv(currLevel);
while(child){
child.parentNode.removeChild(child);
++currLevel;
child = $('location_'+currLevel);
}
},
_getLocationDiv: function(level){
var currentLevel = level || this.level;
return $('location_' + currentLevel);
},
_getOrCreateTableForLocationNode: function(){
var table = ExpandedLocationView.RENDERED_TABLES_BY_LOCATION_ID[this._locationNode.locationId];
if(!table){
var children = this._locationNode.children();
table = this._createTable(children);
this._addBehaviorToDiv(table);
ExpandedLocationView.RENDERED_TABLES_BY_LOCATION_ID[this._locationNode.locationId] = table;
}
return table;
},
calculateNumColumns: function(){
var numChildren = this._locationNode.children().length;
var propsPerLevel = 15+this.level;
return Math.ceil(numChildren/propsPerLevel);
},
_createTable: function(children) {
var numColumns = this.calculateNumColumns();
var templateModel = Object.extend(
{
numColumns: numColumns,
checkboxStateClass: CheckBoxClasses[this._locationNode.getState()]
}, this._locationNode);
var table = new Table();
var parentRow = table.createAndAddRow();
parentRow.addCell(ExpandedLocationView.TEMPLATE_HTML, templateModel);
var currentRow = table.createAndAddRow();
for(var i=0;i<children.length;i++){
if(currentRow.cellCount() >= numColumns){
currentRow = table.createAndAddRow();
}
(new CollapsedLocationView(children[i], this._controller)).render(this.level, currentRow);
}
return table.render();
},
_getOrCreateDivForLevel: function(){
var div = null;
var divId = 'location_' + this.level;
this._removeCurrentLevelDiv(divId);
div = document.createElement('div');
div.id = divId;
div.style.display='block';
return div;
},
_removeCurrentLevelDiv: function() {
var divId = 'location_' + this.level;
div = $(divId);
if(div){
div.parentNode.removeChild(div);
}
},
_addBehaviorToDiv: function(div) {
var checkBoxElement = Element.getElementsBySelector(div, '#'+this._locationNode.locationId + '_checkbox_expanded')[0];
var locationNameElement = Element.getElementsBySelector(div, "#"+this._locationNode.locationId+"_locationName")[0];
if(checkBoxElement){
Event.observe(checkBoxElement, 'click', this._handleCheckBoxClicked.bind(this));
}
if(locationNameElement){
Event.observe(locationNameElement, 'click', this._handleNameClicked.bind(this));
}
//Event.observe(div, 'mouseover', this._handleMouseOver.bind(this));
},
_handleMouseOver:function(){
if(!this.isActive()){
this.activate();
}
},
_handleNameClicked:function(){
this._controller.handleNameClicked(this._locationNode);
},
_handleCheckBoxClicked:function(){
if(typeof WebTrendsAnalyzer == 'function'){
(new WebTrendsAnalyzer()).fireWebTrendAction(
WebTrendsAnalyzer.CreateActionForLocationCheckbox(this._locationNode.locationId, !this._locationNode.isChecked()));
}
this._locationNode.toggle(true);
}
};
ExpandedLocationView.RENDERED_TABLES_BY_LOCATION_ID = {}
LocationController = Class.create();
LocationController.prototype = {
initialize: function(locationModel, relativeToElement) {
var locationNode = locationModel.getRootLocationNode();
this._locationModel = locationModel;
this._rootExpandedView = new ExpandedLocationView(locationNode, 0, this);
this._rootExpandedView.render(relativeToElement);
this.EXPANDED_VIEWS = {};
this.EXPANDED_VIEWS[locationNode.locationId] = this._rootExpandedView;
this._setToggleListener(locationModel);
},
_createFilterDisplay: function(){
return new LocationFilterDisplay(this._locationModel);
},
_setToggleListener: function(locationModel) {
locationModel.setToggleListener(this._handleToggleComplete.bind(this));
},
_handleToggleComplete: function(node) {
},
handleExpandMouseOver: function(locationNode, level, e) {
if(ExpandedLocationView.effect1 != null){
return;
}
var expandedView = this.getExpandedView(locationNode, level);
if(!expandedView.isActive() || !expandedView.isVisible()){
expandedView.render(Event.element(e));
setTimeout(expandedView.activate.bind(expandedView), 100);
}
},
handleExpandMouseOut: function(locationNode) {
if(ExpandedLocationView.effect1 != null){
return;
}
var expandedView = this.EXPANDED_VIEWS[locationNode.locationId];
if(expandedView && !expandedView.isActive()){
expandedView.hide();
}
},
handleExpandClicked: function(locationNode, e) {
var expandedView = this.EXPANDED_VIEWS[locationNode.locationId];
if(expandedView){
expandedView.activate(e);
}
},
handleNameClicked: function(locationNode) {
if(ExpandedLocationView.effectOnLocationNode == locationNode.locationId)
return;
var expandedView = this.EXPANDED_VIEWS[locationNode.locationId];
if(ExpandedLocationView.effect1){
ExpandedLocationView.effect1.cancel();
ExpandedLocationView.effect1=null;
}
if(ExpandedLocationView.effect2){
ExpandedLocationView.effect2.cancel();
ExpandedLocationView.effect2 = null;
}
if(ExpandedLocationView.effect3){
ExpandedLocationView.effect3.cancel();
ExpandedLocationView.effect3 = null;
}
expandedView.hideChildren();
expandedView.showChildCells($('location_'+expandedView.level));
},
getExpandedView: function(locationNode, level) {
var expandedView =  this.EXPANDED_VIEWS[locationNode.locationId];
if(typeof expandedView == "undefined") {
expandedView = new ExpandedLocationView(locationNode, level, this);
this.EXPANDED_VIEWS[locationNode.locationId] = expandedView;
}
return expandedView;
},
getRootExpandedView: function() {
return this._rootExpandedView;
}
};
function ShowAllTemplate(displayLeafNodes){
this._displayLeafNodes = displayLeafNodes;
}
ShowAllTemplate.prototype.apply = function(nodes){
if(this._displayLeafNodes){
nodes = this.flatten(nodes);
}
var mssg = new Array();
var numDisplayed = 0;
for(var i=0; (i<nodes.length) && (numDisplayed<this.getMaximumDisplay());i++) {
if(nodes[i].getState() != CheckBoxState.UnChecked) {
++numDisplayed;
mssg.push(nodes[i].locationName);
mssg.push('<br />');
}
}
return mssg.join('');
}
ShowAllTemplate.prototype.flatten = function(arr, leaves){
if(!leaves){
leaves = [];
}
for(var i=0;i<arr.length;i++){
if(arr[i].children().length>0){
this.flatten(arr[i].children(), leaves);
}else{
leaves.push(arr[i]);
}
}
return leaves;
}
ShowAllTemplate.prototype.getMaximumDisplay =function(){
return 999;
}
function ShowPartialTemplate(displayLeafNodes){
ShowAllTemplate.call(this, displayLeafNodes);
}
ShowPartialTemplate.prototype = new ShowAllTemplate();
ShowPartialTemplate.prototype.getMaximumDisplay = function(){
return 5;
}
function showLocationOption(locationDivToUse, startingLocationId, level, expandDivClicked)
{
if($(locationDivToUse))Element.remove(locationDivToUse);
//create and add locationDivToUse to DOM
var parent = (level == 0) ? $('locationParentNode') : expandDivClicked.parentNode;
var locationModel = getPageController().getSearchOptionsModel().getFilterModel(FilterKey.LOCATION);
if(!locationModel.isQuickSearch()) {
locationController = new LocationController(locationModel, parent);
rootExpandedView = locationController.getRootExpandedView();
Event.observe(document.body, 'click', function(e){ hideLocationWidget(e); });
}
}
function findPos(obj) {
var curleft = obj.offsetLeft;
var curtop = obj.offsetTop;
var done = false;
try{
while (!done && (obj = Position.offsetParent(obj))) {
if(obj == document.body){
done = true;
}else{
curleft += obj.offsetLeft;
curtop  += obj.offsetTop;
}
}
}catch(err){
// sometimes IE has an error but not sure why
}
return {left:curleft,top:curtop};
}
function hideLocationWidget(e) {
var evnt = arguments[0] || window.event,
clickedElement = evnt.target || evnt.srcElement;
if(clickedElement.innerHTML.indexOf('Modify Search') != -1) return;
while(clickedElement != document.body) {
if(
clickedElement.className.indexOf('location_cell') != -1 ||
clickedElement.id == 'locationDT'
)
return;
clickedElement = clickedElement.parentNode;
}
rootExpandedView.hide();
Event.stopObserving(document.body, 'click');
}
Url = Class.create();
Object.extend(Url.prototype ,{
initialize: function(url){
var index = url.indexOf('http://');
if(index != -1){
url = url.substring(index);
}
this._url = this._extractUrl(url);
this._params = this._extractParams(url);
},
toUrlString: function() {
if (this._params.length > 0)
return this._url + '?' + this._params.join('&');
else
return this._url;
},
addParameter: function(nameValue){
if (nameValue != '' && nameValue != null)
this._params.push(nameValue);
},
getParamCount: function() {
return this._params.length;
},
_extractParams: function(url) {
var paramSection = url.split('?');
var params = new Array();
if(paramSection.length==1)
return params;
paramSection = paramSection[1].split('&');
for(var i=0; i<paramSection.length; i++){
params.push(paramSection[i]);
}
return params;
},
_extractUrl: function(url) {
return url.split('?')[0];
}
});
PageCache = Class.create();
Object.extend(PageCache.prototype, {
initialize: function(searchOptionsModel, url, cacheElementName, pageNumber) {
this._cacheElementName = cacheElementName || 'searchResultsIframe';
this._url = url || new Url('/search/results.rails');
this.searchOptionsModel = searchOptionsModel || new SearchOptionsModel();
this._pageNumber = pageNumber || 1;
},
getCacheElement: function() {
return $(this._cacheElementName);
},
getUrl: function() {
return this._url.toUrlString();
},
cache: function() {
if (typeof window.progressChicken != 'undefined') {
window.progressChicken.start(true);
}
$('searchModelInput').value = DataSerializer.serialize(this.searchOptionsModel.dump());
$('searchModelPageInput').value = this.getPageNumber();
$('searchModelForm').action = this.getUrl();
$('searchModelForm').target = this.getCacheElement().id;
$('searchModelForm').submit();
},
getPageNumber: function() {
return this._pageNumber;
}
});
CountModel = Class.create();
Object.extend(CountModel.prototype, Observable.prototype);
Object.extend(CountModel.prototype, {
initialize: function() {
Observable.prototype.initialize.call(this);
},
setText: function(text) {
this._text = text;
this._countNumber = text.split("\n")[0];
this._countMessage = text.split("\n")[1];
this.notifyChange();
},
getText: function() {
return this._text;
},
getCountNumber:function(){
return this._countNumber;
},
getCountMessage:function(){
return this._countMessage;
}
})
CountView = Class.create();
Object.extend(CountView.prototype, {
initialize: function(model) {
this._model = model;
model.addChangeListener(this);
},
onChange: function() {
var number = $('propcountNumberOnly') || {innerHTML: ''};
var message = $('propcountMessage') || {innerHTML: ''};
number.innerHTML = this._model.getCountNumber();
message.innerHTML = this._model.getCountMessage();
}
})
CountController = Class.create();
Object.extend(CountController.prototype, {
initialize: function(serverControllerName, model, countActionName) {
this._controllerName = serverControllerName;
this._model = model;
this._countActionName = countActionName || '/Count.rails';
},
getServerControllerName: function(){
return this._controllerName;
},
update: function() {
if(typeof window.progressChicken != 'undefined'){
window.progressChicken.start();
}
var myRequest = new Ajax.Request(this.getUrl(), {
on200: function(transport){
if(transport.responseText.match(/errorUrl/))
window.location.href = baseUrl + '/GenericError.htm';
},
onComplete: this._updateModel.bind(this),
parameters:  this.getParam()
});
},
_handleException: function(r, e) {
alert(e);
},
getSiteRoot: function() {
//ie throws an exception if siteRoot hasn't been defined and we only check "if(siteRoot)"
if(typeof regionRoot != 'undefined') {
return (regionRoot.charAt(regionRoot.length-1) != '/') ? regionRoot + '/' : regionRoot;
}
return '/';
},
getUrl: function() {
return this.getSiteRoot() + this.getServerControllerName() + this.getCountActionName();
},
getCountActionName: function() {
return this._countActionName;
},
_updateModel: function(response) {
this._model.setText(response.responseText);
if(typeof window.progressChicken != 'undefined'){
window.progressChicken.stop();
}
},
getParam: function(){
if( typeof getSearchOptionsModel == 'function' && typeof DataSerializer == 'object'){
return {searchModel:DataSerializer.serialize(getSearchOptionsModel().dump())};
}
return {};
},
setCountString: function(count) {
this._countString = count;
this._model.setText(count);
},
getCountString: function() {
return this._countString;
}
});
PageController = Class.create();
Object.extend(PageController.prototype, {
initialize: function(params) {
this._initialModel = this._safeGetParam(params, 'searchModel', null);
if ($('quicksearchtextcriteria')) {
this._quickSearchController = this._createQuickSearchController(
this._safeGetParam(params, 'quickSearchBy', null)
);
}
this._shouldAutoUpdateResults = this._safeGetParam(params, '_shouldAutoUpdateResults', false);
if (typeof params != 'undefined' && typeof params['quickSearchBy'] != 'undefined') {
this.setSearchOptionsModel(this._scoopSearchOptionsModelFromQuickSearch(params['quickSearchBy'], params['quickSearchCriteriaUsed'], params['quickSearchDisplayValue']));
} else if (typeof params != 'undefined' && typeof params['searchModel'] != 'undefined') {
this.setSearchOptionsModel(this._scoopSearchOptionsModel(params['searchModel']));
} else {
this.setSearchOptionsModel(this._createSearchOptionsModel());
}
},
_safeGetParam: function(params, key, defaultReturn) {
if (!params || !params[key]) {
return defaultReturn;
}
return params[key];
},
showLocationTree: function() {
return false;
},
getCountController: function() {
return this._countController;
},
setCountString: function(countString) {
if (this._countController) this._countController.setCountString(countString);
},
_createCountController: function(model) {
return new CountController(this.CONTROLLER_NAME, model);
},
_createQuickSearchController: function() {
return new QuickSearchController(ResultType.MLSNO_WEBID);
},
onInitialPageLoad: function() {
var model = new CountModel();
new CountView(model);
this._countController = this._createCountController(model);
if ($('searchResults')) {
this._initialResults = '' + $('searchResults').innerHTML;
}
if ($("idxButton") != null) {
Event.observe($("idxButton"), 'click', this._handleIdxButtonPress.bind(this));
}
},
_handleIdxButtonPress: function() {
this._prepareWebTrendsForIdxView();
},
_prepareWebTrendsForIdxView: function() {
if (typeof WebTrendsAnalyzer == 'function') {
(new WebTrendsAnalyzer()).fireWebTrendAction(
WebTrendsAnalyzer.CreateActionClickOnLink('Region', window.location, 'Idx Website'));
}
},
_searchOptionsModelWasSet: function(newModel, oldModel) {
this._setUpHandlers(newModel);
},
_setUpHandlers: function(newModel) {
this._resultsUpdater = new ResultsUpdater(this);
if (this._shouldAutoUpdateResults) {
newModel.addChangeListener(this._resultsUpdater);
}
this._countUpdater = new CountUpdater(this);
newModel.addChangeListener(this._countUpdater);
var narrowTextUpdater = new NarrowByTextUpdater(newModel);
newModel.addChangeListener(narrowTextUpdater);
narrowTextUpdater.onChange();
},
getSearchOptionsModel: function() {
return this._searchOptionsModel;
},
getResultsUpdater: function() {
return this._resultsUpdater;
},
setSearchOptionsModel: function(newModel) {
if (typeof newModel == 'undefined' || (this._resultsUpdater && this._resultsUpdater._modelDirty) || newModel.equals(this._searchOptionsModel)) {
return;
}
//DO NOT REFRESH SEARCH RESULTS HERE!  BACK BUTTON WOULD HAVE WEIRD RESULTS.
var oldModel = this._searchOptionsModel;
this._searchOptionsModel = newModel;
this._searchOptionsModelWasSet(newModel, oldModel);
},
_createSearchOptionsModel: function(type) {
var modelType = type || 'search';
var searchOptionsModel = new SearchOptionsModel(modelType);
return this._populateFilterModels(searchOptionsModel);
},
_populateFilterModels: function(searchOptionsModel) {
searchOptionsModel._filterModels = {};
modelsToPopulate = this._filterModelsUsed();
for (var key in modelsToPopulate) {
searchOptionsModel.addFilterModel(key, modelsToPopulate[key]);
}
return searchOptionsModel;
},
_filterModelsUsed: function() {
var modelsUsed = {};
modelsUsed[FilterKey.WEB_REGION] = new WebRegionModel(window.regionRoot);
return modelsUsed;
},
switchToResultsView: function(headerElement) {
if (headerElement.tagName == 'DD') {
headerElement = $(headerElement.id.replace('DD', 'DT'));
}
var detailElement = $(headerElement.id.replace('DT', 'DD'));
window.removeClassNameForChildrenWithinAParentTag('searchOptions', 'dt', 'activated');
//added because the location Widget has a special style
window.removeClassNameForChildrenWithinAParentTag('searchOptions', 'dt', 'activatedFirst');
window.removeClassNameForChildrenWithinAParentTag('searchOptions', 'dd', 'activated');
Element.removeClassName(headerElement, 'selected');
//added because the location Widget has a special style
if (headerElement.id == "categorybasedlocationDT") {
Element.addClassName(headerElement, 'activatedFirst');
} else {
Element.addClassName(headerElement, 'activated');
}
Element.removeClassName(detailElement, 'selected');
Element.addClassName(detailElement, 'activated');
if ($('error') && $('error').style.display != 'none') {
Element.hide('error');
this.updateSearchResults();
}
},
updateSearchResults: function() {
this.goToPage(1);
},
updateCount: function() {
var controller = this.getCountController();
if (controller) {
controller.update();
}
},
setModelValues: function() {
},
isLandingPageVisible: function() {
return $('content') && $('content').className.indexOf('resultsList') == -1;
},
goToPage: function(pageNo) {
var model = this.getSearchOptionsModel();
if (this._getPageNavigationURL()) {
new PageCache(model, new Url(regionRoot + this._getPageNavigationURL()), null, pageNo).cache();
}
},
_getPageNavigationURL: function() {
return '/sales/list.rails';
},
getQuickSearchController: function() {
return this._quickSearchController;
},
_scoopSearchOptionsModel: function(dumpStr) {
eval('searchModelDump = ' + dumpStr + ';');
return SearchOptionsModel.scoop(searchModelDump, this);
},
_scoopSearchOptionsModelFromQuickSearch: function(searchBy, criteria, display) {
var model = this._createSearchOptionsModel();
if (searchBy == 'Name') {
model.getFilterModel(FilterKey.AGENT_NAME_SEARCH).setName(criteria);
model.getFilterModel(FilterKey.AGENT_NAME_SEARCH).pushSearchedName();
}
else if (searchBy == 'Area') {
if (model.getFilterModel(FilterKey.LOCATION)) {
model.getFilterModel(FilterKey.LOCATION).setCitySTZip(criteria);
model.getFilterModel(FilterKey.LOCATION).setQuickSearchText(display);
}
}
else if (searchBy == 'subregion') {
model.getFilterModel(FilterKey.SUBREGION).setIdCriteria(criteria);
}
return model;
},
getLinkBackToThisPage: function() {
var url = this._getPageNavigationURL();
if (url.indexOf('http') == -1) {
url = regionRoot + url;
}
return url;
},
resultsLinkClicked: function(url, index) {
$('currentIndex').value = index;
$('searchModelInput').value = DataSerializer.serialize(this.getSearchOptionsModel().dump());
$('searchModelForm').action = url;
$('searchModelForm').target = '_self';
this._appendToValue($('searchResultsActionUrl'), this.getLinkBackToThisPage(), '|');
this._appendToValue($('searchResultsIndex'), index, '|');
//we push the index on twice here because it is popped twice from the detail pages' returnToList method
//we need to revisit this later to clean it up.
this._appendToValue($('searchResultsIndex'), index, '|');
this._appendToValue($('searchResultsSearchModel'), DataSerializer.serialize(this.getSearchOptionsModel().dump()), '|');
this.setUpDetailPagination();
this._submitSearchModelForm();
},
setUpDetailPagination: function() {
$('sir_result_detail_sort_by').value = $('sir_result_sort_by').value;
$('sir_result_detail_sort_direction').value = $('sir_result_sort_direction').value;
$('sir_result_sort_by').value = '';
$('sir_result_sort_direction').value = '';
},
_submitSearchModelForm: function() {
$('searchModelForm').submit();
},
_appendToValue: function(input, value, separator) {
input.value = input.value || '';
if (input.value == '') {
separator = '';
}
input.value = input.value + separator + value;
},
updateViewToResults: function() {
this._updateViewToResults();
},
_updateViewToResults: function() {
if ($('error')) {
Element.remove('error');
}
var contentDiv = $('content');
if (contentDiv) {
contentDiv.className = 'content resultsList';
}
}
});
PageController._createdCallbacks = [];
PageController._constructorParams = {};
PageController.addPageCreatedCallback = function(callback){
PageController._createdCallbacks.push(callback);
}
PageController.getPageCreatedCallbacks = function() {
return PageController._createdCallbacks;
}
PageController.addConstructorParam = function(name, value){
PageController._constructorParams[name] = value;
}
PageController.getConstructorParams = function(){
return PageController._constructorParams;
}
NarrowByTextUpdater = Class.create();
Object.extend(NarrowByTextUpdater.prototype, {
initialize:function(model){
this._model = model;
},
onChange:function(){
var elem = $("narrowSearchLabel");
if(elem){
var text = this._model.isEmpty()?'Narrow search by:':'Narrow or expand search by:';
elem.innerHTML = text;
}
}
});
DetailPageController = Class.create();
Object.extend(DetailPageController.prototype, PageController.prototype);
Object.extend(DetailPageController.prototype, {
initialize: function(params) {
if(params && typeof params.searchModelUsed != 'undefined') {
this._searchModelUsed = params.searchModelUsed;
this._searchResultPage = params.searchResultPage || '1';
}
PageController.prototype.initialize.call(this, params);
},
updateCount: function() {
},
goToDetailPage: function(index, link) {
$('currentIndex').value = index;
$('searchModelForm').action = link.href;
$('searchModelInput').value = this._searchModelUsed;
$('searchModelForm').target = '_self';
$('searchModelPageInput').value = this._searchResultPage;
$('searchModelForm').submit();
},
returnToSearchResults: function() {
// reset searched sort params from detail
$('sir_result_sort_by').value = $('sir_result_detail_sort_by').value;
$('sir_result_sort_direction').value = $('sir_result_detail_sort_direction').value
$('sir_result_detail_sort_by').value = '';
$('sir_result_detail_sort_direction').value = '';
$('searchModelForm').action = this._pop($('searchResultsActionUrl'), '|');
if($('searchModelForm').action.indexOf('/list')) {
this._pop($('searchResultsIndex'), '|');
}
$('currentIndex').value = this._getLast($('searchResultsIndex'), '|');
var index = parseInt($('currentIndex').value);
var perPage = 10;
var input = $("searchModelItemsPerPageInput");
if(input && input.value) {
perPage = input.value;
}
if(isNaN(index)) {
$('searchModelPageInput').value = '';
} else {
$('searchModelPageInput').value = '' + Math.ceil(index / perPage);
}
$('searchModelInput').value = this._pop($('searchResultsSearchModel'), '|');
$('searchModelLayoutInput').value = '';
$('searchModelForm').target = '_self';
this.submitSearchModelForm();
},
_isResultListUrl: function(url) {
return (url.indexOf('list.rails') != -1) || /agents$/.test(url);
},
submitSearchModelForm: function() {
$('searchModelForm').submit();
},
_pop: function(stackElement, delimiter) {
var urls = stackElement.value.split(delimiter);
var url = urls.pop();
stackElement.value = urls.join(delimiter);
return url;
},
_getLast: function(stackElement, delimiter) {
var urls = stackElement.value.split(delimiter);
if(urls.length == 0){
return '';
}
return urls[urls.length - 1];
},
getLinkBackToThisPage: function() {
return window.location.href;
},
resultsLinkClicked: function(url, index) {
if($('searchResultsIndex').value && $('searchResultsIndex').value != '0') {
$('currentIndex').value = index;
$('searchModelInput').value = DataSerializer.serialize(this.getSearchOptionsModel().dump());
$('searchModelForm').action = url;
$('searchModelForm').target = '_self';
this._appendToValue($('searchResultsActionUrl'), this.getLinkBackToThisPage(), '|');
this._appendToValue($('searchResultsIndex'), index, '|');
this._appendToValue($('searchResultsSearchModel'), DataSerializer.serialize(this.getSearchOptionsModel().dump()), '|');
this._submitSearchModelForm();
return;
}
$('currentIndex').value = index;
$('searchModelInput').value = DataSerializer.serialize(this.getSearchOptionsModel().dump());
$('searchModelForm').action = url;
$('searchModelForm').target = '_self';
this._appendToValue($('searchResultsActionUrl'), this.getLinkBackToThisPage(), '|');
$('searchResultsIndex').value = '';
this._appendToValue($('searchResultsSearchModel'), DataSerializer.serialize(this.getSearchOptionsModel().dump()), '|');
this._submitSearchModelForm();
},
_filterModelsUsed: function() {
return {};
}
});
AgentController = Class.create();
Object.extend(AgentController.prototype, PageController.prototype);
Object.extend(AgentController.prototype, {
CONTROLLER_NAME: "agents",
initialize: function(params) {
params = params || {};
params['_shouldAutoUpdateResults'] = false;
PageController.prototype.initialize.call(this, params);
if ($('agentNameSearchInput') && $('agentNameSearchSuggest')) {
this._nameAutoCompleter = new QSAutocompleter('agentNameSearchInput', 'agentNameSearchSuggest', regionRoot + "/agents/suggest.rails", {
paramName: 'textCriteria',
callback: this.suggestCallback.bind(this)
}).start();
}
},
suggestCallback: function(inptElement, entry) {
return entry + "&searchModel=" + DataSerializer.serialize(this.getSearchOptionsModel().dump());
},
_createCountController: function(model) {
return undefined;
},
_filterModelsUsed: function() {
var modelsUsed = PageController.prototype._filterModelsUsed.call(this);
//These are needed for Quicksearch by Agent to preserve search criteria.
modelsUsed[FilterKey.LOCATION] = new LocationModel();
modelsUsed[FilterKey.CAT_BASED_LOCATION] = modelsUsed[FilterKey.LOCATION];
modelsUsed[FilterKey.AGENT_LOCATION] = new AgentLocationFilterModel();
modelsUsed[FilterKey.LANGUAGE] = new LanguageFilterModel();
modelsUsed[FilterKey.AGENT_NAME_SEARCH] = new AgentNameSearchFilterModel();
modelsUsed[FilterKey.LETTER_FROM_FORM] = new LetterFromFormFilterModel();
return modelsUsed;
},
_getPageNavigationURL: function() {
var agentsUrl = '/agents';
if ($('searchModelForm').action.indexOf("AGENT_NAME_SEARCH") == -1) {
var url = document.URL;
var agentsIndex = url.indexOf(agentsUrl, 0);
if (url.lastIndexOf("/") > agentsIndex) {
agentsUrl = url.substring(agentsIndex, url.length);
}
}
return agentsUrl;
},
_setUpHandlers: function(newModel) {
PageController.prototype._setUpHandlers.call(this, newModel);
},
showLocationTree: function() {
return true;
},
onSubmitHook: function() {
getSearchOptionsModel().getFilterModel(FilterKey.AGENT_NAME_SEARCH).pushSearchedName();
}
});
SearchController = Class.create();
Object.extend(SearchController.prototype, PageController.prototype);
Object.extend(SearchController.prototype, {
CONTROLLER_NAME: "sales",
_filterModelsUsed: function() {
var modelsUsed = PageController.prototype._filterModelsUsed.call(this);
modelsUsed[FilterKey.LOCATION] = new LocationModel();
modelsUsed[FilterKey.PRICE] = new PriceFilterModel();
modelsUsed[FilterKey.BED_BATH] = new BedBathSizeFilterModel();
modelsUsed[FilterKey.INTERIOR_SIZE_LOT_SIZE] = new InteriorLotSizeFilterModel();
modelsUsed[FilterKey.CAT_BASED_LOCATION] = modelsUsed[FilterKey.LOCATION];
modelsUsed[FilterKey.ARCHITECTURAL_STYLE] = new MultiLevelAmenityFilterModel("Architectural Style", 'architecturalstyle', 'All Styles');
modelsUsed[FilterKey.PROPERTY_COMMUNITY_TYPE] = new MultiLevelAmenityFilterModel("Property/Community Type", 'propertycommunitytype', 'All Types', 'Add Property Type', 'Edit Property Type');
modelsUsed[FilterKey.FEATURES_AND_AMENITIES] = new MultiLevelAmenityFilterModel("Features and Amenities", 'featuresandamenities', 'Any Features', 'Add Features and Amenities', 'Edit Features and Amenities');
modelsUsed[FilterKey.LIFESTYLE] = new MultiLevelAmenityFilterModel("Lifestyle", 'lifestyle', 'Any Lifestyle');
modelsUsed[FilterKey.ITEMS_PER_PAGE] = new ItemsPerPageFilterModel();
return modelsUsed;
},
showLocationTree: function() {
return true;
},
_searchOptionsModelWasSet: function(newModel, oldModel) {
PageController.prototype._searchOptionsModelWasSet.call(this, newModel, oldModel);
//restores the location widget to what the newModel believes the state should be
//need to tell the LocationFilterWidget (left bar) to update as well WITHOUT firing a toggle
newModel.getFilterModel(FilterKey.LOCATION).setLocationDisplayTree(LOCATION_DISPLAY_TREE);
},
_createCountController: function(model) {
return new CountController("sales", model);
},
_getPageNavigationURL: function() {
return '/sales/list.rails?layout=results';
},
getLinkBackToThisPage: function() {
return regionRoot + '/sales';
},
isLandingPageVisible: function() {
return $('regionSplash') && $('content') && $('content').className.indexOf('resultsList') == -1;
},
setUpDetailPagination: function() {
$('sir_result_detail_sort_by').value = $('sir_result_sort_by').value;
$('sir_result_detail_sort_direction').value = $('sir_result_sort_direction').value;
}
});
WelcomeController = Class.create();
Object.extend(WelcomeController.prototype, SearchController.prototype);
Object.extend(WelcomeController.prototype, {
initialize: function(params) {
SearchController.prototype.initialize.call(this, params);
},
onInitialPageLoad: function() {
PageController.prototype.onInitialPageLoad.call(this);
this.updateCount();
},
_updateViewToResults: function() {
if ($('error')) {
Element.remove('error');
}
$('findPropertiesLink').addClassName("active");
$('findPropertiesLink').addClassName("expanded");
if ($("findPropertiesDownArrow")) {
Element.hide($("findPropertiesDownArrow"));
}
unregisterAnyHandler($('findPropertiesLink'), 'mouseover');
unregisterAnyHandler($('findPropertiesLink'), 'mouseout');
if ($('findPropertiesDrop')) {
unregisterAnyHandler($('findPropertiesDrop'), 'mouseout');
}
if ($('secondarySearchTabs')) {
Element.show($('secondarySearchTabs'));
Element.removeClassName($('secondarySearchTabsDiv'), "empty");
Element.addClassName($('secondarySearchTabs').getElementsByTagName('a')[0], "active");
}
removeLandingPageStyles();
var contentDiv = $('content');
if (contentDiv)
contentDiv.className = 'content resultsList';
}
});
RentalController = Class.create();
Object.extend(RentalController.prototype, SearchController.prototype);
Object.extend(RentalController.prototype, {
CONTROLLER_NAME: "rental",
initialize:function(params){
SearchController.prototype.initialize.call(this, params);
},
_filterModelsUsed: function(){
var modelsUsed = PageController.prototype._filterModelsUsed.call(this);
modelsUsed[FilterKey.LOCATION] = new LocationModel();
modelsUsed[FilterKey.CAT_BASED_LOCATION] = modelsUsed[FilterKey.LOCATION];
modelsUsed[FilterKey.RATES_AND_AVAILABILITY] = new RatesAndAvailabilityFilterModel();
modelsUsed[FilterKey.BED_BATH] = new BedBathSizeFilterModel();
modelsUsed[FilterKey.INTERIOR_SIZE_LOT_SIZE] = new InteriorLotSizeFilterModel();
modelsUsed[FilterKey.ARCHITECTURAL_STYLE] = new MultiLevelAmenityFilterModel("Architectural Style", 'architecturalstyle', 'All Styles');
modelsUsed[FilterKey.PROPERTY_COMMUNITY_TYPE] = new MultiLevelAmenityFilterModel("Property/Community Type", 'propertycommunitytype', 'All Types');
modelsUsed[FilterKey.FEATURES_AND_AMENITIES] = new MultiLevelAmenityFilterModel("Features and Amenities", 'featuresandamenities', 'Any Features', 'Add Features and Amenities', 'Edit Features and Amenities');
modelsUsed[FilterKey.LIFESTYLE] = new MultiLevelAmenityFilterModel("Lifestyle", 'lifestyle', 'Any Lifestyle');
return modelsUsed;
},
_createSearchOptionsModel:function(){
return PageController.prototype._createSearchOptionsModel.call(this, 'search');
},
_getPageNavigationURL: function() {
return '/rental/list.rails?layout=results';
},
_createCountController: function(model){
return new CountController(this.CONTROLLER_NAME, model);
},
getLinkBackToThisPage:function(){
return regionRoot+'/rentals';
}
});
RentalWelcomeController = Class.create();
Object.extend(RentalWelcomeController.prototype, RentalController.prototype);
Object.extend(RentalWelcomeController.prototype, {
initialize: function(params) {
RentalController.prototype.initialize.call(this, params);
},
onInitialPageLoad: function() {
PageController.prototype.onInitialPageLoad.call(this);
this.updateCount();
},
_updateViewToResults: function() {
if ($('error')) {
Element.remove('error');
}
Element.removeClassName($('searchResults'), 'rentalLanding');
removeLandingPageStyles();
var contentDiv = $('content');
if (contentDiv)
contentDiv.className = 'content resultsList';
}
});
OfficeController = Class.create();
Object.extend(OfficeController.prototype, PageController.prototype);
Object.extend(OfficeController.prototype, {
initialize:function(params){
params = params || {};
params['_shouldAutoUpdateResults'] = false;
PageController.prototype.initialize.call(this, params);
},
CONTROLLER_NAME: "offices",
_filterModelsUsed: function(){
var modelsUsed = PageController.prototype._filterModelsUsed.call(this);
modelsUsed[FilterKey.LOCATION] = new LocationModel();
return modelsUsed;
//	},
//	_createCountController:function(model){
//		return undefined;
},
_getPageNavigationURL: function() {
return '/offices';
}
});
AgentDetailController = Class.create();
Object.extend(AgentDetailController.prototype, DetailPageController.prototype);
Object.extend(AgentDetailController.prototype, {
CONTROLLER_NAME: "agentdetail",
initialize: function(params){
this._agentId = params.agentId;
this._countController = null;
DetailPageController.prototype.initialize.call(this, params);
},
_createCountController:function(model){
},
_filterModelsUsed: function(){
var modelsUsed = {};
var model = new AgentIdFilterModel();
model.setIdCriteria(this._agentId);
modelsUsed[FilterKey.AGENT_ID]= model;
return modelsUsed;
},
getAgentId: function() {
return this._agentId;
},
onInitialPageLoad:function(){
PageController.prototype.onInitialPageLoad.call(this);
if ($("AgentWebSite") != null){
Event.observe($("AgentWebSite") , 'click', this._handleLinkClicked.bind(this));
}
},
_getPageNavigationURL: function() {
if(this._isRentalListingsActive()){
return '/rental/byAgent/' + this._agentId;}
else if(this._isSelectSalesActive()) {
return '/agentselectsales/byAgent.rails?agentId='+this._agentId;}
else
return '/sales/byAgent/' + this._agentId;
},
_handleLinkClicked:function(){
this._prepareWebTrendsForAgentWebsites();
},
_prepareWebTrendsForAgentWebsites:function(){
var agentName = $("agentname").innerHTML;
if(typeof WebTrendsAnalyzer == 'function'){
(new WebTrendsAnalyzer()).fireWebTrendAction(
WebTrendsAnalyzer.CreateActionClickOnLink('Agent '+agentName,window.location, 'Agent Website'));
}
},
_isRentalListingsActive: function() {
return ($('currentRentalsLI') && $('currentRentalsLI').className.indexOf('selected') != -1);
},
_isSelectSalesActive: function() {
return ($('selectSalesLI') && $('selectSalesLI').className.indexOf('selected') != -1);
},
createDetailPageURL:function(agentEmail){
return regionRoot+'/agents' + '/' + agentEmail;
},
createSearchResultsActionUrl:function(){
return regionRoot+'/agents';
}
});
OfficeDetailController = Class.create();
Object.extend(OfficeDetailController.prototype, DetailPageController.prototype);
Object.extend(OfficeDetailController.prototype, {
CONTROLLER_NAME: "officedetail",
initialize: function(params){
this._officeId = params.officeId;
this._countController = null;
DetailPageController.prototype.initialize.call(this, params);
},
_createCountController:function(model){
},
_filterModelsUsed: function(){
var modelsUsed = {};
var model = new OfficeIdFilterModel();
model.setIdCriteria(this._officeId);
modelsUsed[FilterKey.OFFICE_ID]= model;
return modelsUsed;
},
getOfficeId: function() {
return this._officeId;
},
_getPageNavigationURL: function() {
if(this._isOfficeListingsActive()){
return '/sales/list.rails';
}else if(this._isOfficeRentalsActive()){
return '/rental/list.rails';
}else if(this._isSelectSalesActive()){
return '/officeselectsales/list.rails?officeId='+this._officeId;
}else{
return '/agents/shortsummary.rails';
}
},
_isOfficeListingsActive: function() {
return ($('currentListingsLI').className.indexOf('selected') != -1)
},
_isOfficeRentalsActive: function() {
return ($('currentRentalsLI') && $('currentRentalsLI').className.indexOf('selected') != -1)
},
_isSelectSalesActive: function() {
return ($('selectSalesLI') && $('selectSalesLI').className.indexOf('selected') != -1)
},
createDetailPageURL:function(officeId){
return regionRoot+'/offices' + '/' + officeId;
},
createSearchResultsActionUrl:function(){
return regionRoot+'/offices/list.rails';
}
});
TeamDetailController = Class.create();
Object.extend(TeamDetailController.prototype, DetailPageController.prototype);
Object.extend(TeamDetailController.prototype, {
CONTROLLER_NAME: "teamdetail",
initialize: function(params){
this._teamId = params.teamId;
this._countController = null;
DetailPageController.prototype.initialize.call(this, params);
},
_createCountController:function(model){
},
_filterModelsUsed: function(){
var modelsUsed = {};
var model = new SalesTeamIdFilterModel();
model.setIdCriteria(this._teamId);
modelsUsed[FilterKey.SALE_TEAM_ID]= model;
return modelsUsed;
},
onInitialPageLoad:function(){
if ($("SalesTeamWebSite") != null){
Event.observe($("SalesTeamWebSite") , 'click', this._handleLinkClicked.bind(this));
}
},
_getPageNavigationURL: function() {
if(this._isRentalListingsActive()){
return '/rental/byTeam.rails?teamid='+this._teamId + '&watched=false';}
else if(this._isSalesListingsActive()){
return '/sales/byTeam.rails?teamid='+this._teamId + '&watched=false';}
else if(this._isSelectSalesActive()) {
return '/agentselectsales/byteam.rails?teamid='+this._teamId;}
else
return '/agents/byTeam.rails?teamId='+this._teamId;
},
_handleLinkClicked:function(){
this._prepareWebTrendsForSalesTeamWebsites();
},
_prepareWebTrendsForSalesTeamWebsites:function(){
var salesteam = $("salesteam").innerHTML;
if(typeof WebTrendsAnalyzer == 'function'){
(new WebTrendsAnalyzer()).fireWebTrendAction(
WebTrendsAnalyzer.CreateActionClickOnLink('Sales Team ' + salesteam,window.location, 'SalesTeam Website'));
}
},
createDetailPageURL:function(agentEmail){
/* ONLY will be called from an agent search results pagination context */
return regionRoot+'/agents' + '/' + agentEmail;
},
_isRentalListingsActive: function() {
return ($('currentRentalsLI') && $('currentRentalsLI').className.indexOf('selected') != -1);
},
_isSelectSalesActive: function() {
return ($('selectSalesLI') && $('selectSalesLI').className.indexOf('selected') != -1);
},
_isSalesListingsActive: function() {
return ($('currentListingsLI') && $('currentListingsLI').className.indexOf('selected') != -1);
}
});
NeighborhoodDetailController = Class.create();
Object.extend(NeighborhoodDetailController.prototype, DetailPageController.prototype);
Object.extend(NeighborhoodDetailController.prototype, {
CONTROLLER_NAME: "neighborhooddetail",
initialize: function(params){
this._neighborhoodId = params['neighborhoodId'];
this._numListings = params['numListings'];
this._countController = null;
DetailPageController.prototype.initialize.call(this, params);
},
_createCountController:function(model){
},
_filterModelsUsed: function(){
var modelsUsed = {};
var model = new NeighborhoodIdFilterModel();
model.setIdCriteria(this._neighborhoodId);
modelsUsed[FilterKey.NEIGHBORHOOD_ID]= model;
return modelsUsed;
},
getNeighborhoodId: function() {
return this._neighborhoodId;
},
onInitialPageLoad:function(){
PageController.prototype.onInitialPageLoad.call(this);
if(this._numListings && this._numListings>0){
//this.updateSearchResults(); //removed this, pushed responsibility back to the server
}
},
createDetailPageURL:function(areaName){
return regionRoot+'/areas/' + areaName;
}
});
AreaController = Class.create();
Object.extend(AreaController.prototype, PageController.prototype);
Object.extend(AreaController.prototype, {
CONTROLLER_NAME: "areas",
_createCountController:function(model){
return new CountController("sales", model);
},
_filterModelsUsed: function(){
var modelsUsed = PageController.prototype._filterModelsUsed.call(this);
var model = new SubRegionFilterModel();
modelsUsed[FilterKey.SUBREGION]= model;
return modelsUsed;
},
updateCount:function(){
},
_getPageNavigationURL: function() {
return window.location.href;
},
onInitialPageLoad: function() {
PageController.prototype.onInitialPageLoad.call(this);
this.updateCount();
},
goToPage: function(pageNo) {
PageController.prototype.goToPage.call(this,pageNo);
this.updateCount();
},
setCountString:function() {
//do nothing
}
});
DevelopmentController = Class.create();
Object.extend(DevelopmentController.prototype, PageController.prototype);
Object.extend(DevelopmentController.prototype, {
CONTROLLER_NAME: "developments",
_filterModelsUsed: function(){
var urlParts = window.location.href.split('/');
var developmentGroup = urlParts[urlParts.length - 1];
var modelsUsed = PageController.prototype._filterModelsUsed.call(this);
var model = new DevelopmentGroupFilterModel();
model.setIdCriteria(developmentGroup);
modelsUsed[FilterKey.DEVELOPMENT_GROUP]= model;
return modelsUsed;
},
_getPageNavigationURL: function() {
return window.location.href;
},
onInitialPageLoad: function() {
PageController.prototype.onInitialPageLoad.call(this);
}
});
SearchByRadioButton = Class.create();
Object.extend(SearchByRadioButton.prototype, RadioButton.prototype);
Object.extend(SearchByRadioButton.prototype, {
initialize: function(type, buttonText, promptText, assistText, action, startAutoComplete, showMarketDropDown) {
RadioButton.prototype.initialize.call(this, type);
this._type = type;
this._buttonText = buttonText;
this._promptText = promptText;
this._assistText = assistText;
this._action = action;
this._startAutoComplete = startAutoComplete || false;
this._showMarketDropDown = showMarketDropDown || false;
},
addToUrl: function(url) {
if(this._action)
url.push(this._action);
},
updateAutoComplete: function(autocompleter) {
if(this._startAutoComplete) {
autocompleter.start();
} else {
autocompleter.stop();
}
},
getType: function(){
return this._type;
},
getButtonText: function(){
return this._buttonText;
},
getAssistText: function() {
return '<label>' + this._assistText + '</label>';
},
getPromptText: function(){
return this._promptText;
},
showMarketDropDown: function(){
return this._showMarketDropDown;
},
render: function() {
return '<input type="radio" class="radio" id="' + this._type + '" value="' + this._type + '" name="searchByRadioButton" />' +
'<label for="'+this._type+'">'+this._buttonText + '</label></input>'
}
});
SearchByRadioButton.LOCATION = new SearchByRadioButton("Location", " City, ST or Zip", "City, ST or Zip", "Within:", 'byCitySTZip');
SearchByRadioButton.MARKET = new SearchByRadioButton("Market", " Location", "", "Within:", 'byMarket', false, true);
SearchByRadioButton.AGENT_NAME = new SearchByRadioButton("Name", " Name", "Example: John Smith", "Enter an Agent's Name", 'byname', true);
SearchByRadioButton.MLSID_WEBNO = new SearchByRadioButton("", "", "", "Web # or MLS ID:", 'byListingNumberOrMlsID');
SearchByRadioButton.getInstance = function(type) {
for(var name in SearchByRadioButton) {
if(typeof SearchByRadioButton[name] == 'object' && SearchByRadioButton[name].getType() == type) return SearchByRadioButton[name];
}
};
SearchByRadioButton.getSelectedRadioButton = function() {
var checked = $('quicksearchform').getInputs('radio', 'searchByRadioButton').find(function(re) {return re.checked;});
return (checked) ? $F(checked) : null;
};
PropertyDetailController = Class.create();
Object.extend(PropertyDetailController.prototype, DetailPageController.prototype);
Object.extend(PropertyDetailController.prototype, {
initialize:function(params){
this._propertyId = params['propertyId'];
DetailPageController.prototype.initialize.call(this, params);
},
getPropertyId:function(){
return this._propertyId;
},
getResultIndex:function(){
return this._resultIndex;
},
updateSearchResults:function(){
},
goToPage:function(){
},
createDetailPageURL:function(propertyId){
return regionRoot+'/' + this._propertyType + '/'+propertyId;
},
createSearchResultsActionUrl:function(){
return regionRoot+'/' + this._propertyType + '/list.rails';
},
_filterModelsUsed: function(){
return {};
}
});
SalesDetailController = Class.create();
Object.extend(SalesDetailController.prototype, PropertyDetailController.prototype);
Object.extend(SalesDetailController.prototype, {
initialize:function(params){
this._propertyType = 'sales';
PropertyDetailController.prototype.initialize.call(this, params);
if($('watchThisPropertyButton')){
(new WatchThisPropertyPanel($('watchThisPropertyDiv'), new WatchPropertyService()));
}else if($('watchListOffLink')){
new CurrentlyWatchingPropertyPanel($('watchThisPropertyDiv'), new WatchPropertyService());
}
}
});
RentalDetailController = Class.create();
Object.extend(RentalDetailController.prototype, PropertyDetailController.prototype);
Object.extend(RentalDetailController.prototype, {
initialize:function(params){
this._propertyType = 'rental';
PropertyDetailController.prototype.initialize.call(this, params);
}
});
OpenHouseDetailController = Class.create();
Object.extend(OpenHouseDetailController.prototype, PropertyDetailController.prototype);
Object.extend(OpenHouseDetailController.prototype, {
initialize:function(params){
this._propertyType = 'openhouses';
PropertyDetailController.prototype.initialize.call(this, params);
if($('watchThisPropertyButton')){
(new WatchThisPropertyPanel($('watchThisPropertyDiv'), new WatchPropertyService()));
}else if($('watchListOffLink')){
new CurrentlyWatchingPropertyPanel($('watchThisPropertyDiv'), new WatchPropertyService());
}
}
});
ResultType = Class.create();
Object.extend(ResultType.prototype, {
initialize: function(type, searchByList, serverControllerName) {
this._type = type;
this._searchByList = searchByList;
this._serverControllerName = serverControllerName;
},
getType: function() {
return this._type;
},
getSearchByList:function(){
return this._searchByList;
},
getDefaultSearchBy:function(){
return this._searchByList[0];
},
addToUrl: function(url) {
url.push(this._serverControllerName);
},
isEmpty: function() {
return this.getDefaultSearchBy().getType() == '';
}
});
ResultType.MLSNO_WEBID = new ResultType("Web # or MLS ID", [SearchByRadioButton.MLSID_WEBNO], 'sales');
ResultType.SALES = new ResultType("Properties for Sale", [SearchByRadioButton.LOCATION, SearchByRadioButton.MARKET], 'sales');
ResultType.RENT = new ResultType("Properties for Rent", [SearchByRadioButton.MARKET], 'rentals');
ResultType.AGENT = new ResultType("Our Agents", [SearchByRadioButton.AGENT_NAME, SearchByRadioButton.LOCATION, SearchByRadioButton.MARKET], 'agents');
ResultType.OFFICE = new ResultType("Our Offices", [SearchByRadioButton.MARKET], 'offices');
ResultType.getInstance = function(type){
for(var name in ResultType){
if(typeof ResultType[name] == 'object' && ResultType[name].getType() == type){
return ResultType[name];
}
}
}
QuickSearchController = Class.create();
Object.extend(QuickSearchController.prototype, {
initialize: function(resultType){
this._model = new QuickSearchModel(resultType);
this._view = new QuickSearchView(this._model, this);
if (typeof QSAutocompleter != 'undefined') { //so that the other tests don't NEED this.
this._autocompleter = new QSAutocompleter('quicksearchtextcriteria', 'suggestText', "/agents/suggest.rails", {
paramName: 'textCriteria'
});
}
this._model.addSearchByListener(new ClosureHandler(this._searchByChanged.bind(this)));
this._model.addResultTypeListener(new ClosureHandler(this._searchByChanged.bind(this)));
this._searchByChanged();
},
submit: function(){
if (typeof dcsMultiTrack == 'function') {
dcsMultiTrack('WT.oss', this._model.getTextCriteria());
}
window.location.href = baseUrl + this.buildQuickSearchURL();
},
buildQuickSearchURL: function(){
var url = [];
if (this._model.getSearchBy().showMarketDropDown()) {
url.push(""); // to add a leading slash before the regionRoot
if (this._view._marketSelect.getSelectionValue().length > 0) {
url.push(this._view._marketSelect.getSelectionValue());
}
this._model.getResultType().addToUrl(url);
}
else {
//			url.push(regionRoot);
url.push("");
this._model.getResultType().addToUrl(url);
this._model.getSearchBy().addToUrl(url);
url.push(this._model.getTextCriteria());
}
return url.join('/');
},
_searchByChanged: function(){
this._model.getSearchBy().updateAutoComplete(this._autocompleter);
},
getModel: function(){
return this._model;
}
});
QuickSearchModel = Class.create();
Object.extend(QuickSearchModel.prototype, {
initialize: function(resultType){
resultType = resultType || ResultType.MLSNO_WEBID;
this._resultTypeObservable = new Observable();
this._searchByObservable = new Observable();
this._textCriteriaObservable = new Observable();
this.setResultType(resultType);
},
addResultTypeListener: function(listener){
this._resultTypeObservable.addChangeListener(listener);
},
addSearchByListener: function(listener){
this._searchByObservable.addChangeListener(listener);
},
addTextCriteriaListener: function(listener){
this._textCriteriaObservable.addChangeListener(listener);
},
setTextCriteria: function(criteria){
this._textCriteria = criteria;
this._textCriteriaObservable.notifyChange();
},
getTextCriteria: function(){
return this._textCriteria;
},
setResultType: function(type){
this._resultType = type;
this._searchBy = type.getDefaultSearchBy();
this._resultTypeObservable.notifyChange();
},
getResultType: function(){
return this._resultType;
},
setSearchBy: function(type){
this._searchBy = type;
this._searchByObservable.notifyChange();
},
getSearchBy: function(){
return this._searchBy;
}
});
QuickSearchModel.RESULT_TYPE_LIST = [ResultType.MLSNO_WEBID, ResultType.SALES, ResultType.RENT, ResultType.AGENT, ResultType.OFFICE];
QuickSearchView = Class.create();
Object.extend(QuickSearchView.prototype, {
initialize: function(model, controller) {
this._controller = controller;
this._resultTypeSelect = new Select('mainquicksearchcriteria');
this._submitButton = new PeerElement('new_quickSearchSubmitButton');
this._textCriteria = new InputElement('quicksearchtextcriteria');
this._searchByRadioButtonPane = $('searchByRadioButtonPaneDiv');
this._marketSelect = new Select('marketselect');
this._model = model;
this._updateSearchByList();
this._updateResultTypeList();
this._onSearchByChange();
this._model.addResultTypeListener(new ClosureHandler(this._onResultTypeChange.bind(this)));
this._model.addSearchByListener(new ClosureHandler(this._onSearchByChange.bind(this)));
this._model.addTextCriteriaListener(new ClosureHandler(this._onTextCriteriaChange.bind(this)));
this._bindListeners();
},
_bindListeners: function() {
this._createSearchByRadioButtonBindings();
this._resultTypeSelect.addChangeListener(this._handleResultTypeChanged.bind(this));
this._textCriteria.addFocusListener(this._handleFocusGained.bind(this));
this._textCriteria.addBlurListener(this._handleFocusLost.bind(this));
this._textCriteria.addEnterKeyListener(this._handleEnterKeyPressed.bindAsEventListener(this));
this._submitButton.addClickListener(this._handleSubmit.bind(this));
},
_createSearchByRadioButtonBindings: function() {
this._model.getResultType().getSearchByList().each(function(searchByRadioButton) {
this._createASearchByRadioButtonBinding(searchByRadioButton)
}
.bind(this));
},
_createASearchByRadioButtonBinding: function(searchByRadioButton) {
searchByRadioButton.addClickListener(this._handleSearchByChanged.bind(this));
},
_updateResultTypeList: function() {
this._resultTypeSelect.update(QuickSearchModel.RESULT_TYPE_LIST.collect(function(resultType) {
return resultType.getType();
}), this._model.getResultType().getType());
},
_onTextCriteriaChange: function() {
this._textCriteria.setValue(this._model.getTextCriteria());
},
_onSearchByChange: function() {
if (this._model.getSearchBy() && this._model.getSearchBy().showMarketDropDown()) {
this._textCriteria.hide();
var showAllMarkets = (ResultType.getInstance(this._resultTypeSelect.getSelection().text) != ResultType.RENT);
var marketListProvider = new MarketSelectListProvider(this._marketSelect._getElement(), showAllMarkets);
marketListProvider.render();
Element.show(this._marketSelect._getElement());
}
else {
Element.hide(this._marketSelect._getElement());
this._textCriteria.show();
this._updateTextBox(this._getQuickSearchPromptText());
}
this._updateAssistText();
},
_getQuickSearchPromptText: function() {
return this._model.getSearchBy().getPromptText();
},
_onResultTypeChange: function() {
this._updateSearchByList();
this._onSearchByChange();
},
_updateSearchByList: function() {
this._searchByRadioButtonPane.innerHTML = '';
if (!this._model.getResultType().isEmpty() && this._model.getResultType().getSearchByList().size() > 1) {
var html = this._model.getResultType().getSearchByList().collect(function(radioButton) {
return radioButton.render()
}).join('');
this._searchByRadioButtonPane.innerHTML = '<label>Search By: </label>' + html;
this._createSearchByRadioButtonBindings();
this._selectDefaultSearchByRadioButton();
}
},
_updateAssistText: function() {
$('assistTextDiv').innerHTML = this._model.getSearchBy().getAssistText();
},
_selectDefaultSearchByRadioButton: function() {
$(this._model.getResultType().getDefaultSearchBy().getType()).checked = true;
},
_handleSearchByChanged: function() {
this._model.setSearchBy(SearchByRadioButton.getInstance(SearchByRadioButton.getSelectedRadioButton()));
},
_handleResultTypeChanged: function() {
this._model.setResultType(ResultType.getInstance(this._resultTypeSelect.getSelection().text));
},
_updateTextBox: function(text) {
this._textCriteria.setValue(text);
this._textCriteria.removeClass('hintTextboxActive');
this._textCriteria.addClass('hintTextbox');
this._textCriteria.addClass('prompt');
},
_handleFocusGained: function() {
if (this._textCriteria.getValue() == this._model.getSearchBy().getPromptText()) {
this._textCriteria.clear();
this._textCriteria.removeClass('hintTextbox');
this._textCriteria.removeClass('prompt');
this._textCriteria.addClass('hintTextboxActive');
}
},
_handleFocusLost: function() {
if (this._textCriteria.getValue() == "") {
this._updateTextBox(this._getQuickSearchPromptText());
}
},
_handleEnterKeyPressed: function() {
this._createTimeout(this._doEnterPressed.bind(this), 10);
},
_createTimeout: function(fn, delay) {
setTimeout(fn, delay);
},
_handleSubmit: function() {
var textCriteriaValue = this._textCriteria.getValue();
if ("." == textCriteriaValue.charAt(textCriteriaValue.length - 1)) {
textCriteriaValue = textCriteriaValue.substring(0, textCriteriaValue.length - 1);
}
textCriteriaValue = textCriteriaValue.replace(":", "");
this._model.setTextCriteria(textCriteriaValue);
this._controller.submit();
},
_doEnterPressed: function() {
this._handleSubmit();
}
})
MarketSelectListProvider = Class.create();
Object.extend(MarketSelectListProvider.prototype, {
initialize: function(control, showAllLocations) {
this._control = control;
this._showAllLocations = showAllLocations;
},
isShowAllLocation: function() {
return this._showAllLocations;
},
render: function() {
this._control.options.length = 0;
var allMarketsOption = [{ text: "All Markets", value: ""}];
var otherMarkets = [
{ text: "Cape Cod, MA", value: "capecod" },
{ text: "Greenwich, CT", value: "greenwich" },
{ text: "Hamptons, NY", value: "hamptons" },
{ text: "Jackson Hole, WY", value: "jacksonhole" },
{ text: "London, UK", value: "london" },
{ text: "New York, NY", value: "nyc" },
{ text: "Northern California", value: "norcal" },
{ text: "Palm Beach, FL", value: "palmbeach" },
{ text: "Santa Fe, NM", value: "santafe" },
{ text: "Southern California", value: "socal" },
{ text: "Sun Valley, ID", value: "sunvalley" }
];
var optionsToAdd = (this.isShowAllLocation()) ? allMarketsOption.concat(otherMarkets) : otherMarkets;
for (var i = 0; i < optionsToAdd.length; i++) {
this._control.options[i] = new Option(optionsToAdd[i].text, optionsToAdd[i].value);
}
}
});
OpenHousePageController = Class.create();
Object.extend(OpenHousePageController.prototype, PageController.prototype);
Object.extend(OpenHousePageController.prototype, {
initialize: function(params) {
PageController.prototype.initialize.call(this, params);
},
CONTROLLER_NAME: "openhouses",
_getPageNavigationURL: function() {
return '/openhouses/list.rails';
},
onInitialPageLoad: function() {
PageController.prototype.onInitialPageLoad.call(this);
},
_filterModelsUsed: function(){
var modelsUsed = PageController.prototype._filterModelsUsed.call(this);
modelsUsed[FilterKey.SUBREGION] = new SubRegionFilterModel();
return modelsUsed;
}
});
DevelopmentIdFilterModel = Class.create();
Object.extend(DevelopmentIdFilterModel.prototype, IdFilterModel.prototype);
Object.extend(DevelopmentIdFilterModel.prototype,  {
initialize: function() {
IdFilterModel.prototype.initialize.call(this, 'developmentId', '_developmentId');
this.constructor = DevelopmentIdFilterModel; // Safari Fix
}
});
DevelopmentIdFilterModel.scoop = function(dump){
return IdFilterModel.scoop(dump, new DevelopmentIdFilterModel());
};
DevelopmentDetailController = Class.create();
Object.extend(DevelopmentDetailController.prototype, DetailPageController.prototype);
Object.extend(DevelopmentDetailController.prototype, {
CONTROLLER_NAME: "developmentdetail",
initialize: function(params){
this._developmentId = params['developmentId'];
this._developmentAddressId = params['developmentAddressId'];
this._onBoardZipCode = params['onBoardZipCode'];
this._countController = null;
DetailPageController.prototype.initialize.call(this, params);
},
_createCountController:function(model){
},
_filterModelsUsed: function(){
var modelsUsed = {};
var model = new DevelopmentIdFilterModel();
model.setIdCriteria(this._developmentId);
modelsUsed[FilterKey.DEVELOPMENT_ID]= model;
return modelsUsed;
},
getDevelopmentId: function() {
return this._developmentId;
},
getOnBoardZipCode: function() {
return this._onBoardZipCode;
},
getDevelopmentAddressId: function() {
return this._developmentAddressId;
},
_handleAdditionalInfoTabLoad: function(){
if (this._isMapTabActive()){
showMapForProperty('/map/drawmap.rails?address='+this.getDevelopmentAddressId());
}
else if(this._isLocalInformationTabActive()) {
showLocalInformation(this.getOnBoardZipCode());
}
},
_getPageNavigationURL: function() {
if(this._isDevelopmentListingsActive()){
return '/sales/list.rails';
}
},
_isDevelopmentListingsActive: function() {
return ($('currentListingsLI')&&$('currentListingsLI').className.indexOf('selected') != -1)
},
_isMapTabActive: function(){
return ($('mapLI')&&$('mapLI').className.indexOf('selected') != -1)
},
_isLocalInformationTabActive: function() {
return ($('localInformationLI')&&$('localInformationLI').className.indexOf('selected') != -1)
},
createDetailPageURL:function(developmentId){
return regionRoot+'/developments' + '/' + developmentId;
},
onInitialPageLoad:function(){
PageController.prototype.onInitialPageLoad.call(this);
this.updateSearchResults();
this._handleAdditionalInfoTabLoad();
}
})
SaveSearchPanel = Class.create();
Object.extend(SaveSearchPanel.prototype,{
initialize:function(searchModel){
this._emailAddressId = 'SearchEmailAddress';
this._emailErrorMessageId = 'InvalidEmailErrors';
this._serverErrorMessageId = 'ServerErrors';
this._nameId = 'SearchName';
this._nameErrorMessageId = 'InvalidSearchNameErrors';
this._saveSearchPanelId = 'saveSearchPanelId';
this._validatedMessageId = 'saveSearchPanelValidatedId';
this._searchNameValidatedMessageId = 'searchNameValidatedDisplayId';
this._searchModel = searchModel;
this._emailValidator = new EmailAddressValidator($(this._emailAddressId),
this._emailValidationFailed.bind(this),
this._emailValidationPassed.bind(this));
},
_emailValidationPassed:function(email){
this._hideErrorMessage(this._emailErrorMessageId);
createCookie('userEmail', email);
},
_emailValidationFailed:function(email){
this._showErrorMessage(this._emailErrorMessageId);
},
isValidName: function(name){
name = name.strip();
return /^[0-9|a-z|A-Z]/.test(name);
},
validateEmailAddress: function() {
return this._emailValidator.validate();
},
validateName: function() {
if(this.isValidName($(this._nameId).value)){
return this._hideErrorMessage(this._nameErrorMessageId)
}
return this._showErrorMessage(this._nameErrorMessageId);
},
validate: function() {
this._hideErrorMessage(this._serverErrorMessageId);
var valid = this.validateEmailAddress();
//DON'T change this.  We dont want it to short circut and changing it to &= turns it into
//bits.
valid = this.validateName() && valid;
if(valid) {
$(this._searchNameValidatedMessageId).innerHTML = $(this._nameId).value;
}
return valid;
},
_hideErrorMessage: function(errorMessageId) {
Element.hide($(errorMessageId));
return true;
},
_showErrorMessage: function(errorMessageId, message) {
Element.show($(errorMessageId));
if(message){
Element.update(errorMessageId, message);
}
return false;
},
bindEvents: function() {
Event.observe('SaveSearchSaveButton', 'click', this.handleSaveButtonClicked.bindAsEventListener(this) );
},
handleSaveButtonClicked:function(evt){
Event.stop(evt);
if(this.validate()){
this.saveSearch($('SearchName').value.strip(),
$('SearchEmailAddress').value.strip(),
DataSerializer.serialize(this._searchModel.dump()),
getPageController().getLinkBackToThisPage()
);
}
return false;
},
saveSearch:function(name, email, jsonString, url){
new Ajax.Request(siteRoot+"savesearch/save.rails", {
method: 'post',
onSuccess: this.saveComplete.bind(this),
parameters: {name:name,email:email,jsonString:jsonString,searchUrl:url}
});
},
saveComplete:function(transport){
if (transport.responseText.match(/<success\/>/)){
this.saveSuccessful();
}else{
this.saveFailed(transport.responseText);
}
},
saveSuccessful:function(){
Element.hide($(this._saveSearchPanelId));
Element.show($(this._validatedMessageId));
$(this._searchNameValidatedMessageId).update($(this._nameId).value.escapeHTML()) ;
},
saveFailed:function(message){
return this._showErrorMessage(this._serverErrorMessageId, message);
}
});
SaveSearchPanel.Create = function() {
new SaveSearchPanel(getPageController().getSearchOptionsModel()).bindEvents();
}
WebRegionModel = Class.create();
Object.extend(WebRegionModel.prototype, FilterModel.prototype);
Object.extend(WebRegionModel.prototype,  {
initialize: function(regionName) {
FilterModel.prototype.initialize.call(this,"WebRegion");
this.constructor = WebRegionModel; // Safari Fix
this._regionName = this._parseRegionName(regionName);
},
_parseRegionName:function(regionName){
return  regionName ? regionName.substring(1):'corporate';
},
dump: function(){
dumpArray = {};
dumpArray._regionName = this._regionName;
return dumpArray;
},
equals: function(other) {
return other._regionName == this._regionName;
},
isEmpty:function(){
return false;
},
clear:function() {
},
getRegionName: function() {
return this._regionName;
}
});
WebRegionModel.scoop = function(dump){
return Object.extend(new WebRegionModel(), dump);
}
/*
* Global Variable Declarations
*/
var ajaxCount = 0;
var progressChicken = new ProgressChicken();
var ratesAndAvailabilityPanel = null;
var _pageController;
var PageControllerClasses = {
"agents": AgentController,
"sales": SearchController,
"rental": RentalController,
"offices": OfficeController,
"openhouses": OpenHousePageController,
"agentdetail": AgentDetailController,
"officedetail": OfficeDetailController,
"areas": AreaController,
"developments": DevelopmentController,
"areadetail": NeighborhoodDetailController,
"propertydetail": PropertyDetailController,
"salesdetail": SalesDetailController,
"rentaldetail": RentalDetailController,
"welcome": WelcomeController,
"rentalwelcome": RentalWelcomeController,
"location": WelcomeController,
"openhousedetail": OpenHouseDetailController,
"developmentdetail": DevelopmentDetailController,
"teamdetail": TeamDetailController,
"_default": SearchController
}
function printHTML(){
var x = 0;
for (var x = 0; x < document.all.length - 1; x++) {
document.getElementById("output").value = x.innerHTML;
}
}
function removeLandingPageStyles(){
if(isLandingPageVisible()){
Element.removeClassName($('body'), 'welcome');
Element.removeClassName($('body'), 'rentalwelcome');
if($('OpenHouses'))
$('OpenHouses').hide();
if($('NewDevelopments'))
$('NewDevelopments').hide();
if($('LetUsSearch'))
$('LetUsSearch').hide();
if($('mortgageServicesButton'))
$('mortgageServicesButton').hide();
if($('updateOptionsButton'))
$('updateOptionsButton').hide();
if($('AboutOurAgents'))
$('AboutOurAgents').hide();
Element.setStyle($('toolbar'),{display: 'block'});
// swap out old FindPropertyDiv
swapFiltersDiv('SwapDiv','frame');
// bind events to new div
prepareAllWidgets();
}
}
function handleWindowOnLoad(controllerName, next, prev) {
moveChangeLocationDropIfPresent();
bindNavigationWidget();
var initialSearchModelDump = $('searchModelInput').value;
PageController.addConstructorParam("searchModel", initialSearchModelDump);
var controllerClass = PageControllerClasses[controllerName] || PageControllerClasses['_default'];
_pageController = new controllerClass(PageController.getConstructorParams());
for (var i = 0; i < PageController.getPageCreatedCallbacks().length; i++) {
PageController.getPageCreatedCallbacks()[i](_pageController);
}
_pageController.onInitialPageLoad();
bindGlassPaneForOptionsPane();
prepareAllWidgets();
prepareWebTrends();
}
function moveChangeLocationDropIfPresent() {
var holder = $("changeLocationHolder");
var tempHolder = $("changeLocationTempHolder");
if(holder && tempHolder) {
holder.innerHTML = tempHolder.innerHTML;
}
}
function bindNavigationWidget(){
registerDropDownEvents('findPropertiesLink', 'findPropertiesDrop');
registerDropDownEvents('changeLocationLink', 'changeLocationDrop');
registerDropDownEvents('findAgentsLink', 'findAgentsDrop');
registerDropDownEvents('aboutusheaderlink', 'aboutUsDrop');
registerDropDownEvents('aboutTheAreaLink', 'aboutTheAreaDrop');
}
function bindGlassPaneForOptionsPane(){
Event.observe(document.body, 'click', hideOptionsPaneOnClick);
}
function hideOptionsPaneOnClick(e){
var filter = $('filter');
if (filter && filter.style.visibility == 'visible') {
var clickedElement = Event.element(e);
if (clickedElement.innerHTML.indexOf('Modify Search') != -1)
return;
while (clickedElement != document.body && clickedElement != null) {
if (Element.hasClassName(clickedElement, 'activated') || clickedElement.id == 'filter')
return;
clickedElement = clickedElement.parentNode;
}
searchOptionInfoClose();
}
}
function clearSortFields(){
$('sir_result_sort_by').value = '';
$('sir_result_sort_direction').value = '';
}
function prepareWebTrends(){
if (typeof WebTrendsAnalyzer == 'function') {
(new WebTrendsAnalyzer()).scan(WebTrendsAnalyzer.INITIAL_RULES);
}
}
function prepareWebTrendsForEmail(){
if (document.getElementsByTagName('FORM').length > 0 && typeof WebTrendsAnalyzer == 'function') {
(new WebTrendsAnalyzer()).scan(WebTrendsAnalyzer.CreateRulesForEmail());
}
}
function createClass(classText){
return new Function("return" + classText)();
}
function loadResults(html, searchModelDumpStr, countString, pageHeading){
if (!getPageController()) {
setTimeout(loadResults.bind(window, html, searchModelDumpStr, countString), 10);
return;
}
var newSearchModel = null;
if (searchModelDumpStr) {
var searchModelDump = null;
searchModelDump = createClass(searchModelDumpStr);
newSearchModel = SearchOptionsModel.scoop(searchModelDump, getPageController());
if (countString)
getPageController().setCountString(countString);
if (!newSearchModel.equals(getPageController().getSearchOptionsModel())) {
getPageController().setSearchOptionsModel(newSearchModel);
prepareAllWidgets();
}
}
if (pageHeading && isLandingPageVisible()) {
var pageHeadingElement = $('pageHeaderContainer');
if(pageHeadingElement) {
Element.show(pageHeadingElement);
pageHeadingElement.innerHTML = pageHeading;
}
}
progressChicken.stop(true);
clearSplashImageFromSearchOptionInfoDiv();
switchToResultCSSClass();
$('searchResults').innerHTML = html;
Element.show($('searchResults'));
for(var modelName in getPageController()._filterModelsUsed()) {
var model = getSearchOptionsModel().getFilterModel(modelName);
model.notifyChange();
}
(window.onLoadResultsCallback || new Function())();
}
function getPageController(){
return _pageController;
}
function getSearchOptionsModel(){
return getPageController().getSearchOptionsModel();
}
function showSearchOption(element, type) {
if (!getPageController()) {
setTimeout(showSearchOption.bind(window, element, type), 10);
return;
}
type = type.toLowerCase().replace("/", "");
var filterHeader = FilterViewFactory.getHeaderElement(type);
if (filterHeader && filterHeader.className.indexOf('activated') == -1) {
showSearchOptionInfoDiv(type);
switchToResultsView(element);
}
}
function getSearchUrl(methodName){
return regionRoot + '/' + getSearchOptionsModel().getSearchType() + '/' + methodName + '.rails';
}
function showSearchOptionInfoDiv(type){
if (typeof WebTrendsAnalyzer == 'function') {
(new WebTrendsAnalyzer()).fireWebTrendAction(WebTrendsAnalyzer.CreateActionForFilterOptionType(regionRoot, type));
}
if (type == FilterKey.LOCATION || type == FilterKey.CAT_BASED_LOCATION) {
var locModel = getSearchOptionsModel().getFilterModel(FilterKey.LOCATION);
if (!this.getPageController().showLocationTree()) {
return;
}
if (locModel.isQuickSearch()) {
type = FilterKey.LOCATION;
}
}
var options = {
searchType: type,
searchModel: DataSerializer.serialize(getSearchOptionsModel().dump())
};
updateSearchOptionPane(getSearchUrl(type), options, type);
}
function clearLinkBelowFilters(){
if ($('automatedUpdateOptionsDiv'))
Element.hide($('automatedUpdateOptionsDiv'));
if ($('otherNetworkLocationsDiv'))
Element.hide($('otherNetworkLocationsDiv'));
}
var SEARCH_OPTIONS_PANE_CACHE = {};
function clearSearchOptionsPaneCache(){
SEARCH_OPTIONS_PANE_CACHE = {};
}
function cacheSearchOptionsPane(type){
SEARCH_OPTIONS_PANE_CACHE[type] = $('filter');
}
function isNotInCache(options){
if (options && options.searchType) {
return typeof SEARCH_OPTIONS_PANE_CACHE[options.searchType] == 'undefined';
}
return true;
}
function updateSearchOptionPane(vmUrl, options, type) {
if ($('filter')) {
prepareFilterForRemoval();
$('searchOptionInfoDiv').removeChild($('filter'));
}
if (isNotInCache(options)) {
showFilterWaitingMessage(type);
putOptionPaneIntoCache(vmUrl, options || {});
}
else {
restoreSearchOptionsPaneFromCache(options);
}
Element.show($('searchOptionInfoDiv'));
}
function putOptionPaneIntoCache(vmUrl, options){
makeAjaxUpdater('searchOptionInfoDiv', vmUrl, function(request){
clearSearchOptionInfoDiv();
if (typeof options != 'undefined') {
if (typeof options.widgetClass != 'undefined') {
options.widgetClass.Create();
}
if (typeof options.webtrendsrules != 'undefined' && typeof WebTrendsAnalyzer == 'function') {
(new WebTrendsAnalyzer()).scan(options.webtrendsrules);
}
}
if (typeof WebTrendsAnalyzer == 'function') {
(new WebTrendsAnalyzer()).scan(WebTrendsAnalyzer.CreateRulesForOptionPane(options.searchType));
}
if (options && options.searchType) {
bindSearchOptionsPaneWidgets(options.searchType.toLowerCase());
cacheSearchOptionsPane(options.searchType);
positionSearchOptionsPane(options.searchType.toLowerCase());
hideFilterWaitingMessage();
}
}, options);
}
function hideFilterWaitingMessage(){
$('filterWaitingMessage').style.visibility = "hidden";
}
function showFilterWaitingMessage(type){
$('filterWaitingMessage').style.visibility = "";
positionSearchOptionsPane(type, true, 'filterWaitingMessage');
}
function restoreSearchOptionsPaneFromCache(options){
$('searchOptionInfoDiv').appendChild(SEARCH_OPTIONS_PANE_CACHE[options.searchType]);
positionSearchOptionsPane(options.searchType.toLowerCase(), true);
fixCheckboxesInFilter();
}
function bindSearchOptionsPaneWidgets(searchType){
var model = getSearchOptionsModel().getFilterModel(searchType);
SearchOptionsPanelFactory.create(searchType, model);
}
function prepareFilterForRemoval(){
if ($('filter')) {
var inputs = $('filter').getElementsByTagName('INPUT');
$('filter').style.left = '';
var checkboxes = [];
for (var i = 0; i < inputs.length; i++) {
if (inputs[i].type == 'checkbox' && inputs[i].checked) {
inputs[i]._oldChecked = true;
}
}
}
}
function fixCheckboxesInFilter(){
if ($('filter')) {
var inputs = $('filter').getElementsByTagName('INPUT');
var checkboxes = [];
for (var i = 0; i < inputs.length; i++) {
if (inputs[i].type == 'checkbox' && typeof inputs[i]._oldChecked == 'boolean') {
inputs[i].checked = inputs[i]._oldChecked;
inputs[i]._oldChecked = false;
}
}
}
}
function positionSearchOptionsPane(filterType, fromCache, filter) {
var filter = filter || 'filter';
var filterHeader = $(filterType + 'DT');
var optionsPane = $(filter);
if (!filterHeader) {
if (filterType == 'location') {
fromCache = false;
filterHeader = $('categorybasedlocationDT');
}
}
var header = Position.cumulativeOffset(filterHeader);
var headerTop = header[1];
var paneTop = Position.cumulativeOffset($('content'))[1];
var moveBy =  headerTop - paneTop ;
moveBy += 1;
optionsPane.style.top = moveBy + 'px';
optionsPane.style.visibility = 'visible';
}
function handleResetClicked(){
if (getSearchOptionsModel().isEmpty() == false) {
getSearchOptionsModel().clear();
if (!isLandingPageVisible()) {
submitSearch();
}
clearSearchOptionsPaneCache();
}
}
function showSaveSearchResultInfoDiv(){
var rules = [];
if (typeof WebTrendsAnalyzer == 'function') {
(new WebTrendsAnalyzer()).fireWebTrendAction(WebTrendsAnalyzer.INITIATE_SAVE_SEARCH_ACTION);
rules = WebTrendsAnalyzer.DYNAMIC_SAVE_SEARCH_RULES;
}
makeAjaxUpdater('watchThisPanel', regionRoot + '/savesearch/panel.rails', function(request){
SaveSearchPanel.Create();
(new WebTrendsAnalyzer()).scan(rules);
Element.show($('watchThisPanel'));
setTimeout(function(){
$('SearchName').focus()
}, 0);
});
}
function clearSearchOptionInfoDiv(){
Element.show($('searchOptionInfoDiv'));
}
function switchToResultsView(element, controllerName){
getPageController().switchToResultsView(element);
}
function switchToResultCSSClass(){
getPageController().updateViewToResults();
}
function resetMinValueCombo(){
var maxValuesCombo = new Select("MaxDropDownList");
var minValuesCombo = new Select("MinDropDownList");
var maxSelectedIndex = maxValuesCombo.getSelectionIndex()
if (maxSelectedIndex <= 0) {
maxSelectedIndex = maxValuesCombo.getCount() - 1;
}
for (var i = 0; i <= maxSelectedIndex; i++) {
minValuesCombo.getOptionAt(i).disabled = false;
}
for (var i = maxSelectedIndex + 1; i < maxValuesCombo.getCount(); i++) {
minValuesCombo.getOptionAt(i).disabled = true;
}
if (minValuesCombo.getSelectionIndex() > maxValuesCombo.getSelectionIndex()) {
minValuesCombo.setSelectionIndex(maxValuesCombo.getSelectionIndex());
}
}
function updateResultsAndTotalForPrice(){
var maxValuesCombo = $("MaxDropDownList");
var selectedMaxValueIndex = maxValuesCombo.selectedIndex;
var minValuesCombo = $("MinDropDownList");
var selectedMinValueIndex = minValuesCombo.selectedIndex;
var minValueOption = minValuesCombo.options[selectedMinValueIndex];
var maxValueOption = maxValuesCombo.options[selectedMaxValueIndex];
var priceModel = getSearchOptionsModel().getFilterModel(FilterKey.PRICE);
priceModel.setMinPrice(minValueOption.value, minValueOption.innerHTML);
priceModel.setMaxPrice(maxValueOption.value, maxValueOption.innerHTML);
}
function updateResultsAndTotalForBedAndBath(selectElement, ddElementName, criteriaType, criteriaValue, setterToCall){
!setterToCall || eval('getSearchOptionsModel().getFilterModel(FilterKey.BED_BATH).' + setterToCall + '(selectElement.value, selectElement.options[selectElement.selectedIndex].text)');
}
function updateResultsAndTotalForInteriorSizeLotSize(selectElement, ddElementName, criteriaType, criteriaValue, setterToCall){
!setterToCall || eval('getSearchOptionsModel().getFilterModel(FilterKey.INTERIOR_SIZE_LOT_SIZE).' + setterToCall + '(selectElement.value, selectElement.options[selectElement.selectedIndex].text)');
}
function searchOptionInfoClose(){
removeSearchOptionHighlighting();
if ($('searchOptionInfoDiv')) {
Element.hide($('searchOptionInfoDiv'));
}
}
function watchThisClose(){
Element.hide($('watchThisPanel'));
}
function removeSearchOptionHighlighting(){
removeClassNameForChildrenWithinAParentTag('searchOptions', 'dt', 'activated');
//added because the location Widget has a special style
removeClassNameForChildrenWithinAParentTag('searchOptions', 'dt', 'activatedFirst');
removeClassNameForChildrenWithinAParentTag('searchOptions', 'dd', 'activated');
//selected stuff
}
function nextResultNumber(){
return Math.round(10000 * Math.random());
}
function makeAjaxUpdater(divName, methodName, oncomplete, params){
progressChicken.start();
var o = new Ajax.Updater(divName, methodName, {
on200: function(transport){
if (transport.responseText.match(/errorUrl/))
window.location.href = baseUrl + '/GenericError.htm';
},
onComplete: function(request){
//not sure why but if the stop is AFTER the oncomplete it won't fire...
progressChicken.stop();
if (oncomplete) {
oncomplete(request);
}
},
//we don't need the onException and onError b/c onComplete is Always Called
evalScripts: true,
parameters: params ||
{}
});
return o;
}
function prepareAllWidgets(){
if ($('searchOptions')) {
prepareAllViewsForModel(getSearchOptionsModel());
}
}
function prepareAllViewsForModel(optionsModel){
var keys = optionsModel.getFilterModelKeys();
for (var i = 0; i < keys.length; i++) {
if (FilterViewFactory.getHeaderElement(keys[i])) {
FilterViewFactory.create(keys[i], optionsModel);
}
}
}
function moveSearchOptionInfoDivUnderContent(){
//move searchOptionInfoDiv under content and fix 'filter' style
var searchOptionInfoDiv = $('searchOptionInfoDiv');
searchOptionInfoDiv.parentNode.removeChild(searchOptionInfoDiv);
$('content').appendChild(searchOptionInfoDiv);
if($('filter'))
$('filter').style.left = '';
}
function swapFiltersDiv(currentFilters, newFilters){
if ($(currentFilters) && $(newFilters)){
var tmp = $(currentFilters).innerHTML;
$(currentFilters).innerHTML = $(newFilters).innerHTML;
$(newFilters).innerHTML = tmp;
}
}
function backToHome() {
if (!getPageController()) {
setTimeout(backToHome.bind(window), 10);
return;
}
var pageController = getPageController();
if(pageController.CONTROLLER_NAME == "offices")
return;
if ($('searchResults') && pageController._initialResults && !isStringBlank(pageController._initialResults)) {
if ($('searchResults').innerHTML != pageController._initialResults) {
$('searchResults').innerHTML = pageController._initialResults;
if (pageController._initialModel) {
pageController.setSearchOptionsModel(pageController._scoopSearchOptionsModel(pageController._initialModel));
clearSearchOptionsPaneCache();
prepareAllWidgets();
}
}
}
else {
if (isShowLandingPage()) {
Element.addClassName($('body'), 'welcome');
if($('OpenHouses'))
$('OpenHouses').show();
if($('NewDevelopments'))
$('NewDevelopments').show();
if($('LetUsSearch'))
$('LetUsSearch').show();
if($('mortgageServicesButton'))
$('mortgageServicesButton').show();
if($('updateOptionsButton'))
$('updateOptionsButton').show();
if($('AboutOurAgents'))
$('AboutOurAgents').show();
if($('toolbar'))
Element.hide('toolbar');
//selected stuff
removeClassNameForChildrenWithinAParentTag('searchOptions', 'dt', 'activated');
if($('searchResults'))
Element.hide('searchResults');
$('content').className = 'content landingPageContent';
if (rootExpandedView)
rootExpandedView.hide();
getSearchOptionsModel().clear();
clearSearchOptionsPaneCache();
var pageHeader = $('pageHeaderContainer');
if(pageHeader){
Element.hide(pageHeader);
}
var secondarySearchTabsDiv = $('secondarySearchTabsDiv');
if(secondarySearchTabsDiv){
secondarySearchTabsDiv.className = 'secondaryTabs empty';
}
var secondarySearchTabs = $('secondarySearchTabs');
if(secondarySearchTabs){
Element.hide(secondarySearchTabs);
}
$('findPropertiesLink').className = '';
if($("findPropertiesDownArrow")) {
Element.show($("findPropertiesDownArrow"));
}
//swap FindPropertiesDiv
swapFiltersDiv('frame','SwapDiv');
//move searchOptionInfoDiv back under sidebar
if ($('searchOptionInfoDiv')){
var searchOptionInfoDiv = $('searchOptionInfoDiv');
searchOptionInfoDiv.parentNode.removeChild(searchOptionInfoDiv);
$('sidebar').appendChild(searchOptionInfoDiv);
moveSearchOptionInfoDivUnderContent();
// bind events to new div
prepareAllWidgets();
}
}
}
}
function isStringBlank(str){
return /^\s*$/.test(str);
}
function isShowLandingPage() {
return !(document.location.href.indexOf('404.htm') > -1) && $('content') && document.body.className.indexOf('welcome') == -1 && !isLandingPageVisible() && !isAboutUsOfficesPage() && !isAreasPage();
}
function isAboutUsOfficesPage(){
return document.location.href.indexOf("aboutus/officedirectory.rails") > -1
}
function isAreasPage(){
return document.location.href.indexOf("agents/Real-Estate-Agents-") > -1
}
function isLandingPageVisible() {
return getPageController().isLandingPageVisible();
}
function clearSplashImageFromSearchOptionInfoDiv(){
var infoDiv = $('searchOptionInfoDiv');
var splashDivs = document.getElementsByClassName('color2', infoDiv);
if (splashDivs.length > 0)
infoDiv.innerHTML = "";
clearLinkBelowFilters();
}
function showFloorPlanImages(listingNumber){
removeClassNameForChildrenWithinAParentTag('additionalInfoUL', 'li', 'selected');
Element.addClassName($('floorPlanLI'), 'selected');
new Ajax.Updater('tabDetailDiv', siteRoot + '/property/FloorPlanImages.rails?listingnumber=' + listingNumber, {
asynchronous: true,
evalScripts: true,
onComplete: function(request){
setTimeout("Element.scrollTo($('floorPlanLI'));", 100);
}
});
}
function showMapForProperty(url){
if ($('searchResults')) {
Element.hide($('searchResults'));
}
Element.show($('tabDetailDiv'));
removeClassNameForChildrenWithinAParentTag('additionalInfoUL', 'li', 'selected');
Element.addClassName($('mapLI'), 'selected');
$('tabDetailDiv').innerHTML = '<iframe class="map" style="width: 550px; height: 550px;padding:0px;" frameborder="0"' +
'src="' +
url +
'"></iframe>';
setTimeout("Element.scrollTo($('mapLI'));", 100);
}
function showLocalInformation(zip){
removeClassNameForChildrenWithinAParentTag('additionalInfoUL', 'li', 'selected');
Element.addClassName($('localInformationLI'), 'selected');
new Ajax.Updater('tabDetailDiv', siteRoot + '/property/localinfo.rails?onBoardZipCode=' + zip, {
onComplete: function(request){
setTimeout("Element.scrollTo($('localInformationLI'));", 100);
showAmenities(zip);
}
});
}
function showAmenities(zip){
Element.show($('tabDetailDiv'));
if ($('searchResults')) {
Element.hide($('searchResults'));
}
removeClassNameForChildrenWithinAParentTag('localInformationUL', 'li', 'selected');
Element.addClassName($('amenitiesLI'), 'selected');
new Ajax.Updater('localInformationContent', siteRoot + '/property/amenities.rails?zipcode=' + zip, {
onComplete: function(response){
setTimeout("Element.scrollTo($('tabDetailDiv'));", 100);
}
});
}
function showCommunityProfile(zip){
removeClassNameForChildrenWithinAParentTag('localInformationUL', 'li', 'selected');
Element.addClassName($('communityProfileLI'), 'selected');
new Ajax.Updater('localInformationContent', siteRoot + '/property/communityprofile.rails?zipcode=' + zip);
}
function showSchools(zip){
removeClassNameForChildrenWithinAParentTag('localInformationUL', 'li', 'selected');
Element.addClassName($('schoolsLI'), 'selected');
new Ajax.Updater('localInformationContent', siteRoot + '/property/schooldistricts.rails?zipcode=' + zip);
}
function showDistricts(zip){
removeClassNameForChildrenWithinAParentTag('localInformationUL', 'li', 'selected');
Element.addClassName($('districtsLI'), 'selected');
new Ajax.Updater('localInformationContent', siteRoot + '/property/districts.rails?zipcode=' + zip);
}
function showHomeSales(zip){
removeClassNameForChildrenWithinAParentTag('localInformationUL', 'li', 'selected');
Element.addClassName($('homeSalesLI'), 'selected');
new Ajax.Updater('localInformationContent', siteRoot + '/property/homesales.rails?zipcode=' + zip);
}
function showFeatures(listingNumber){
removeClassNameForChildrenWithinAParentTag('additionalInfoUL', 'li', 'selected');
Element.addClassName($('featureLI'), 'selected');
new Ajax.Updater('tabDetailDiv', siteRoot + '/property/Features.rails?listingnumber=' + listingNumber, {});
}
function showListingsTab(){
clearSortFields();
if ($('tabDetailDiv')) {
Element.hide($('tabDetailDiv'));
}
removeClassNameForChildrenWithinAParentTag('additionalInfoUL', 'li', 'selected');
Element.addClassName($('currentListingsLI'), 'selected');
getPageController().updateSearchResults();
}
function showRentalsTab(){
clearSortFields();
removeClassNameForChildrenWithinAParentTag('additionalInfoUL', 'li', 'selected');
Element.addClassName($('currentRentalsLI'), 'selected');
getPageController().updateSearchResults();
}
function showSelectSalesTab(){
clearSortFields();
removeClassNameForChildrenWithinAParentTag('additionalInfoUL', 'li', 'selected');
Element.addClassName($('selectSalesLI'), 'selected');
getPageController().updateSearchResults();
}
function showOfficeDirections(officeId){
removeClassNameForChildrenWithinAParentTag('additionalInfoUL', 'li', 'selected');
Element.addClassName($('officeDirectionsLI'), 'selected');
new Ajax.Updater('searchResults', siteRoot + '/offices/directions.rails?officeId=' + officeId, {});
}
function showOfficeAgentRoster(officeId){
clearSortFields();
removeClassNameForChildrenWithinAParentTag('additionalInfoUL', 'li', 'selected');
Element.addClassName($('agentRoster'), 'selected');
gotoPage(1);
}
function showSalesTeamTab(teamid){
clearSortFields();
removeClassNameForChildrenWithinAParentTag('additionalInfoUL', 'li', 'selected');
Element.addClassName($('salesTeamLI'), 'selected');
new Ajax.Updater('searchResults', siteRoot + '/teams/summary/' + teamid, {});
}
function removeClassNameForChildrenWithinAParentTag(parentElementName, childTagName, classNameToRemove, classNameToAdd){
additionalInfoULElement = $(parentElementName);
if (additionalInfoULElement) {
var liChildren = additionalInfoULElement.getElementsByTagName(childTagName);
for (var i = 0; i < liChildren.length; i++) {
var liElement = liChildren[i];
if (classNameToAdd && liElement.id.length > 0) {
var ddElement = $(liElement.id.replace(/DT/, 'DD'));
if (ddElement.style.display == '') {
Element.addClassName(liElement, classNameToAdd);
}
}
Element.removeClassName(liElement, classNameToRemove);
}
}
}
function changeSortOrder(order){
createCookie("priceOrder", order);
getPageController().goToPage(1);
}
function changeResultSort(newSortBy, newSortDirection){
$("sir_result_sort_by").value = newSortBy;
$("sir_result_sort_direction").value = newSortDirection;
gotoPageTop(1);
}
function addInteriorSizeSession(value){
createCookie("interiorSize", value);
$('selectedInteriorSize').selectedIndex = 0;
getSearchOptionsModel().getFilterModel(FilterKey.INTERIOR_SIZE_LOT_SIZE).resetInteriorSize();
}
function addLotSizeSession(value){
createCookie("lotSize", value);
$('selectedLotSize').selectedIndex = 0;
getSearchOptionsModel().getFilterModel(FilterKey.INTERIOR_SIZE_LOT_SIZE).resetLotSize();
}
function createCookie(name, value){
var exdate = new Date();
exdate.setDate(exdate.getDate() + 30);
document.cookie = name + "=" + value + ";expires=" + exdate.toGMTString() + "; path=/";
}
function setInteriorSizeUnitForLondon(value){
createCookie("interiorSize", value);
getPageController().updateSearchResults();
}
function moveToASearchResultsPage(pageNo, type){
getPageController().goToPage(pageNo);
}
function filterByLocation(element, locationId){
var isChecked;
if (Element.hasClassName(element, "checked")) {
Element.replaceClassName(element, "checked", "cleared");
isChecked = "false";
}
else {
Element.replaceClassName(element, "cleared", "checked");
isChecked = "true";
}
new Ajax.Request(getSearchUrl('addcriteria') + '?type=includelocation&treeId=' + locationId + "&checked=" + isChecked, {});
}
function filterByCheckbox(filterModelName, isChecked, checkBox){
var filterModel = getSearchOptionsModel().getFilterModel(filterModelName);
if (filterModel) {
if (isChecked) {
filterModel.addCheckBox(checkBox);
}
else {
filterModel.removeCheckBox(checkBox);
}
}
}
function RenderLineOfBusiness(zip, lineOfBusiness, element){
var location = siteRoot + '/property/amenitiesbylineofbusiness.rails?zipCode=' + zip + '&lineOfBusiness=' + lineOfBusiness;
RenderSubLocalInfo(location, element, lineOfBusiness);
}
function RenderSchoolDistrict(schoolDistrictNo, element){
var location = siteRoot + '/property/schoolsbydistrict.rails?schoolDistrictNo=' + schoolDistrictNo;
RenderSubLocalInfo(location, element, schoolDistrictNo);
}
function RenderPrivateSchools(zipCode, element){
var location = siteRoot + '/property/privateschoolsbyzipcode.rails?zipCode=' + zipCode;
RenderSubLocalInfo(location, element, 'privateschools');
}
function RenderSubLocalInfo(location, node, divToUpdate){
if ($(node).hasClassName('expand')) {
Element.replaceClassName(node, 'expand', 'collapse');
new Ajax.Updater(divToUpdate, location, {
onComplete: function(response){
Element.show($(divToUpdate));
setTimeout("Element.scrollTo($('" + divToUpdate + "'));", 1000);
}
});
}
else {
Element.replaceClassName(node, 'collapse', 'expand');
Element.hide($(divToUpdate));
}
}
function gotoPage(page){
getPageController().goToPage(page);
}
function gotoPageTop(pageNo) {
gotoPage(pageNo);
}
function moveToLocation(action, webRegionIdToSwitch){
url = getSearchUrl(action);
if (webRegionIdToSwitch) {
url = url + '?webRegionId=' + webRegionIdToSwitch;
}
new Ajax.Request(url);
}
function disableAndSwitchToRegion(regionToSwitch, regionDisplayText, regionLocationNodeId, rootRegionLocationNodeId){
var locationModel = getSearchOptionsModel().getFilterModel(FilterKey.LOCATION);
locationModel.disableQuickSearch();
var chosenRegionNode;
var testNode = locationModel.getRootLocationNode();
if (regionLocationNodeId != rootRegionLocationNodeId) {
// Since we have changed the default state to unchecked we can skip the next step
// testNode.setState(CheckBoxState.UnChecked);
var children = testNode.children();
for (var i = 0; i < children.length; i++) {
if (children[i].locationId == regionLocationNodeId) {
chosenRegionNode = children[i];
chosenRegionNode.setState(CheckBoxState.Checked);
}
}
testNode.setState(CheckBoxState.Partial);
locationModel.nodeToggled(chosenRegionNode);
}
locationModel.notifyChange();
}
function enableLocationCriteria(regionDisplayText){
var locationModel = getSearchOptionsModel().getFilterModel(FilterKey.LOCATION);
locationModel.enableQuickSearch();
var rootNode = locationModel.getRootLocationNode();
rootNode.setState(CheckBoxState.UnChecked);
locationModel.notifyChange();
}
function enableCorporateLocation(rootRegionLocationNodeId){
var locationModel = getSearchOptionsModel().getFilterModel(FilterKey.LOCATION);
locationModel.disableQuickSearch();
var rootNode = locationModel.getCorporateNode();
rootNode.setState(CheckBoxState.UnChecked);
locationModel.nodeToggled(rootNode);
locationModel.notifyChange();
}
function onLocationComponentClicked(treeId){
showLocationOption('locationDiv0', treeId, 0, this);
clearSearchOptionInfoDiv();
switchToResultsView($('locationDT'));
}
function paginateToDetailPage(anchor, index){
getPageController().resultsLinkClicked(anchor.href, index);
return false;
}
function filterByDropDown(dropdown){
if (typeof dropdown._select == 'undefined') {
dropdown._select = new Select(dropdown.id);
}
var value = dropdown._select.getSelection().value;
if (dropdown.name == 'Fireplaces') {
getPageController().getSearchOptionsModel().getFilterModel(FilterKey.FEATURES_AND_AMENITIES).setMinFireplaces(value);
}
else if (dropdown.name == 'Garages') {
getPageController().getSearchOptionsModel().getFilterModel(FilterKey.FEATURES_AND_AMENITIES).setMinGarageBays(value);
}
}
function londonViewPropertiesLinkClicked(){
Element.show($('londonSearch'));
Element.hide($('viewAllPropertiesArea'));
clearSplashImageFromSearchOptionInfoDiv();
switchToResultCSSClass();
gotoPage(1);
$('findPropertiesLink').addClassName("active");
unregisterAnyHandler($('findPropertiesLink'), 'mouseover');
unregisterAnyHandler($('findPropertiesLink'), 'mouseout');
}
function fixLondonViewPropertiesLink(){
if ($('resultTitleLink_1') && $('londonSearch') && $('viewAllPropertiesArea')) {
Element.show($('londonSearch'));
Element.hide($('viewAllPropertiesArea'));
}
}
function fixAreaDetailSlideshowImage(img){
img = $(img);
if (img.getDimensions().width > 408) {
var parent = img.parentNode;
var newImg = document.createElement('IMG');
newImg.src = img.src;
newImg.alt = img.alt;
newImg.title = img.title;
newImg.width = 408;
Event.observe(newImg, 'load', fixAreaDetailSlideshowImageHeightForIE.bind(window, newImg));
img.parentNode.appendChild(newImg);
img.parentNode.removeChild(img);
fixAreaDetailSlideshowImageHeightForIE(newImg);
}
}
function fixAreaDetailSlideshowImageHeightForIE(img){
img = $(img);
var height = img.getDimensions().height;
if (height > 308) {
img.height = 308;
}
}
function iFrameHeight(){
if (document.getElementById && !(document.all)) {
h = document.getElementById('idxframe').contentDocument.body.scrollHeight;
document.getElementById('idxframe').style.height = h;
}
else
if (document.all) {
h = document.frames('idxframe').document.body.scrollHeight;
document.all.idxframe.style.height = h;
}
}
function agentSubmitSearch() {
$('letterFromForm').value = '';
getPageController().onSubmitHook();
submitSearch();
ClearAlphabetFilterSelected();
}
function submitSearch() {
window.onLoadResultsCallback = searchOptionInfoClose;
getPageController().getResultsUpdater().onChange();
}
function submitSearchWithoutClose() {
window.onLoadResultsCallback = new Function();
getPageController().getResultsUpdater().onChange();
}
function resetCriteria(key){
delete SEARCH_OPTIONS_PANE_CACHE[key];
getSearchOptionsModel().getFilterModel(key).clear();
if (!isLandingPageVisible()) {
submitSearchWithoutClose();
}
showSearchOptionInfoDiv(key);
}
function changeItemsPerPage(value){
children = $("items_per_page").getElementsByTagName("a");
for (var i = 0; i < children.length; i++) {
var child_id = children[i].id;
$(child_id).removeClassName("selected");
}
$(value + "_per_page").addClassName("selected");
$("searchModelItemsPerPageInput").value = value;
gotoPageTop(1);
}
function ClearAlphabetFilterSelected(){
if($('alphabetFilter')){
var matches = $('alphabetFilter').getElementsByClassName("selected");
$A(matches).each(function(currentMatch){
Element.removeClassName(currentMatch, "selected");
});
}
}
function navToClickHandler(selectListId) {
var selected = $(selectListId).selectedIndex;
window.location = window.location + '/' + Element.readAttribute($(selectListId).options[selected], 'navto');
}
function isOlderSafari(){
if (BrowserDetect.browser=="Safari" && BrowserDetect.version > 0 && BrowserDetect.version <= 419.3){
return true;
}
return false;
}
function isNewerSafari(){
if (BrowserDetect.browser=="Safari" && BrowserDetect.version  > 0 && BrowserDetect.version  > 419.3){
return true;
}
return false;
}
function isFireFox2(){
if (BrowserDetect.browser == "Firefox" && BrowserDetect.version == 2) {
return true;
}
return false;
}
function isFireFox3(){
if (BrowserDetect.browser == "Firefox" && BrowserDetect.version == 3) {
return true;
}
return false;
}
function isIE7(){
if (BrowserDetect.browser=="Explorer" && BrowserDetect.version  == 7){
return true;
}
return false;
}
function isChrome(){
if (BrowserDetect.browser == "Chrome") {
return true;
}
return false;
}
SAFARI = {}
SAFARI = {}
WINDOW = {}
MINUSONE = {}
SAFARI.positionSearchOptionsPane = function(filterType, fromCache, filter) {
WINDOW.positionSearchOptionsPane(filterType, fromCache, filter);
var filter = filter || 'filter';
var optionsPane = $(filter);
var topWithPixel = new String(optionsPane.style.top);
var topPostion = Number(topWithPixel.substr(0, topWithPixel.indexOf("px")));
optionsPane.style.top = (topPostion - 1) + 'px';
}
MINUSONE.positionSearchOptionsPane = function(filterType, fromCache, filter) {
WINDOW.positionSearchOptionsPane(filterType, fromCache, filter);
var filter = filter || 'filter';
var optionsPane = $(filter);
var topWithPixel = new String(optionsPane.style.top);
var topPostion = Number(topWithPixel.substr(0, topWithPixel.indexOf("px")));
optionsPane.style.top = (topPostion - 1) + 'px';
}
SAFARI.findPos = function(obj) {
var toRet = WINDOW.findPos(obj);
if(obj.id=='locationParentNode'){
curtop+=SAFARI.topDifference();
curleft+=20;
}
return toRet;
}
SAFARI.topDifference = function(obj){
return 174;
}
BrowserDetect.init();
if (isOlderSafari() || isNewerSafari() || isChrome()) {
WINDOW.positionSearchOptionsPane = positionSearchOptionsPane;
positionSearchOptionsPane = SAFARI.positionSearchOptionsPane;
WINDOW.findPos = findPos;
findPos = SAFARI.findPos;
}
if (isFireFox3()) {
WINDOW.positionSearchOptionsPane = positionSearchOptionsPane;
positionSearchOptionsPane = MINUSONE.positionSearchOptionsPane;
}
function ExpandSelectSold(listingid, element) {
var location = '/selectsalesexpanded/Expanded.rails?listingId=' + listingid;
ToggleSecondRow(location, element, listingid);
}
function ToggleSecondRow(location, node, listingId) {
var divToUpdate = 'selectSoldDetails' + listingId;
var hiddenRow = listingId + '_hiddenRow';
if ($(node).hasClassName('expand')) {
Element.replaceClassName(node, 'expand', 'collapse');
new Ajax.Updater(divToUpdate, location, {
onComplete: function(response) {
Element.show($(hiddenRow));
}
});
}
else {
Element.replaceClassName(node, 'collapse', 'expand');
Element.hide($(hiddenRow));
}
}
