initial commit

This commit is contained in:
Chris Sewell
2012-11-28 03:55:08 -05:00
parent 7adb399b2e
commit cf140a2e97
3247 changed files with 492437 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

33
html/messages2/autotab.js Executable file
View File

@ -0,0 +1,33 @@
0
/* This script and many more are available free online at
The JavaScript Source!! http://javascript.internet.com
Created by: Cyanide_7 | */
var isNN = (navigator.appName.indexOf("Netscape")!=-1);
function autoTab(input,len, e) {
var keyCode = (isNN) ? e.which : e.keyCode;
var filter = (isNN) ? [0,8,9] : [0,8,9,16,17,18,37,38,39,40,46];
if(input.value.length >= len && !containsElement(filter,keyCode)) {
input.value = input.value.slice(0, len);
input.form[(getIndex(input)+1) % input.form.length].focus();
}
function containsElement(arr, ele) {
var found = false, index = 0;
while(!found && index < arr.length)
if(arr[index] == ele)
found = true;
else
index++;
return found;
}
function getIndex(input) {
var index = -1, i = 0, found = false;
while (i < input.form.length && index == -1)
if (input.form[i] == input)index = i;
else i++;
return index;
}
return true;
}

144
html/messages2/formmail.php Executable file
View File

@ -0,0 +1,144 @@
<?php
$for = $_POST['for'];
$name = $_POST['name'];
$company = $_POST['company'];
$phone = "(".$_POST['phone'].")".$_POST['phone-2']."-".$_POST['phone-3'];
$ext = "ext. ".$_POST['ext'];
$time_to_call = $_POST['time_to_call'];
$mobile = "(".$_POST['mobile'].")".$_POST['mobile-2']."-".$_POST['mobile-3'];
$time_to_call_mobile = $_POST['time_to_call_mobile'];
$fax = "(".$_POST['fax'].")".$_POST['fax-2']."-".$_POST['fax-3'];
$telephoned = $_POST['telephoned'];
$came_to_see_you = $_POST['came_to_see_you'];
$wants_to_see_you = $_POST['wants_to_see_you'];
$returned_your_call = $_POST['returned_your_call'];
$please_call = $_POST['please_call'];
$will_call_again = $_POST['will_call_again'];
$rush = $_POST['rush'];
$special_attention = $_POST['special_attention'];
$callers_message = $_POST['callers_message'];
$signed_data = explode('||',$_POST['signed']);
//$signed = $_POST['signed'];
//$from = $_POST['signed'];
$signed = $signed_data[0];
$from = $signed_data[0];
$reply_to = $signed_data[1];
$date = "Time of call: ".date("F j, Y, g:i a");
$time = date("F j, Y, g:i a");
if($ext == 'ext. ')
$ext = '';
else $ext = $ext;
if($time_to_call != '')
$time_to_call = 'Time to call: '.$time_to_call;
if($mobile != '()-')
$mobile = 'Mobile: '.$mobile;
else $mobile = '';
if($time_to_call_mobile != '')
$time_to_call_mobile = 'Time to call mobile: '.$time_to_call_mobile;
if($fax != '()-')
$fax = 'Fax: '.$fax;
else $fax = '';
if($telephoned == 'on')
$telephoned = 'Telephoned';
else $telephoned = '';
if($came_to_see_you == 'on')
$came_to_see_you = 'Came to see you';
else $came_to_see_you = '';
if($wants_to_see_you == 'on')
$wants_to_see_you = 'Wants to see you';
else $wants_to_see_you = '';
if($returned_your_call == 'on')
$returned_your_call = 'Returned your call';
else $returned_your_call = '';
if($please_call == 'on')
$please_call = 'Please call';
else $please_call = '';
if($will_call_again == 'on')
$will_call_again = 'Will call again';
else $will_call_again = '';
if($rush == 'on')
$rush = 'Rush';
else $rush = '';
if($special_attention == 'on')
$special_attention = 'Special Attention';
else $special_attention = '';
if($callers_message != '')
$callers_message = 'Message: '.$callers_message;
if($signed != '')
$signed = 'Signed: '.$signed;
$body = "$date
Name: $name
Company: $company
Phone: $phone $ext
";
if($time_to_call != '')
$body .= $time_to_call;
if($mobile != '')
$body .= $mobile;
if($time_to_call_mobile != '')
$body .= $time_to_call_mobile;
if($fax != '')
$body .= $fax;
if($telephoned != '' || $came_to_see_you != '' || $wants_to_see_you != '' || $returned_your_call != '' || $please_call != '' || $will_call_again != '' || $rush != '' || $special_attention != '')
$body .= "
Please:
";
if($telephoned != '')
$body .= $telephoned."\n";
if($came_to_see_you != '')
$body .= $came_to_see_you."\n";
if($wants_to_see_you != '')
$body .= $wants_to_see_you."\n";
if($returned_your_call != '')
$body .= $returned_your_call."\n";
if($please_call != '')
$body .= $please_call."\n";
if($will_call_again != '')
$body .= $will_call_again."\n";
if($rush != '')
$body .= $rush."\n";
if($special_attention != '')
$body .= $special_attention."\n";
$body .= "
$callers_message
$signed";
$subject = "Important Message From " . $name ." - ". $time;
//mail($for, $subject, $body, 'from: messages@atlanticbiomedical.com');
mail($for, $subject, $body, "from: $reply_to");
header('Location: /messages/index.php');
?>
<body onload="window.close();"></body>

125
html/messages2/index.inc Executable file
View File

@ -0,0 +1,125 @@
<link href="style.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="autotab.js"></script>
<script src="scriptaculous/lib/prototype.js" type="text/javascript"></script>
<script src="scriptaculous/src/effects.js" type="text/javascript"></script>
<script type="text/javascript" src="validation.js"></script>
<form method="post" action="formmail.php" id="test">
<fieldset>
<label for="for">For </label>
<select name="for" class="half">
<option value="jaking17@gmail.com">Jason King</option>
<option value="haskinsj87@gmail.com">Jacob Haskins</option>
<option value="arwolcott@gmail.com">Allison Wolcott</option>
<option value="caendres1@gmail.com">Carl Endres</option>
<option value="caendres@gmail.com">Chris Endres</option>
<option value="kcwashburn1@gmail.com">Kate Washburn</option>
</select>
<div class="form-row">
<label for="name" class="name">Name </label>
<input type="text" name="name" id="name" class="validate-name half" />
<div class="form-row-ff"></div>
</div>
<div class="form-row">
<label for="company">Company </label>
<input type="text" name="company" class="validate-company" />
<div class="form-row-ff"></div>
</div>
<div class="form-row"><span id="bug">
<label for="phone">Phone </label>
<input type="text" name="phone" onKeyUp="return autoTab(this, 3, event);" maxlength="3" size="3" class="validate-phone phone" />
<input type="text" name="phone-2" onKeyUp="return autoTab(this, 3, event);" maxlength="3" size="3" class="validate-phone phone" />
<input type="text" name="phone-3" onKeyUp="return autoTab(this, 4, event);" maxlength="4" size="4" class="validate-phone phone3" />
<label for="ext" class="ext">ext. </label>
<input type="text" name="ext" size="4" class="phone" />
<label for="time_to_call" class="time">Time To Call</label>
<input type="text" name="time_to_call" class="phone" /></span>
</div>
<span style="display:inline-block"><label for="mobile">Mobile </label>
<input type="text" name="mobile" onKeyUp="return autoTab(this, 3, event);" maxlength="3" size="3" class="phone" />
<input type="text" name="mobile-2" onKeyUp="return autoTab(this, 3, event);" maxlength="3" size="3" class="phone" />
<input type="text" name="mobile-3" onKeyUp="return autoTab(this, 4, event);" maxlength="4" size="4" class="phone3" />
<label for="time_to_call_mobile" class="time2">Time To Call</label>
<input type="text" name="time_to_call_mobile" class="phone" /></span>
<span style="display:inline-block"><label for="fax">Fax </label>
<input type="text" name="fax" onKeyUp="return autoTab(this, 3, event);" maxlength="3" size="3" class="phone" />
<input type="text" name="fax-2" onKeyUp="return autoTab(this, 3, event);" maxlength="3" size="3" class="phone" />
<input type="text" name="fax-3" onKeyUp="return autoTab(this, 4, event);" maxlength="4" size="4" class="phone3" /></span>
<span style="display:inline-block"><div id="checkboxes">
<label for="telephoned" class="row1_label">Telephoned </label>
<input type="checkbox" name="telephoned" />
<label for="came_to_see_you" class="row2_label">Came To See You </label>
<input type="checkbox" name="came_to_see_you" />
<label for="wants_to_see_you" class="row3_label">Wants To See You </label>
<input type="checkbox" name="wants_to_see_you" />
<label for="returned_your_call" class="row1_label">Returned Your Call </label>
<input type="checkbox" name="returned_your_call" />
<label for="please_call" class="row2_label">Please Call </label>
<input type="checkbox" name="please_call" />
<label for="will_call_again" class="row3_label">Will Call Again </label>
<input type="checkbox" name="will_call_again" />
<label for="rush" class="row1_label">Rush </label>
<input type="checkbox" name="rush" />
<label for="special_attention" class="row2_label">Special Attention </label>
<input type="checkbox" name="special_attention" />
</div></span>
<div class="form-row">
<label for="callers_message" id="message">Message </label>
<textarea name="callers_message" cols="10" rows="10" class="validate-message"></textarea>
<div class="form-row-ff"></div>
</div>
<input type="submit" value="Submit Message" class="button" />
<div class="form-row">
<label for="signed" id="signed">Signed </label>
<select name="signed" class="validate-sign">
<option></option>
<option value="Allison">Allison</option>
<option value="Chris">Chris</option>
<option value="Kate">Kate</option>
</select>
<div class="form-row-ff"></div>
</div>
</fieldset>
</form>
<script type="text/javascript">
var valid = new Validation('test', {immediate : true});
Validation.addAllThese([
['validate-name', 'A name is required.', function(v){
return !Validation.get('IsEmpty').test(v);
}],
['validate-company', 'A company is required.', function(v){
return !Validation.get('IsEmpty').test(v);
}],
['validate-phone', 'A phone number is required.', function(v){
return !Validation.get('IsEmpty').test(v);
}],
['validate-message', 'A message is required.', function(v){
return !Validation.get('IsEmpty').test(v);
}],
['validate-sign', 'Please sign this message.', function(v){
return !Validation.get('IsEmpty').test(v);
}]
]);
</script>

196
html/messages2/index.php Executable file
View File

@ -0,0 +1,196 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="title" content="Atlantic Biomedical" />
<meta name="robots" content="index, follow" />
<meta name="description" content="Atlantic Biomedical" />
<meta name="keywords" content="Atlantic Biomedical, medical, equipment, repair" />
<meta name="language" content="en" />
<title>Atlantic Biomedical</title>
<link rel="shortcut icon" href="/favicon.ico" />
<script type="text/javascript" src="/sf/prototype/js/prototype.js"></script>
<script type="text/javascript" src="/sf/calendar/calendar.js"></script>
<script type="text/javascript" src="/sf/calendar/lang/calendar-en.js"></script>
<script type="text/javascript" src="/sf/calendar/calendar-setup.js"></script>
<link href="style.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="autotab.js"></script>
<script src="scriptaculous/lib/prototype.js" type="text/javascript"></script>
<script src="scriptaculous/src/effects.js" type="text/javascript"></script>
<script type="text/javascript" src="validation.js"></script>
<link rel="stylesheet" type="text/css" media="screen" href="/css/main.css" />
<link rel="stylesheet" type="text/css" media="screen" href="/css/client.css" />
<link rel="stylesheet" type="text/css" media="screen" href="/css/user.css" />
<link rel="stylesheet" type="text/css" media="screen" href="/css/theme.css" />
<link rel="stylesheet" type="text/css" media="screen" href="/sf/calendar/skins/aqua/theme.css" />
</head>
<body>
<div class="header">
<div class="logo_wrapper">
<div class="logo">
<img src="/images/logo.png" alt="Logo" /> </div>
</div>
<div class="menu">
<div class="menuCommands">
<a href="/index.php/scheduler">Scheduler</a>&nbsp;&nbsp;|&nbsp;&nbsp;
<a href="/index.php/workOrder">Workorders</a>&nbsp;&nbsp;|&nbsp;&nbsp;
<a href="/index.php/maps">Maps</a>&nbsp;&nbsp;|&nbsp;&nbsp;
<a href="/index.php/clientManager">Clients</a>&nbsp;&nbsp;|&nbsp;&nbsp;
<a href="/index.php/userManager">Users</a>&nbsp;&nbsp;|&nbsp;&nbsp;
<a href="http://<?php echo $_SERVER['HTTP_HOST']; ?>/messages/index.php">Messages</a>&nbsp;&nbsp;|&nbsp;&nbsp;
<a href="http://www.accella.net/bugs/index.php">Support</a>&nbsp;&nbsp;|&nbsp;&nbsp;
<a href="/index.php/security/logout">Logout</a> </div>
</div>
</div>
<div id="main">
<center>
<br/>
<form method="post" action="formmail.php" id="test">
<fieldset>
<label for="for">For </label>
<select name="for" class="half">
<option value="arwolcott@gmail.com">Allison Wolcott</option>
<option value="caendres1@gmail.com">Carl Endres</option>
<option value="caendres@gmail.com" selected="selected">Chris Endres</option>
<option value="kcwashburn1@gmail.com">Kate Washburn</option>
</select>
<div class="form-row">
<label for="name" class="name">Name </label>
<input type="text" name="name" id="name" class="validate-name half" />
<div class="form-row-ff"></div>
</div>
<div class="form-row">
<label for="company">Company </label>
<input type="text" name="company" class="validate-company" />
<div class="form-row-ff"></div>
</div>
<div class="form-row"><span id="bug">
<label for="phone">Phone </label>
<input type="text" name="phone" onKeyUp="return autoTab(this, 3, event);" maxlength="3" size="3" class="validate-phone phone" />
<input type="text" name="phone-2" onKeyUp="return autoTab(this, 3, event);" maxlength="3" size="3" class="validate-phone phone" />
<input type="text" name="phone-3" onKeyUp="return autoTab(this, 4, event);" maxlength="4" size="4" class="validate-phone phone3" />
<label for="ext" class="ext">ext. </label>
<input type="text" name="ext" size="4" class="phone" />
<label for="time_to_call" class="time">Time To Call</label>
<input type="text" name="time_to_call" class="phone" /></span>
</div>
<span style="display:inline-block"><label for="mobile">Mobile </label>
<input type="text" name="mobile" onKeyUp="return autoTab(this, 3, event);" maxlength="3" size="3" class="phone" />
<input type="text" name="mobile-2" onKeyUp="return autoTab(this, 3, event);" maxlength="3" size="3" class="phone" />
<input type="text" name="mobile-3" onKeyUp="return autoTab(this, 4, event);" maxlength="4" size="4" class="phone3" />
<label for="time_to_call_mobile" class="time2">Time To Call</label>
<input type="text" name="time_to_call_mobile" class="phone" /></span>
<span style="display:inline-block"><label for="fax">Fax </label>
<input type="text" name="fax" onKeyUp="return autoTab(this, 3, event);" maxlength="3" size="3" class="phone" />
<input type="text" name="fax-2" onKeyUp="return autoTab(this, 3, event);" maxlength="3" size="3" class="phone" />
<input type="text" name="fax-3" onKeyUp="return autoTab(this, 4, event);" maxlength="4" size="4" class="phone3" /></span>
<span style="display:inline-block"><div id="checkboxes">
<label for="telephoned" class="row1_label">Telephoned </label>
<input type="checkbox" name="telephoned" />
<label for="came_to_see_you" class="row2_label">Came To See You </label>
<input type="checkbox" name="came_to_see_you" />
<label for="wants_to_see_you" class="row3_label">Wants To See You </label>
<input type="checkbox" name="wants_to_see_you" />
<label for="returned_your_call" class="row1_label">Returned Your Call </label>
<input type="checkbox" name="returned_your_call" />
<label for="please_call" class="row2_label">Please Call </label>
<input type="checkbox" name="please_call" />
<label for="will_call_again" class="row3_label">Will Call Again </label>
<input type="checkbox" name="will_call_again" />
<label for="rush" class="row1_label">Rush </label>
<input type="checkbox" name="rush" />
<label for="special_attention" class="row2_label">Special Attention </label>
<input type="checkbox" name="special_attention" />
</div></span>
<div class="form-row">
<label for="callers_message" id="message">Message </label>
<textarea name="callers_message" cols="10" rows="10" class="validate-message"></textarea>
<div class="form-row-ff"></div>
</div>
<input type="submit" value="Submit Message" class="button" />
<div class="form-row">
<label for="signed" id="signed">Signed </label>
<select name="signed" class="validate-sign">
<option></option>
<option value="Allison||arwolcott@gmail.com">Allison</option>
<option value="Chris||caendres@gmail.com">Chris</option>
<option value="Kate||kcwashburn1@gmail.com">Kate</option>
</select>
<div class="form-row-ff"></div>
</div>
</fieldset>
</form>
<script type="text/javascript">
var valid = new Validation('test', {immediate : true});
Validation.addAllThese([
['validate-name', 'A name is required.', function(v){
return !Validation.get('IsEmpty').test(v);
}],
['validate-company', 'A company is required.', function(v){
return !Validation.get('IsEmpty').test(v);
}],
['validate-phone', 'A phone number is required.', function(v){
return !Validation.get('IsEmpty').test(v);
}],
['validate-message', 'A message is required.', function(v){
return !Validation.get('IsEmpty').test(v);
}],
['validate-sign', 'Please sign this message.', function(v){
return !Validation.get('IsEmpty').test(v);
}]
]);
</script>
</center><br/>
</div>
<!-- </div> -->
<div class="footer">
<a href="/index.php/">Dashboard</a>&nbsp;&nbsp;|&nbsp;&nbsp;
<a href="/index.php/scheduler">Scheduler</a>&nbsp;&nbsp;|&nbsp;&nbsp;
<a href="/index.php/workOrder">Workorders</a>&nbsp;&nbsp;|&nbsp;&nbsp;
<a href="/index.php/maps">Maps</a>&nbsp;&nbsp;|&nbsp;&nbsp;
<a href="/index.php/clientManager">Clients</a>&nbsp;&nbsp;|&nbsp;&nbsp;
<a href="/index.php/userManager">Users</a>&nbsp;&nbsp;<br />
<a href="/index.php/faq">FAQs</a>&nbsp;&nbsp;|&nbsp;&nbsp;
<a href="/index.php/support">Support</a>&nbsp;&nbsp;<br />
&copy; Copyright Atlantic Biomedical 2007
</div>
</body>
</html>

133
html/messages2/index_old.html Executable file
View File

@ -0,0 +1,133 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled Document</title>
<link href="style.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="autotab.js"></script>
<script src="scriptaculous/lib/prototype.js" type="text/javascript"></script>
<script src="scriptaculous/src/effects.js" type="text/javascript"></script>
<script type="text/javascript" src="validation.js"></script>
</head>
<body>
<form method="post" action="formmail.php" id="test">
<fieldset>
<label for="for">For </label>
<select name="for" class="half">
<option value="arwolcott@gmail.com">Allison Wolcott</option>
<option value="caendres1@gmail.com">Carl Endres</option>
<option value="caendres@gmail.com">Chris Endres</option>
<option value="kcwashburn1@gmail.com">Kate Washburn</option>
</select>
<div class="form-row">
<label for="name" class="name">Name </label>
<input type="text" name="name" id="name" class="validate-name half" />
<div class="form-row-ff"></div>
</div>
<div class="form-row">
<label for="company">Company </label>
<input type="text" name="company" class="validate-company" />
<div class="form-row-ff"></div>
</div>
<div class="form-row"><span id="bug">
<label for="phone">Phone </label>
<input type="text" name="phone" onKeyUp="return autoTab(this, 3, event);" maxlength="3" size="3" class="validate-phone phone" />
<input type="text" name="phone-2" onKeyUp="return autoTab(this, 3, event);" maxlength="3" size="3" class="validate-phone phone" />
<input type="text" name="phone-3" onKeyUp="return autoTab(this, 4, event);" maxlength="4" size="4" class="validate-phone phone3" />
<label for="ext" class="ext">ext. </label>
<input type="text" name="ext" size="4" class="phone" />
<label for="time_to_call" class="time">Time To Call</label>
<input type="text" name="time_to_call" class="phone" /></span>
</div>
<span style="display:inline-block"><label for="mobile">Mobile </label>
<input type="text" name="mobile" onKeyUp="return autoTab(this, 3, event);" maxlength="3" size="3" class="phone" />
<input type="text" name="mobile-2" onKeyUp="return autoTab(this, 3, event);" maxlength="3" size="3" class="phone" />
<input type="text" name="mobile-3" onKeyUp="return autoTab(this, 4, event);" maxlength="4" size="4" class="phone3" />
<label for="time_to_call_mobile" class="time2">Time To Call</label>
<input type="text" name="time_to_call_mobile" class="phone" /></span>
<span style="display:inline-block"><label for="fax">Fax </label>
<input type="text" name="fax" onKeyUp="return autoTab(this, 3, event);" maxlength="3" size="3" class="phone" />
<input type="text" name="fax-2" onKeyUp="return autoTab(this, 3, event);" maxlength="3" size="3" class="phone" />
<input type="text" name="fax-3" onKeyUp="return autoTab(this, 4, event);" maxlength="4" size="4" class="phone3" /></span>
<span style="display:inline-block"><div id="checkboxes">
<label for="telephoned" class="row1_label">Telephoned </label>
<input type="checkbox" name="telephoned" />
<label for="came_to_see_you" class="row2_label">Came To See You </label>
<input type="checkbox" name="came_to_see_you" />
<label for="wants_to_see_you" class="row3_label">Wants To See You </label>
<input type="checkbox" name="wants_to_see_you" />
<label for="returned_your_call" class="row1_label">Returned Your Call </label>
<input type="checkbox" name="returned_your_call" />
<label for="please_call" class="row2_label">Please Call </label>
<input type="checkbox" name="please_call" />
<label for="will_call_again" class="row3_label">Will Call Again </label>
<input type="checkbox" name="will_call_again" />
<label for="rush" class="row1_label">Rush </label>
<input type="checkbox" name="rush" />
<label for="special_attention" class="row2_label">Special Attention </label>
<input type="checkbox" name="special_attention" />
</div></span>
<div class="form-row">
<label for="callers_message" id="message">Message </label>
<textarea name="callers_message" cols="10" rows="10" class="validate-message"></textarea>
<div class="form-row-ff"></div>
</div>
<input type="submit" value="Submit Message" class="button" />
<div class="form-row">
<label for="signed" id="signed">Signed </label>
<select name="signed" class="validate-sign">
<option></option>
<option value="Allison">Allison</option>
<option value="Chris">Chris</option>
<option value="Kate">Kate</option>
</select>
<div class="form-row-ff"></div>
</div>
</fieldset>
</form>
<script type="text/javascript">
var valid = new Validation('test', {immediate : true});
Validation.addAllThese([
['validate-name', 'A name is required.', function(v){
return !Validation.get('IsEmpty').test(v);
}],
['validate-company', 'A company is required.', function(v){
return !Validation.get('IsEmpty').test(v);
}],
['validate-phone', 'A phone number is required.', function(v){
return !Validation.get('IsEmpty').test(v);
}],
['validate-message', 'A message is required.', function(v){
return !Validation.get('IsEmpty').test(v);
}],
['validate-sign', 'Please sign this message.', function(v){
return !Validation.get('IsEmpty').test(v);
}]
]);
</script>
</body>
</html>

View File

@ -0,0 +1,962 @@
*V1.7.0 beta 2* (December 18, 2006)
* Change the default setting for effects to support up to 60fps, if renderable by the browser. Add performance info to effects unit test.
* Change get/setOpacity to use Prototype's new support for cross-browser opacity.
* Update to Prototype 1.5.0_rc2 revision [5741], which fixes some of the reported issues with beta 1 (see Prototype's CHANGELOG for more):
* Opera 9, while not officially supported, should work now with Prototype and script.aculo.us
* Fixes issue with Safari when using Prototype's Ajax helpers with HTTP authorization
* Add hash and CSS className support to Effect.Morph, fixes #6674 [Tobie]
Examples:
$(element).morph('myClass')
// will morph to all the properties specified
// in .className (in your external stylesheet).
// All properties which cannot be morphed (such as font-style)
// will be applied AfterFinish
$(element).morph('font-size: 10px') // or
$(element).morph({fontSize: '10px'}) // will morph the font-size to 10px
*V1.7.0 beta 1* (November 21, 2006)
* Add Element.morph() and Element.Methods.morph() as a shortcut to Effect.Morph
Example:
// basic Effect.Morph
$('error_message').morph('color:#f00;font-size:17px');
// fade out after a while
$('error_message').show().morph('font-size:17px').morph('opacity:0',{delay:4});
* Update to Prototype 1.5.0_rc2 revision [5580]
* Add a paramName option to the inplace editor for overriding the default parameter name of "value"
* Add Effect.Transform that generates parallel executing Effect.Morph sets
Example:
// set up transformation
var transformation = new Effect.Transform([
{ 'div.morphing': 'font-size:20px;padding-left:40em' },
{ 'blah' : 'width:480px;border-width:10px;border-right-width:20px;margin:200px;margin-bottom:-20px;font-size:30px' }
],{ duration: 0.5 });
// play transformation (can be called more than once)
transformation.play();
* Add Effect.Morph core effect that morphs to a given CSS style rule. Effect.Morph does take orginal styles given by CSS style rules or the style attribute into consideration when calculating the transforms. It works with all length and color based CSS properties, including margins, paddings, borders, opacity and text/background colors.
Example:
new Effect.Morph('mydiv',{
style: 'font-size:3em;color:#f00;border-width:2em',
duration: 2.0
});
*V1.6.5* (November 8, 2006)
* Update to Prototype 1.5.0_rc1 revision [5462]
* Support the HTML 'for' attribute in Builder by using 'htmlFor', fixes #6472 [gjones, tdd]
var node = Builder.node('label', { htmlFor: 'myinput' });
* Add support to run a specific failing unit test by clicking on the corresponding test result, fixes #6290 [leeo]
* Add modifier key support to Event.simulateMouse, fixes #6391 [savetheclocktower]
* Add rails-trunk update task, clean up references to MIT license
* Add new 'with-last' queue position option to queue effects to occur in parallel with the last effect to start in the queue
* Add new special core effect Effect.Event for one-shot events that follow timelines defined by effect queues
new Effect.Event({ afterFinish:function(){
// do some code here
}, position: 'end' });
* Do some refactoring to make use of Prototype 1.5 functionalities and save LOC
* Fix an possible crash of IE on Effect.SlideUp, fixes #3192 [thx nel]
* Add Builder.build() to create nodes from strings containing HTML, [DHH]
var node = Builder.build("<p>this is <b>neat!</b></p>");
* Add a pulses parameter to Effect.Pulsate to control the amount of pulses, fixes #6245 [leeo]
For example, Effect.Pulsate('d8', {pulses: 2}) would pulsate twice. If the option is not given, it defaults to five pulses.
* Fix an issue with clicking on a slider span resulting in an exception, fixes #4707 [thx sergeykojin]
* Fix an issue with Draggables when no options are supplied, fixes #6045 [thx tdd]
*V1.6.4* (September 6, 2006)
* Hotfix IE issues with patched Prototype V1.5.0_rc1
*V1.6.3* (September 5, 2006)
* Update Prototype to V1.5.0_rc1
* Merge assertElementsMatch and assertElementMatches from Prototype's [4986] unittest.js [Sam Stephenson]
* Update Prototype to revision [4930]
* Fix various issues with IE detection and Opera, and setOpacity, fixes #3886, #5973
* Make Sortable.serialize handle DOM IDs like "some_element_1" correctly, fixes #5324
* Add assertRespondsTo and shouldRespondTo assertions
* Add experimental alternate syntax for unit tests (Behaviour Driven Development-style)
* Add support for onStart, onDrag and onEnd events directly on Draggables (invoked from the Draggables.notify), fixes #4747 [thx scriptkitchen]
* Add element shortcuts to Builder that can be activated by calling Builder.dump() (see the unit test), fixes #4260 [thx napalm]
* Fix selection of correct option in SELECT element generated by InPlaceCollectionEditor for indexed option arrays, fixes #4789 [thx steve]
* Add autoSelect option to Autocompleters to auto select an entry if only one is returned, fixes #5183 [thx cassiano dandrea]
* Added delay option to Draggables and Sortables, see test/functional/dragdrop_delay_test.html for usage, implements #3325 [thx lsimon, tomg]
* Remove revert cache code obsoleted by #4706, fixes #3436 (again) [thx tomg]
* Fix autoscrolling inside scrollable containers when window is scrolled too, fixes #5200 [thx wseitz]
* Make Effect.Puff work correctly for floating elements, fixes #3777 [thx michael hartl]
* Add version and timestamp to indvidual library files for easier identification (the files are preprocessed by the Rake fresh_scriptaculous task), fixes #3015 [thx Tobie]
* Add assertIndentical and assertNotIdentical unit test assertions, which test for equality and common type, fixes #5822 [thx glazedginger]
* Add integration test for Ajax autocompleter for results with no linebreaks, #4149
* Fix an issue with redrawing ghosted draggables that are inside a scrolled container, fixes #3860 [thx gkupps, tsukue]
* Added a custom exception to all base effects when used on non-existing DOM elements, added a assertRaise method to unit tests
* Fix autoscrolling when dragging an element unto a scrollable container, fixes #5017 [thx tomg]
* Fix a condition where overriding the endeffect on Draggables without overriding the starteffect too leads to a Javascript error [thx Javier Martinez]
* Fix a possible error with the drag/drop logic (affects the solution to #4706)
*V1.6.2*
* Fix a problem in the drag and drop logic if an reverting/drag ending draggable was initialized for a new drag (for example by clicking repeatedly) for all cases where the default start/revert/end-effects are used, fixes #4706 [thx tecM0]
* Fix possible memory leaks with Draggables, fixes #3436 [thx aal]
* Throw nicer errors when requires script.aculo.us libraries are not loaded, fixes #5339
* Make slider handles work when not displayed initially by using CSS width/height, fixes #4011 [thx foysavas]
* Update sortable functional test with onUpdate counter
* Make more Element extensions unit tests work on Safari
* Add the assertMatch unit test assertion for asserts with RegExps [thx Ian Tyndall]
* Fix a problem with Effect.Move causing "jumping" elements because of very low float numbers in some situations
* Fix a missing semicolon in dragdrop.js, fixes #5569 [thx mackalicious]
* Fix a slight inaccuracy with Effect.Scale that could lead the scaling to be one pixel off
* Be more prototypish with Effect.Transitions.linear
* Make Effect.Scale recognize font sizes that use the pt unit, fixes #4136 [thx aljoscha]
* Fix IE hack in Effect.Opacity, fixes #5444 [thx nicholas]
* Fix IFRAME layout fix for IE and Autocompleter, fixes #5192 [thx tommy skaue]
* Fix only option in onEmptyHover, fiex #5348 [thx glenn nilsson]
* Fix Effect.BlindDown and SwitchOff handling of supplied callbacks, fixes #5089 [thx martinstrom]
* Fix a problem with field focus on Ajax.InPlaceEditor and loading external text, fixes #4988, #5244 [thx rob]
* Do not attempt to scroll if scrollspeed is 0/0, fixes #5035 [thx tomg]
* Fix a problem with Sortable Tree serialization, fixes #4939, #4688, #4767 [thx Sammi Williams]
* Fix an endless loop with sliders, fixes #3226, #4051, #4765 [thx jeff]
* Make autocompleter work with update DIVs that have scrollbars, fixes #4782 [thx Tommy Skaue]
* Corrected options parsing on switchoff effect, fixes #4710 [thx haldini]
*V1.6.1*
* Update to Prototype 1.5.0_rc0
* Add Draggable object as third parameter to snap, fixes #4074 [thx mdaines]
* Fix an IE flicker with SlideUp/SlideDown, fixes #3774, [thx sbbowers]
* Add parsing/setting of any currently set opacity CSS rule to default opacity effect on draggables, fixes #3682 [thx Mike A. Owens]
* Added prototype $() performance patch from #4477 and updated effects.js to new Element.addMethods() syntax
* Sortable trees [thx Sammi Williams, sammi@oriontransfer.co.nz]
- Added functional test (test/functional/sortable_tree_test.html)
- removed greedy option
- modified the way Droppables.show works - added affected list
- added Droppables.findDeepestChild
- modified Sortable.options to work for trees
- modified Sortable.onEmptyHover with additional logic to insert
the element at a certain place according to the overlap
- modified Sortable.onHover to avoid DOM Exceptions
- modified Sortable.create to support the creation of Sortable trees
- added two convenience functions - Sortable.findElements and
Sortable.findTreeElements
- Added Sortable.tree (and a number of private functions to facilitate it)
Returns a tree structure:
var root = {
id: null,
parent: null,
children: <children>,
container: <sortable element>,
}
var child = {
parent: <node>,
children: <array>,
id: <string> (as per options.format),
element: <element>,
container: <element>,
position: <integer>
}
This is intended to become part of the public API, and can be used to manipulate
the tree programatically.
- Modified Sortable.serialize to use Sortable.tree when set in the options.
* Fix a problem with window scrolling on draggables [thx Gregory Hill]
* Let the benchmark method return the time taken in ms, so it can be used for time-based assertions
* Fix problem with id-based handle names and draggables
* More Element.childrenWithClassName optimization
* Added benchmark method to unittest.js; some cleaning up of unit tests
* Add fix for IE memory leaks in included prototype.js from [4094]
*V1.6.0*
* Major speedup for sortable with handles initialization [thx Jamis Buck]
* Update to latest Prototype 1.5.0_pre1 trunk
* Add functional "random effects" test, also for browser compatibility testing
* Fix two typos introduced with the 1.5 Methods syntax update
* Add functional test for $$-triggered effects with .visualEffect
* Fix shift-tab for autocompleter in Safari, fixes #4423 [thx matt]
* Prepare for script.aculo.us 1.6, add Prototype 1.5 requirement and check that Element.Methods is available in the scriptaculous loader
* Refactor effects.js to use the new Prototype 1.5 Element Methods syntax
* Update to latest Prototype 1.5.0_pre0 trunk
* Fix a problem with the draggable window scrolling code and scrolling inside overflow containers
* Add passing through of scroll options from Sortable to Draggable [thx Gregory Hill]
* Make it possible to scroll window on dragging, #3921 [thx rdmiller]
* Make Element.forceRerendering give up on any exception (this fixes various problems with IE)
* added visualEffect method for the Element Mixin, fixed so you can chain multiple calls. [Rick Olson]
* Fix only option on Sortable.create to accept multiple class names, fixes #3427 [thx glenn nilsson]
* Added workaround for a rendering bug in Safari when using floating elements with Effect.Appear
* Update lib/prototype.js to Prototype 1.5.0_pre0
*V1.5.3*
* Change version number to V1.5.3, prepare Rakefile
* Remove unneeded height restoring in Effect.BlindDown as that is handled internally by the restoreAfterFinish option to Effect.Scale, fixes #3667 [thx Ross Lawley]
* Added Ajax.InPlaceCollectionEditor which uses a SELECT element instead of a text field (see test/functional/ajax_inplacecollectioneditor_test.html for usage), #3491 [thx anna]
* Enable in place editor to use RJS (implements a new evalScripts option for the in place editor), #3490 [thx Richard Livsey]
* Added Sortable.setSequence to programmatically reorder a Sortable, #3711 [thx Mike A. Owens]
* Added unit test for #3732 (currently fails due to Prototype #3877) [thx michal]
* Fix span positioning for sliders with ranges not starting at 0, fixes #3731 [thx michal]
* Make name option on Sortable.serialize work again, fixes #3873
* Make dragging cancel only on ESC key, not on any key, fixes #3817
* Fix Rakefile for V1.5.2
*V1.5.2*
* Change version number to V1.5.2
* Fix a wrong parameter in dragdrop.js, fixes #3555
* Fix two typos in effects.js, fixes #3481 [thx jtolds]
* Add assertEnumEqual for unit testing (from Prototype SVN trunk) [Sam Stephenson]
* Add Sortable.sequence method to extract the current sequence of a Sortable as an array, fixes #3675 [thx sphivo]
* Add limit option to effect queues to limit the maximum number of effects in a queue, new unit tests for scoped effect queues, fixes #3498 [thx Abdur-Rahman Advany]
* Fix Element.collectTextNodesIgnoreClass to correctly filter child nodes, fixes #3380 [thx lam]
* Fix a condition where OPTION elements could cause unwanted dragging on Draggables, fixes #3441 [thx tom]
* Fix a crash because of an IE bug in Effect.SlideDown, fixes #3192 [thx Rob Mayhew]
* Added experimental auto-scroll option to Draggables and Sortables, activate with scroll: 'id_of_scroll_container_element'.
Note: needs testing, call syntax might change
See test/functional/dragdrop3_test.html for usage/demo
* Added activate method to Autocompleter that allows you to trigger the suggestions through other means than user input [DHH]
*V1.5.1*
* Add select option to Autocompleter to optionally use textnodes from elements with a specific CSS class (see test/functional/ajax_autocompleter_test.html for usage)
* In-place editor: add ok/cancel visibility options and onblur() submission, fixes #3233 [thx pulsation]
Note: currently, blur form submission breaks the cancel link functionality, if enabled
* Added Effect.toggle for slide, blind and appear/fade effects, fixes #2704 [thx Azad]
* Added selective component loading to scriptaculous.js, see test/unit/loading_test.html for usage [thx David Z<>lke]
* Added local/scoped effect queues [thx David Z<>lke]
* New core effect Effect.Move that can do absolute/relative movement [thx David Z<>lke]
* Make default effects options modifyable globally by setting Effect.DefaultOptions
* Make Draggables recognize top/left CSS properties defined in an external stylesheet, fixes #3205 [thx ansonparker]
* Fixed draggables starting to drag even if mouse button was released with no movement, [thx topfunky]
* Updated the README to reflect final status
*V1.5.0*
* Prepared for V1.5.0 final
* Update lib/prototype.js to Prototype 1.4.0 final
*V1.5.0_rc6*
* Update lib/prototype.js to Prototype 1.4.0_rc4
* Fix Effect.SlideDown/SlideUp on Internet Explorer, includes a change to Effect.Scale, (should) fix #2962 and others, [thx wyldeone]
* Make Draggables that are reverting cancel the default revert effect when they are dragged again while reverting, fixes #3188, [thx maverick]
* Fix a problem with a wrong reference in Effect.Pulsate, fixes #3184, [thx cyx_]
* Fix Sortable.findElements for XHTML in Gecko, fixes #3081, [thx fgnass]
* Fix a problem with the slider getting NaN results when clicking directly on the track, fixes #3020, [thx rectalogic]
* Fix a problem with Safari not doing sub-pixel rendering when setting opacity to 1 with Element.setOpacity
* Fix slider to make handle width/height count for track length, fixes #3040, fixes #3017, [thx buggedcom]
* Added Basic unit test for Effect.inspect
* Fix Effect.multiple to deal correctly with delays
* Safeguard Effect.Base.render to only do updates when Effect is in running state, fixes #2912
* Added inspect method to Effect.Base
* Added functional test for DOM-based UL sortables #3016
* Added offset option to Effect.ScrollTo
* More effects.js/dragdrop.js refactoring
* Refactoring and optimizations for effects (not complete yet)
* Refactoring and optimizations for Draggables/Droppables/Sortables (not complete yet)
*V1.5.0_rc5*
* Make Droppables.remove accept DOM IDs in addition to elements
* Added some unit tests for drag and drop
* Update lib/prototype.js to Prototype 1.4.0_rc3
* Make 'contents' a synonym for 'content' on Effect.Scale scaleMode option
* Fix some possible exceptions in slider.js
* Support for various snapping options on Draggables, adresses #2826, [thx saimonmoore]
* Support horizontal ghostable Sortables, fixes #2794, [thx johnm]
* Prevent an exception on IE with a functional test, see #2706
* Add functional testing of hoverclasses for sortables
* Add an assert for correct UTF-8 return chars in Autocompleter
* Correct IE detection in Autocompleter for Opera, fixes #2558 [thx gary]
* Add onDrag callback to Draggable observers, #2827 [thx saimonmoore]
* Added Form.Element.DelayedObserver to controls.js for live-search fields
* Remove Element.Class in favour of Prototype Element.ClassNames, new function Element.childrenWithClassName()
* Update Copyright notice in slider.js
* Fix slider firing onChange events to eagerly on dragging a handle [thx wombert]
* Fix a problem with Start/End spans and single handles
* Add event property to Slider object so that callbacks can determine if setValue originated from a UI event or from script
* Fix Builder.node() throwing unresolved errors in IE6, #2707 [thx flwombat]
* Give currently active handle on slider the "selected" CSS class
* Add start and end spans to slider
* Make track clickable for sliders (moves last active handle [or first handle] to nearest possible position)
* Make initial values on slider work for single and multiple handle sliders
*V1.5.0_rc4*
* Abort Effect.Highlight on elements which have display:none set (prevents problem with Safari)
* Make Effect.Queue an Enumerable, fix a problem with Effect.Grow, more unit tests
* Added restricted option to prevent moved of handles prior/after adjacent handles on Sliders with multiple handles
* Update lib/prototype.js to Prototype 1.4.0_rc2
* Fix a bug with wrongly scrolling to the page top in Ajax.InPlaceEditor (circumvents various browser bugs) [Jon Tirsen], #2616
* major slider refactoring, changed slider range to default to [0,1]. Slider Range can be set with range:$R(from,to) option. The increment option is not active for now.
* Added spans support for Control.Slider to mark spans bordered by slider handles, see unit test [thx to www.bartenbach.de for sponsoring this functionality]
* Added preliminary support for optional multiple handles to Control.Slider [thx to www.bartenbach.de for sponsoring this functionality]
* Fixed wrong inclusion of libs in inplace editor functional test
* Fixed Effect.SlideDown/SlideUp to honor refactoring of Effect.Scale, fixes #2523 [thx obiwanki]
* Reset the zIndex on Draggables correctly, #2483 [thx Jon Whitcraft]
* Fix onChange callback on Sortables when dragging between sortables, #2488 [thx Dylan Greene]
* Removed Builder code from effects.js, removed Object.debug (implemented as Test.Unit.inspect)
* Added slider unit tests, fixed handling of values to autocalculate min/max, fixed upper/lower boundaries on setting the value programmatically
* Synced to Rails 1.0 release candidate, update to Prototype 1.4.0_rc1, removed util.js, merged rests of util.js into effects.js to prepare for refactoring
* Give Builder it's own file
* Fix a logic issue with Autocompleter [thx tshinnic], #2457
*V1.5.0_rc3*
* Make Effect position available to callbacks
* Droppables.fire: send event to onDrop callback [Fran<61>ois Beausoleil], #2389
* InPlaceEditor: Add disabling the field while loadTextURL loads and add a class while loading, plus fix various bugs with Internet Explorer and InPlaceEditor, [Jon Tirsen] #2302, #2303
* Made Droppables.remove work again [thx Mindaugas Pelionis], #2409
* Fixed that IE6 would incorrectly render the "fix-windowed-elements-overlapping" IFRAME on autocompletion [thx tshinnic], #2403
* Fixed Element.getOpacity throwing an error on Safari in some situations (this caused the autocompleter not to work)
* Added format option to Sortable.create and Sortable.serialize to allow custom id formats. The format option takes a regular expression where the first grouping that matches is used for building the parameters. The default format is /^[^_]*_(.*)$/ which matches the string_identifier format. If you want to use the full id of the elements, use "format: /(.*)/". More examples are available in the sortable unit test file.
* Started refactorings to use the new Prototype features and general code-cleanup
* Update lib/prototype.js to Prototype 1.4.0_pre11
* Fixed a typo breaking the up arrow key for autocompletion [thx tshinnic], #2406
* Changed the handle option on Draggbles to accept classnames, or ids or elements [thx to Andrew West], #2274
* Force indicator to be hidden on hiding autocompletion update element, #2342
* Make Draggables honor external CSS positioning [thx to Mark Shawkey], #2359
* Make zindex handling for Draggables honor external CSS styles
* Fix two Sortable.serialize issues, [thx Avi, Gorou], #2339, #2357
* Make Element.getOpacity work with IE, added unit tests [thx to Greg Hill]
* Make Element.setOpacity honor non-alpha filters on IE (it now works with filters for alpha PNGs)
* Fixed that Element.class.remove wrongly deleted spaces between class names, fixes #2311, #2313
* Fixed Builder for OPTION and OPTGROUP tags on Firefox < 1.5 and Internet Explorer 6, completely fixes #2325
* Improved Builder implementation to deal with Firefox-specific requirements and innerHTML parsing, partly fixes #2325
*V1.5.0_rc2*
* Update lib/prototype.js to corrected Prototype 1.4.0_pre7 (fixed a problem with IE)
* Update lib/prototype.js to Prototype 1.4.0_pre7
* Reverted to patched version of Prototype 1.4.0_pre4 for the time being (getResponseHeader problem on Mozilla)
* Attempt to fix crashes in Safari 2.0.1, probably related to the event registering und unregistering in Draggables, possibly fixes #2310
* Update lib/prototype.js to Prototype 1.4.0_pre6
* Changed effects_test.html functional test to incoporate Firefox anti-flicker overflow:hidden CSS property
*V1.5.0_rc1*
* Prepared Rakefile and README for V1.5.0_rc1 release
* Droppables w/greedy and hoverclass are now reverted when dragged item is no longer over them, fixes #2184
* Let Effect.Highlight correctly parse IE colors, add String.prototype.parseColor() for this, fixes #2037
* Fix Effect.Highlight to restore background image only if there was one
* Made Effect.tagifyText work again on IE
* Added String.prototype.toArray because Strings aren't iterable on IE
* Fixed Element.getOpacity falsely returning 0 on IE
* Some cleaning up in util.js
* Cleaned up Effect.Opacity
* Removed useless line in Position.page
* Make scriptaculous.js work if a query strings are used when calling it
* Fixed typos in slider.js and the functional test
* Fixed a bug with Safari and the InPlaceEditor with form submission. Add support for interpreting simple <br>s into linebreaks. [Jon Tirsen]
* New Control.Slider() for horizontal and vertical sliders [Marty Haught]
* Fixed autoapplying a 'layout' on IE with Effect.Opacity not working for elements given as id string
* Make Effect.Parallel render final frames and call beforeFinish/afterFinish on included effects
* Make Element.setOpacity work correctly again (browser-specific extensions, except for IE, are disabled at this time)
* Added focusing the text field or text area created when using Ajax.InPlaceEditor #2126 [thx to Lee Mallabone]
* Fixed Element.Class.childrenWith not returning the correct elements #2120 [cmees AT rogers DOT com]
* Added MIT-LICENSE header to scriptaculous.js, cut back on license info in other libs to keep files smaller
* Fix issues with form elements inside draggables not clickable with Firefox #2129
* Fixed an error in dragdrop.js with Draggables when no Droppables are defined
* Fixed an issue with Element.makePositioned causing Effect.SlideDown to fail on Safari
* Make effects "stateless" by cleaning up element.style after finish of effect #2133 [agr30 AT uni-koeln DOT de]
* Add "internal" events to effects, to make them more easily extendable [Martin Bialasinski]
* Set container element height to auto on finishing Effect.BlindDown und Effect.SlideDown #2123 [Tony Arnold]
* Fixed a weird char in dragdrop.js
* Controls.js Autocompleter.Base.updateElement() hook #2116 [Rob Wills]
* Refactoring to use the Prototype enumerable extensions
* Update to Prototype 1.4.0_pre4
*V1.5.0_pre4*
* Added a queue option to effects for easy stacking and simple timeline building. Valid values are "front", "end" and "parallel" (default), see for test/functional/effects_queue_test.html for usage
* Added a setup function to the core effects that gets called by Effect.Base when first entering into running state, which allows them to query the current state of an element or other page properties when queuing and/or delays are used
* Added a state instance variable to Effect.Base that indicates whether a effect that uses the queue is idle, running or finished
* Fixed a flicker with Effect.Puff
* General code cleaning to get rid of (legitimate) Mozilla strict javascript warnings
* Changes to assertVisible in unittest.js
* Slight refactoring of Effect.Text, now known as Effect.multiple(), change first parameter to also accept an array of strings or elements, or a NodeList of elements (if a single element or a string is given, defaults to $('element').childNodes)
* Made tagifyText work with IE. defaults to a style of "position: relative; zoom:1;" for the created SPAN wrappers. It also replaces spaces with non-breakable spaces. These sit-ups are required to work around problems with rendering elements with the proprietary IE "layout" and non-quirksmode documents.
* Add a break to scriptaculous.js when the includes are done [thx to Danilo Celic]
* Fixed a problem with the Autocompleter when hitting ESC would select the entry in IE and redisplay the entries box in Safari
* Fixed that the onDrop callback on Droppables didn't receive the dopped element as second parameter
* Make check for correct Prototype version on loading script.aculo.us
* Changed implementation of Builder to an innerHTML-based approach to make it work with IE6 (note: removed special "style" handling for now)
* Changed non-sync Effects to use a common setInterval call for better timing and page update speeds. See the new Effect.Queue object.
* Fixed a problem with setting opacity in Effect.Opacity to very small values
* Changed the implemention of Effect.Base to use setInterval
* Set version number to 1.5_pre4_trunk
* Added experimental Effect.Text function that allows to start delayed text effects, see test/functional/texteffects_test.html.
* Added experimental Effect.tagifyText(element) which wraps an elements text nodes characters in relatively positioned span elements
* Added "delay" option to Effect.Base to start an effect only after a specified delay
* Finetuning unittest.js + even more unit tests
* Added support for Firefox and Konqueror automatic unit testing on Linux [Michael Schuerig]
* Added basic unit test files for Effects, updated unit testing tests
* Fix typo in lib/prototype.js fix in R2069 (whoops)
* Added unit test for Position.clone
* Made the Postition.cumulative override recognize KHTML and AppleWebKit
* Fix the "hide form controls" iframe fix on the Autocompleter on Internet Explorer
*V1.5.0_pre3*
* More positioning fixes, expanded Element.clone [thx to Michael Schuerig]
* Fixed some JavaScript warnings about redeclared vars [Courtenay]
* Fixed a problem with autocompleting update divs not correctly positioned inside positioned elements [thx to Jonathan Feinberg]
* Workaround for a Safari bug on absolutely positioned children of the BODY element
* Added test/run_functional_test.html to more easily find your way around in the functional tests
* Fixed some missing var declarations in effects.js
* Support for automatic unit testing on IE/Win [Jon Tirsen]
* Added loading the text for the Ajax.InPlaceEditor from the server, more CSS support [Richard Livsey, Jon Tirsen]
* Made builder_test.html unit test work with Safari, fixed (one of two) caching issues with javascripttest.rb, added ajax_autocompleter_test.html to Rakefile unittests
* Fixed Element.Class getting false matches on class names like classA-foobar, added unit tests [Martin Bialasinski]
* Added a test to evluate the Fade/Appear effects across browsers and elements (test/functional/effects6_test.html)
* Framework for completely self-running in-browser unit tests on Mac OS X (try "rake unittest") [Jon Tirsen]
* Updates to Ajax.InPlaceEditor (Highlighting, Ajax options, more) [Jon Tirsen]
* Made event registering on Draggables happen per drag for improved performance [thx to Cathy]
* Moved Element.collectTextNodesIgnoreClass to util.js (preparation for refactoring)
* Made sortable onChange option work again
* Fixed a bug with Sortables resulting in wrong result when using Sortable.serialize with onUpdate on ghostly Sortables [thx Richard Livsey, Caleb Buxton]
* Changed version number in scriptaculous.js to 1.5_pre3
* Moved setting focus in Autocompleter to updateElement function to make it overridable [Brian Palmer]
* Added special handling for style attributes to Builder [Michael Schuerig]
* Changed opacity=1.0 check back to be inline with its original (pre 1.5) implementation to prevent flickering in Firefox < 1.1 on opacity-based effects (this also fixes flickering with drag-and-drop, sortable lists and autocompleting text fields). Note that this potentially breaks correct colors in some situations. [thx to David Z<>lke]
* Automatically deactivate browser built-in autocompletion on autocompleting textfields, fixes part of Rails #1824.
* Fixed a problem with Ajax.InPlaceEditor causing a JavaScript exception on Safari [thx to Patrick Lenz]
*V1.5.0_pre2*
* Fixed a weird character in dragdrop.js, added check to allow empty containers on Sortables (useful with dropOnEmpty option) [thx to Dave Strus]
* Added unit test runner file test/run_unit_tests.html, new unit test files must be listed in test/unit/index.html
* Added unit tests for Prototype string functions
*V1.5.0_pre1*
* Prepared README for V1.5.0_pre1
* Added a main scriptaculous.js file to load in the other libraries transparently:
<script src="path/to/prototype.js" type="text/javascript"></script>
<script src="path/to/scriptaculous.js" type="text/javascript"></script>
in the HEAD section of an HTML file is now all that's needed to include all of the script.aculo.us libraries,
given that they all can be accessed by the same path as scriptaculous.js is.
* Fixed possible problem with greedy Droppables when using the dropOnEmpty option on Sortable.create
* Added new CSS/background color features to Ajax.InPlaceEditor [Jon Tirsen]
* Added unit test for Autocompleter, first Version
* Added Event.simulateKey/s to unittest.js. Note that due to a bug in Firefox this will only work with Firefox up to v1.0.4 (see https://bugzilla.mozilla.org/show_bug.cgi?id=289940)
* Fixed a condition where standard a href=xxx links wouldn't work in autocomplete results. These do now, the onclick event is not cancelled. [thx to Jasper Slits]
* Fix showing ghosting marker only on ghosting Sortables
* Some more Builder stuff, expanded builder unit tests
* Moved stuff that didn't belong into specific libs into util.js; util.js is now required for all script.aculo.us libs
* Corrected weirdness in unittest.js
* Added dropOnEmpty option to Sortables to allow dropping on empty lists (see test/functional/sortable3_test.html)
* Changed algoritm for drag/drop position setting
* Changed workaround for class attributes (fixes a Firefox 1.0 error) from klass to className to be more Javascriptesque [thx to Martin Bialasinski]
* Fixed a typo in ajax_inplaceeditor_test.html
* Updated Rakefile to add unittest.js and util.js to the package
* Added util.js which contains various utlity functions and extensions to Prototype
* Major restructuring
* Added TEXTAREA support to Ajax.InPlaceEditor [Sanford Barr]
* Added Ghost Train alpha 0.1.0. See ghosttrain/test.html.
* More features for Ajax.InPlaceEditor [Jon Tirsen]
* Tweaks to unittest.css [Thomas Fuchs]
* Refactoring and new features in unittest.js [Thomas Fuchs] [Jon Tirsen]
* Fixed a wrong variable reference in Effect.Scale
* Fix Element.makePositioned to recognize the 'static' position
* Allow to choose the parameter name for Ajax.Autocompleter [Cameron Braid]
* Changed resolving indicator DOM element more flexibility [Cameron Braid]
* Fixed a reference in Ajax.InPlaceEditor
* Added contributors to unittest.js
* Souped-up Ajax.InPlaceEditor, added support for a form id and specifying all the texts through options [Jon Tirsen]
* Make unit testing look good [Michael Schuerig]
* Changed default revert duration for Draggables to distance-dependent algorithm [suggested by San]
* Fix double unescaping in Autocompleter
* Refactoring auf Autocompleter classes to use camelCase (note: changes the syntax of some of the options)
* Add updateElement option to Autocompleter [Rob Sharp]
* Updated Ajax.InPlaceEditor, refactoring of unit testing [Jon Tirsen]
* Added preliminary version of Ajax.InPlaceEditor to controls.js; added experimental Firefox only functional testing for it (inplaceeditor_result.html) [Jon Tirsen]
* Added some addtional test files.
* Fixes a bug with Droppables not recognizing a drop if no hoverclass is given [thanks drewie]
* Fixes to ghosting marker, allow a predefined marker (element with id "dropmarker").
* Changed Effect.Opacity to better handle 100% opacity
* Various fixes to ghosting, improves compatiblity with Safari and IE. [thanks to David Z<>lke]
* Added experimental ghosting option to Sortables. See sortable_functional_ghosting.html for usage.
* Renamed the clone option on Draggables to "ghosting".
* Added experimental "clone" option to Draggable to so that a "clone" stays in place while dragging a translucent version of the draggable element. Currently, this requires relatively positioned elements, and doesn't work with sortable lists (but should after some tweaking). See dragdrop_function_4.html test file for details.
* Added Element.getStyle to find computed CSS styles of an element. Note: doesn't work in all cases in Safari, see my bug report at http://bugzilla.opendarwin.org/show_bug.cgi?id=4125
*1.1beta1*
* Fixed rendering of last frame of animation when from/to is not 0.0/1.0. [thanks to David Z<>lke]
* Updated internal Prototype JavaScript framework to version 1.4.0_pre2 (patched w/ workaround for Ajax.Updater init bug)
* Some refactoring of controls.js to get rid of "dirty" implementation detail (dont' ask)
* Added returning the generated combined effects to allow for .cancel() on all effects
* Updated internal Prototype JavaScript framework to version 1.4.0_pre2
*Rails 0.13.1*
* Updated Ajax.Autocompleter to deal with parameters options correctly [Martin Marinschek]
* Updated controls.js to allow multple matches in local localcompletion [Ivan Krstic]
* Make version of prototype.js in lib have a nicer Event object [David Z<>lke]
* Added incremental and local autocompleting and loads of documentation to controls.js [Ivan Krstic]
* Experimental: make version of prototype.js in lib destroy events on page unload to prevent browser memory leaks
* Fixed a possible memory leak in dragdrop.js
* Make version of prototype.js in lib compatible with some 3rd-party JavaScript libraries (like IE7) by refactoring to use Object.extend() for testing [David Z<>lke]
* Make effects.js, dragdrop.js and controls.js compatible with some 3rd-party JavaScript libraries (like IE7) by refactoring to use Object.extend() [David Z<>lke]
* Changed some tests to work better
* Always reset background color on Effect.Highlight; this make change backwards-compatibility, to be sure include style="background-color:(target-color)" on your elements or else elements will fall back to their CSS rules (which is a good thing in most circumstances)
* Removed a possible memory leaks with IE with sortables and droppables (removed references from elements)
* Changes to class extension in effects.js
* Make Effect.Highlight restore any previously set background color when finishing (makes effect work with set CSS classes)
* Added capability to remove draggables/droppables and redeclare sortables in dragdrop.js
* Added Effect.ScrollTo to smoothly scroll the page to an element
* Better Firefox flickering handling on SlideUp/SlideDown
* Some cleaning up in effects.js
* Removed a possible memory leak in IE with draggables
* Added support for cancelling dragging my hitting ESC
* Changed logic of drag-and-drop to only include the last referenced droppable when firing a drop event. This change also offers slight performance gains. [Dominik Wagner]
* Added addtional effects test page, added tests for scriptfragment matching
*1.0.0*
* Changed auto-hiding update div in Ajax.Autocompleter
* Changed default serialization on Ajax.Autocompleter to use Form.Element.serialize
* Added test file for drag/drop inside scrolled elements
* Fixed dragging of unpositioned elements in Internet Explorer
* Change default behaviour of Ajax.Autocompleter to do automatic overlapping, sizing and appear/fade effects
* Fixed Internet Explorer hide-windowed-controls iframe handling
* Changed Ajax.Autocompleter event handling
* Added onShow/onHide callbacks to Ajax.Autocompleter to allow for customized handling/effects
* Fixed SlideUp/SlideDown to restore the overflow CSS property (note: Firefox 1.0.X is buggy, set overflow:hidden as a workaround)
* Fixed BlindUp/BlindDown to restore the overflow CSS property (note: Firefox 1.0.X is buggy, set overflow:hidden as a workaround)
* Fixed draggables with revert:false on repeated drags behaving badly
* Expanded the revert option on draggables to optionally take a function and revert only if it returns true
* Added the dragged element as a parameter to the Draggables.notify callbacks [Michael Sokolov]
* Removed a deprecated reference to Effect2 om Effect.Fold
* Make the percentage on Element.setContentZoom absolute
* Corrected rendering of Ajax.AutoCompleter when focus is lost while updating
* Added (crude) functional tests
* Some slight refactoring in controls.js
* Changed dragdrop.js to use the Effect namespace for its effects
* Updated to Prototype 1.3.0: removal of prototype-ext.js; refactoring.
* Fixed behaviour of cursor keys in Safari on autocomplete script
* Fixed Position.within_including_scrolloffsets
* Fixed sortables that are absolutely positioned
* Fixed unhandled whitespace in Ajax.Autocompleter
* Updated prototype-ext.js to include additions for Ajax.Autocompleter
* Added controls.js, contains AJAX autocompleting text fields from #960
* Refactored Event object
* Renamed effects2.js to effects.js
* Fixed draggables on pages with no droppables
* Moved Event, Position and Element.Class to prototype-ext.js in preparation to Rails 0.13
* Added Effect.Transitions.pulse
* Added Effect.Pulsate and Effect.Fold effect by Justin Palmer
* Added transitions by Mark Pilgrim: .full, .none
* Added effects by Mark Pilgrim: Effect.Grow, Effect.Shrink
* Changed effects namespace to Effect. (Effect2 is deprecated, but works too)
* Changed old Effect.ContentZoom class to Element.setContentZoom() function
* Greatly expanded Effect.Highlight to have user-defined colors and autodetecting the background color
* Converted remaining effects (Squish, Highlight) to new format
* Sortable.create now passes the zindex, starteffect, reverteffect and endeffect options to the underlying Draggables
* Sortable.serialize now honors the only option on Sortable.create
* New overridable options on Draggables: zindex, starteffect, reverteffect, endeffect
* Fix a Gecko engine flicker on Sortables in dragdrop.js
* Fixed event.isLeftClick
* Some small changes in effects2.js
* Refactoring of dragdrop.js
* Added an Object.prototype.inspect() and more verbose messages for js unit testing
* Added test/unittest.js and initial tests in test/html.
* Cleaning up of effects2.js (convert tabs to spaces)
* Added Rakefile for distribution packaging (default task = make distribution, rake clean for cleaning up)
* Initial check-in and directory layout for the script.aculo.us JavaScripts

View File

@ -0,0 +1,20 @@
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.

View File

@ -0,0 +1,57 @@
== script.aculo.us web 2.0 javascript
The Web is changing. The 30-year-old terminal-like technology it was originally
is gradually giving way to new ways of doing things. The power of AJAX allows
for rich user interaction without the trouble that has bugged traditional
web applications.
Building upon the wonderful Prototype JavaScript library, script.aculo.us
provides you with some great additional ingredients to mix in.
For more information, see http://script.aculo.us/
== What's new in this release?
See the CHANGELOG file for information on what's new.
== Installation/Usage
script.aculo.us includes the Prototype JavaScript Framework
V1.5.0. You can use later versions, as they become available
(see http://prototype.conio.net).
Put prototype.js, and the six files scriptaculous.js,
builder.js, effects.js, dragdrop.js, controls.js and slider.js
in a directory of your website, e.g. /javascripts.
(The unittest.js file is optional and is only needed if you
want to do unit testing on your own javascripts).
Now, you can include the scripts by adding the following
tags to the HEAD section of your HTML pages:
<script src="/javascripts/prototype.js" type="text/javascript"></script>
<script src="/javascripts/scriptaculous.js" type="text/javascript"></script>
scriptaculous.js will automatically load the other files of the
script.aculo.us distribution in, provided they are accessible
via the same path.
See http://wiki.script.aculo.us/scriptaculous/show/Usage for detailed
usage instructions.
== The distribution
Besides the script.aculo.us files in src, there's a complete
test tree included which holds functional and unit tests for
script.aculo.us.
If you need examples on how to implement things, the best place to
start is by opening test/run_functional_tests.html or
test/run_unit_tests.html in your browser, and looking at
the sources of the examples provided.
== License
script.aculo.us is licensed under the terms of the MIT License,
see the included MIT-LICENSE file.

2426
html/messages2/scriptaculous/lib/prototype.js vendored Executable file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,131 @@
// script.aculo.us builder.js v1.7.0_beta2, Mon Dec 18 23:38:56 CET 2006
// Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
//
// 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/
var Builder = {
NODEMAP: {
AREA: 'map',
CAPTION: 'table',
COL: 'table',
COLGROUP: 'table',
LEGEND: 'fieldset',
OPTGROUP: 'select',
OPTION: 'select',
PARAM: 'object',
TBODY: 'table',
TD: 'table',
TFOOT: 'table',
TH: 'table',
THEAD: 'table',
TR: 'table'
},
// note: For Firefox < 1.5, OPTION and OPTGROUP tags are currently broken,
// due to a Firefox bug
node: function(elementName) {
elementName = elementName.toUpperCase();
// try innerHTML approach
var parentTag = this.NODEMAP[elementName] || 'div';
var parentElement = document.createElement(parentTag);
try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707
parentElement.innerHTML = "<" + elementName + "></" + elementName + ">";
} catch(e) {}
var element = parentElement.firstChild || null;
// see if browser added wrapping tags
if(element && (element.tagName != elementName))
element = element.getElementsByTagName(elementName)[0];
// fallback to createElement approach
if(!element) element = document.createElement(elementName);
// abort if nothing could be created
if(!element) return;
// attributes (or text)
if(arguments[1])
if(this._isStringOrNumber(arguments[1]) ||
(arguments[1] instanceof Array)) {
this._children(element, arguments[1]);
} else {
var attrs = this._attributes(arguments[1]);
if(attrs.length) {
try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707
parentElement.innerHTML = "<" +elementName + " " +
attrs + "></" + elementName + ">";
} catch(e) {}
element = parentElement.firstChild || null;
// workaround firefox 1.0.X bug
if(!element) {
element = document.createElement(elementName);
for(attr in arguments[1])
element[attr == 'class' ? 'className' : attr] = arguments[1][attr];
}
if(element.tagName != elementName)
element = parentElement.getElementsByTagName(elementName)[0];
}
}
// text, or array of children
if(arguments[2])
this._children(element, arguments[2]);
return element;
},
_text: function(text) {
return document.createTextNode(text);
},
ATTR_MAP: {
'className': 'class',
'htmlFor': 'for'
},
_attributes: function(attributes) {
var attrs = [];
for(attribute in attributes)
attrs.push((attribute in this.ATTR_MAP ? this.ATTR_MAP[attribute] : attribute) +
'="' + attributes[attribute].toString().escapeHTML() + '"');
return attrs.join(" ");
},
_children: function(element, children) {
if(typeof children=='object') { // array can hold nodes and text
children.flatten().each( function(e) {
if(typeof e=='object')
element.appendChild(e)
else
if(Builder._isStringOrNumber(e))
element.appendChild(Builder._text(e));
});
} else
if(Builder._isStringOrNumber(children))
element.appendChild(Builder._text(children));
},
_isStringOrNumber: function(param) {
return(typeof param=='string' || typeof param=='number');
},
build: function(html) {
var element = this.node('div');
$(element).update(html.strip());
return element.down();
},
dump: function(scope) {
if(typeof scope != 'object' && typeof scope != 'function') scope = window; //global scope
var tags = ("A ABBR ACRONYM ADDRESS APPLET AREA B BASE BASEFONT BDO BIG BLOCKQUOTE BODY " +
"BR BUTTON CAPTION CENTER CITE CODE COL COLGROUP DD DEL DFN DIR DIV DL DT EM FIELDSET " +
"FONT FORM FRAME FRAMESET H1 H2 H3 H4 H5 H6 HEAD HR HTML I IFRAME IMG INPUT INS ISINDEX "+
"KBD LABEL LEGEND LI LINK MAP MENU META NOFRAMES NOSCRIPT OBJECT OL OPTGROUP OPTION P "+
"PARAM PRE Q S SAMP SCRIPT SELECT SMALL SPAN STRIKE STRONG STYLE SUB SUP TABLE TBODY TD "+
"TEXTAREA TFOOT TH THEAD TITLE TR TT U UL VAR").split(/\s+/);
tags.each( function(tag){
scope[tag] = function() {
return Builder.node.apply(Builder, [tag].concat($A(arguments)));
}
});
}
}

835
html/messages2/scriptaculous/src/controls.js vendored Executable file
View File

@ -0,0 +1,835 @@
// script.aculo.us controls.js v1.7.0_beta2, Mon Dec 18 23:38:56 CET 2006
// 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));
}
};

944
html/messages2/scriptaculous/src/dragdrop.js vendored Executable file
View File

@ -0,0 +1,944 @@
// script.aculo.us dragdrop.js v1.7.0_beta2, Mon Dec 18 23:38:56 CET 2006
// Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
// (c) 2005, 2006 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz)
//
// 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/
if(typeof Effect == 'undefined')
throw("dragdrop.js requires including script.aculo.us' effects.js library");
var Droppables = {
drops: [],
remove: function(element) {
this.drops = this.drops.reject(function(d) { return d.element==$(element) });
},
add: function(element) {
element = $(element);
var options = Object.extend({
greedy: true,
hoverclass: null,
tree: false
}, arguments[1] || {});
// cache containers
if(options.containment) {
options._containers = [];
var containment = options.containment;
if((typeof containment == 'object') &&
(containment.constructor == Array)) {
containment.each( function(c) { options._containers.push($(c)) });
} else {
options._containers.push($(containment));
}
}
if(options.accept) options.accept = [options.accept].flatten();
Element.makePositioned(element); // fix IE
options.element = element;
this.drops.push(options);
},
findDeepestChild: function(drops) {
deepest = drops[0];
for (i = 1; i < drops.length; ++i)
if (Element.isParent(drops[i].element, deepest.element))
deepest = drops[i];
return deepest;
},
isContained: function(element, drop) {
var containmentNode;
if(drop.tree) {
containmentNode = element.treeNode;
} else {
containmentNode = element.parentNode;
}
return drop._containers.detect(function(c) { return containmentNode == c });
},
isAffected: function(point, element, drop) {
return (
(drop.element!=element) &&
((!drop._containers) ||
this.isContained(element, drop)) &&
((!drop.accept) ||
(Element.classNames(element).detect(
function(v) { return drop.accept.include(v) } ) )) &&
Position.within(drop.element, point[0], point[1]) );
},
deactivate: function(drop) {
if(drop.hoverclass)
Element.removeClassName(drop.element, drop.hoverclass);
this.last_active = null;
},
activate: function(drop) {
if(drop.hoverclass)
Element.addClassName(drop.element, drop.hoverclass);
this.last_active = drop;
},
show: function(point, element) {
if(!this.drops.length) return;
var affected = [];
if(this.last_active) this.deactivate(this.last_active);
this.drops.each( function(drop) {
if(Droppables.isAffected(point, element, drop))
affected.push(drop);
});
if(affected.length>0) {
drop = Droppables.findDeepestChild(affected);
Position.within(drop.element, point[0], point[1]);
if(drop.onHover)
drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element));
Droppables.activate(drop);
}
},
fire: function(event, element) {
if(!this.last_active) return;
Position.prepare();
if (this.isAffected([Event.pointerX(event), Event.pointerY(event)], element, this.last_active))
if (this.last_active.onDrop)
this.last_active.onDrop(element, this.last_active.element, event);
},
reset: function() {
if(this.last_active)
this.deactivate(this.last_active);
}
}
var Draggables = {
drags: [],
observers: [],
register: function(draggable) {
if(this.drags.length == 0) {
this.eventMouseUp = this.endDrag.bindAsEventListener(this);
this.eventMouseMove = this.updateDrag.bindAsEventListener(this);
this.eventKeypress = this.keyPress.bindAsEventListener(this);
Event.observe(document, "mouseup", this.eventMouseUp);
Event.observe(document, "mousemove", this.eventMouseMove);
Event.observe(document, "keypress", this.eventKeypress);
}
this.drags.push(draggable);
},
unregister: function(draggable) {
this.drags = this.drags.reject(function(d) { return d==draggable });
if(this.drags.length == 0) {
Event.stopObserving(document, "mouseup", this.eventMouseUp);
Event.stopObserving(document, "mousemove", this.eventMouseMove);
Event.stopObserving(document, "keypress", this.eventKeypress);
}
},
activate: function(draggable) {
if(draggable.options.delay) {
this._timeout = setTimeout(function() {
Draggables._timeout = null;
window.focus();
Draggables.activeDraggable = draggable;
}.bind(this), draggable.options.delay);
} else {
window.focus(); // allows keypress events if window isn't currently focused, fails for Safari
this.activeDraggable = draggable;
}
},
deactivate: function() {
this.activeDraggable = null;
},
updateDrag: function(event) {
if(!this.activeDraggable) return;
var pointer = [Event.pointerX(event), Event.pointerY(event)];
// Mozilla-based browsers fire successive mousemove events with
// the same coordinates, prevent needless redrawing (moz bug?)
if(this._lastPointer && (this._lastPointer.inspect() == pointer.inspect())) return;
this._lastPointer = pointer;
this.activeDraggable.updateDrag(event, pointer);
},
endDrag: function(event) {
if(this._timeout) {
clearTimeout(this._timeout);
this._timeout = null;
}
if(!this.activeDraggable) return;
this._lastPointer = null;
this.activeDraggable.endDrag(event);
this.activeDraggable = null;
},
keyPress: function(event) {
if(this.activeDraggable)
this.activeDraggable.keyPress(event);
},
addObserver: function(observer) {
this.observers.push(observer);
this._cacheObserverCallbacks();
},
removeObserver: function(element) { // element instead of observer fixes mem leaks
this.observers = this.observers.reject( function(o) { return o.element==element });
this._cacheObserverCallbacks();
},
notify: function(eventName, draggable, event) { // 'onStart', 'onEnd', 'onDrag'
if(this[eventName+'Count'] > 0)
this.observers.each( function(o) {
if(o[eventName]) o[eventName](eventName, draggable, event);
});
if(draggable.options[eventName]) draggable.options[eventName](draggable, event);
},
_cacheObserverCallbacks: function() {
['onStart','onEnd','onDrag'].each( function(eventName) {
Draggables[eventName+'Count'] = Draggables.observers.select(
function(o) { return o[eventName]; }
).length;
});
}
}
/*--------------------------------------------------------------------------*/
var Draggable = Class.create();
Draggable._dragging = {};
Draggable.prototype = {
initialize: function(element) {
var defaults = {
handle: false,
reverteffect: function(element, top_offset, left_offset) {
var dur = Math.sqrt(Math.abs(top_offset^2)+Math.abs(left_offset^2))*0.02;
new Effect.Move(element, { x: -left_offset, y: -top_offset, duration: dur,
queue: {scope:'_draggable', position:'end'}
});
},
endeffect: function(element) {
var toOpacity = typeof element._opacity == 'number' ? element._opacity : 1.0;
new Effect.Opacity(element, {duration:0.2, from:0.7, to:toOpacity,
queue: {scope:'_draggable', position:'end'},
afterFinish: function(){
Draggable._dragging[element] = false
}
});
},
zindex: 1000,
revert: false,
scroll: false,
scrollSensitivity: 20,
scrollSpeed: 15,
snap: false, // false, or xy or [x,y] or function(x,y){ return [x,y] }
delay: 0
};
if(!arguments[1] || typeof arguments[1].endeffect == 'undefined')
Object.extend(defaults, {
starteffect: function(element) {
element._opacity = Element.getOpacity(element);
Draggable._dragging[element] = true;
new Effect.Opacity(element, {duration:0.2, from:element._opacity, to:0.7});
}
});
var options = Object.extend(defaults, arguments[1] || {});
this.element = $(element);
if(options.handle && (typeof options.handle == 'string'))
this.handle = this.element.down('.'+options.handle, 0);
if(!this.handle) this.handle = $(options.handle);
if(!this.handle) this.handle = this.element;
if(options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML) {
options.scroll = $(options.scroll);
this._isScrollChild = Element.childOf(this.element, options.scroll);
}
Element.makePositioned(this.element); // fix IE
this.delta = this.currentDelta();
this.options = options;
this.dragging = false;
this.eventMouseDown = this.initDrag.bindAsEventListener(this);
Event.observe(this.handle, "mousedown", this.eventMouseDown);
Draggables.register(this);
},
destroy: function() {
Event.stopObserving(this.handle, "mousedown", this.eventMouseDown);
Draggables.unregister(this);
},
currentDelta: function() {
return([
parseInt(Element.getStyle(this.element,'left') || '0'),
parseInt(Element.getStyle(this.element,'top') || '0')]);
},
initDrag: function(event) {
if(typeof Draggable._dragging[this.element] != 'undefined' &&
Draggable._dragging[this.element]) return;
if(Event.isLeftClick(event)) {
// abort on form elements, fixes a Firefox issue
var src = Event.element(event);
if(src.tagName && (
src.tagName=='INPUT' ||
src.tagName=='SELECT' ||
src.tagName=='OPTION' ||
src.tagName=='BUTTON' ||
src.tagName=='TEXTAREA')) return;
var pointer = [Event.pointerX(event), Event.pointerY(event)];
var pos = Position.cumulativeOffset(this.element);
this.offset = [0,1].map( function(i) { return (pointer[i] - pos[i]) });
Draggables.activate(this);
Event.stop(event);
}
},
startDrag: function(event) {
this.dragging = true;
if(this.options.zindex) {
this.originalZ = parseInt(Element.getStyle(this.element,'z-index') || 0);
this.element.style.zIndex = this.options.zindex;
}
if(this.options.ghosting) {
this._clone = this.element.cloneNode(true);
Position.absolutize(this.element);
this.element.parentNode.insertBefore(this._clone, this.element);
}
if(this.options.scroll) {
if (this.options.scroll == window) {
var where = this._getWindowScroll(this.options.scroll);
this.originalScrollLeft = where.left;
this.originalScrollTop = where.top;
} else {
this.originalScrollLeft = this.options.scroll.scrollLeft;
this.originalScrollTop = this.options.scroll.scrollTop;
}
}
Draggables.notify('onStart', this, event);
if(this.options.starteffect) this.options.starteffect(this.element);
},
updateDrag: function(event, pointer) {
if(!this.dragging) this.startDrag(event);
Position.prepare();
Droppables.show(pointer, this.element);
Draggables.notify('onDrag', this, event);
this.draw(pointer);
if(this.options.change) this.options.change(this);
if(this.options.scroll) {
this.stopScrolling();
var p;
if (this.options.scroll == window) {
with(this._getWindowScroll(this.options.scroll)) { p = [ left, top, left+width, top+height ]; }
} else {
p = Position.page(this.options.scroll);
p[0] += this.options.scroll.scrollLeft + Position.deltaX;
p[1] += this.options.scroll.scrollTop + Position.deltaY;
p.push(p[0]+this.options.scroll.offsetWidth);
p.push(p[1]+this.options.scroll.offsetHeight);
}
var speed = [0,0];
if(pointer[0] < (p[0]+this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[0]+this.options.scrollSensitivity);
if(pointer[1] < (p[1]+this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[1]+this.options.scrollSensitivity);
if(pointer[0] > (p[2]-this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[2]-this.options.scrollSensitivity);
if(pointer[1] > (p[3]-this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[3]-this.options.scrollSensitivity);
this.startScrolling(speed);
}
// fix AppleWebKit rendering
if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);
Event.stop(event);
},
finishDrag: function(event, success) {
this.dragging = false;
if(this.options.ghosting) {
Position.relativize(this.element);
Element.remove(this._clone);
this._clone = null;
}
if(success) Droppables.fire(event, this.element);
Draggables.notify('onEnd', this, event);
var revert = this.options.revert;
if(revert && typeof revert == 'function') revert = revert(this.element);
var d = this.currentDelta();
if(revert && this.options.reverteffect) {
this.options.reverteffect(this.element,
d[1]-this.delta[1], d[0]-this.delta[0]);
} else {
this.delta = d;
}
if(this.options.zindex)
this.element.style.zIndex = this.originalZ;
if(this.options.endeffect)
this.options.endeffect(this.element);
Draggables.deactivate(this);
Droppables.reset();
},
keyPress: function(event) {
if(event.keyCode!=Event.KEY_ESC) return;
this.finishDrag(event, false);
Event.stop(event);
},
endDrag: function(event) {
if(!this.dragging) return;
this.stopScrolling();
this.finishDrag(event, true);
Event.stop(event);
},
draw: function(point) {
var pos = Position.cumulativeOffset(this.element);
if(this.options.ghosting) {
var r = Position.realOffset(this.element);
pos[0] += r[0] - Position.deltaX; pos[1] += r[1] - Position.deltaY;
}
var d = this.currentDelta();
pos[0] -= d[0]; pos[1] -= d[1];
if(this.options.scroll && (this.options.scroll != window && this._isScrollChild)) {
pos[0] -= this.options.scroll.scrollLeft-this.originalScrollLeft;
pos[1] -= this.options.scroll.scrollTop-this.originalScrollTop;
}
var p = [0,1].map(function(i){
return (point[i]-pos[i]-this.offset[i])
}.bind(this));
if(this.options.snap) {
if(typeof this.options.snap == 'function') {
p = this.options.snap(p[0],p[1],this);
} else {
if(this.options.snap instanceof Array) {
p = p.map( function(v, i) {
return Math.round(v/this.options.snap[i])*this.options.snap[i] }.bind(this))
} else {
p = p.map( function(v) {
return Math.round(v/this.options.snap)*this.options.snap }.bind(this))
}
}}
var style = this.element.style;
if((!this.options.constraint) || (this.options.constraint=='horizontal'))
style.left = p[0] + "px";
if((!this.options.constraint) || (this.options.constraint=='vertical'))
style.top = p[1] + "px";
if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering
},
stopScrolling: function() {
if(this.scrollInterval) {
clearInterval(this.scrollInterval);
this.scrollInterval = null;
Draggables._lastScrollPointer = null;
}
},
startScrolling: function(speed) {
if(!(speed[0] || speed[1])) return;
this.scrollSpeed = [speed[0]*this.options.scrollSpeed,speed[1]*this.options.scrollSpeed];
this.lastScrolled = new Date();
this.scrollInterval = setInterval(this.scroll.bind(this), 10);
},
scroll: function() {
var current = new Date();
var delta = current - this.lastScrolled;
this.lastScrolled = current;
if(this.options.scroll == window) {
with (this._getWindowScroll(this.options.scroll)) {
if (this.scrollSpeed[0] || this.scrollSpeed[1]) {
var d = delta / 1000;
this.options.scroll.scrollTo( left + d*this.scrollSpeed[0], top + d*this.scrollSpeed[1] );
}
}
} else {
this.options.scroll.scrollLeft += this.scrollSpeed[0] * delta / 1000;
this.options.scroll.scrollTop += this.scrollSpeed[1] * delta / 1000;
}
Position.prepare();
Droppables.show(Draggables._lastPointer, this.element);
Draggables.notify('onDrag', this);
if (this._isScrollChild) {
Draggables._lastScrollPointer = Draggables._lastScrollPointer || $A(Draggables._lastPointer);
Draggables._lastScrollPointer[0] += this.scrollSpeed[0] * delta / 1000;
Draggables._lastScrollPointer[1] += this.scrollSpeed[1] * delta / 1000;
if (Draggables._lastScrollPointer[0] < 0)
Draggables._lastScrollPointer[0] = 0;
if (Draggables._lastScrollPointer[1] < 0)
Draggables._lastScrollPointer[1] = 0;
this.draw(Draggables._lastScrollPointer);
}
if(this.options.change) this.options.change(this);
},
_getWindowScroll: function(w) {
var T, L, W, H;
with (w.document) {
if (w.document.documentElement && documentElement.scrollTop) {
T = documentElement.scrollTop;
L = documentElement.scrollLeft;
} else if (w.document.body) {
T = body.scrollTop;
L = body.scrollLeft;
}
if (w.innerWidth) {
W = w.innerWidth;
H = w.innerHeight;
} else if (w.document.documentElement && documentElement.clientWidth) {
W = documentElement.clientWidth;
H = documentElement.clientHeight;
} else {
W = body.offsetWidth;
H = body.offsetHeight
}
}
return { top: T, left: L, width: W, height: H };
}
}
/*--------------------------------------------------------------------------*/
var SortableObserver = Class.create();
SortableObserver.prototype = {
initialize: function(element, observer) {
this.element = $(element);
this.observer = observer;
this.lastValue = Sortable.serialize(this.element);
},
onStart: function() {
this.lastValue = Sortable.serialize(this.element);
},
onEnd: function() {
Sortable.unmark();
if(this.lastValue != Sortable.serialize(this.element))
this.observer(this.element)
}
}
var Sortable = {
SERIALIZE_RULE: /^[^_\-](?:[A-Za-z0-9\-\_]*)[_](.*)$/,
sortables: {},
_findRootElement: function(element) {
while (element.tagName != "BODY") {
if(element.id && Sortable.sortables[element.id]) return element;
element = element.parentNode;
}
},
options: function(element) {
element = Sortable._findRootElement($(element));
if(!element) return;
return Sortable.sortables[element.id];
},
destroy: function(element){
var s = Sortable.options(element);
if(s) {
Draggables.removeObserver(s.element);
s.droppables.each(function(d){ Droppables.remove(d) });
s.draggables.invoke('destroy');
delete Sortable.sortables[s.element.id];
}
},
create: function(element) {
element = $(element);
var options = Object.extend({
element: element,
tag: 'li', // assumes li children, override with tag: 'tagname'
dropOnEmpty: false,
tree: false,
treeTag: 'ul',
overlap: 'vertical', // one of 'vertical', 'horizontal'
constraint: 'vertical', // one of 'vertical', 'horizontal', false
containment: element, // also takes array of elements (or id's); or false
handle: false, // or a CSS class
only: false,
delay: 0,
hoverclass: null,
ghosting: false,
scroll: false,
scrollSensitivity: 20,
scrollSpeed: 15,
format: this.SERIALIZE_RULE,
onChange: Prototype.emptyFunction,
onUpdate: Prototype.emptyFunction
}, arguments[1] || {});
// clear any old sortable with same element
this.destroy(element);
// build options for the draggables
var options_for_draggable = {
revert: true,
scroll: options.scroll,
scrollSpeed: options.scrollSpeed,
scrollSensitivity: options.scrollSensitivity,
delay: options.delay,
ghosting: options.ghosting,
constraint: options.constraint,
handle: options.handle };
if(options.starteffect)
options_for_draggable.starteffect = options.starteffect;
if(options.reverteffect)
options_for_draggable.reverteffect = options.reverteffect;
else
if(options.ghosting) options_for_draggable.reverteffect = function(element) {
element.style.top = 0;
element.style.left = 0;
};
if(options.endeffect)
options_for_draggable.endeffect = options.endeffect;
if(options.zindex)
options_for_draggable.zindex = options.zindex;
// build options for the droppables
var options_for_droppable = {
overlap: options.overlap,
containment: options.containment,
tree: options.tree,
hoverclass: options.hoverclass,
onHover: Sortable.onHover
}
var options_for_tree = {
onHover: Sortable.onEmptyHover,
overlap: options.overlap,
containment: options.containment,
hoverclass: options.hoverclass
}
// fix for gecko engine
Element.cleanWhitespace(element);
options.draggables = [];
options.droppables = [];
// drop on empty handling
if(options.dropOnEmpty || options.tree) {
Droppables.add(element, options_for_tree);
options.droppables.push(element);
}
(this.findElements(element, options) || []).each( function(e) {
// handles are per-draggable
var handle = options.handle ?
$(e).down('.'+options.handle,0) : e;
options.draggables.push(
new Draggable(e, Object.extend(options_for_draggable, { handle: handle })));
Droppables.add(e, options_for_droppable);
if(options.tree) e.treeNode = element;
options.droppables.push(e);
});
if(options.tree) {
(Sortable.findTreeElements(element, options) || []).each( function(e) {
Droppables.add(e, options_for_tree);
e.treeNode = element;
options.droppables.push(e);
});
}
// keep reference
this.sortables[element.id] = options;
// for onupdate
Draggables.addObserver(new SortableObserver(element, options.onUpdate));
},
// return all suitable-for-sortable elements in a guaranteed order
findElements: function(element, options) {
return Element.findChildren(
element, options.only, options.tree ? true : false, options.tag);
},
findTreeElements: function(element, options) {
return Element.findChildren(
element, options.only, options.tree ? true : false, options.treeTag);
},
onHover: function(element, dropon, overlap) {
if(Element.isParent(dropon, element)) return;
if(overlap > .33 && overlap < .66 && Sortable.options(dropon).tree) {
return;
} else if(overlap>0.5) {
Sortable.mark(dropon, 'before');
if(dropon.previousSibling != element) {
var oldParentNode = element.parentNode;
element.style.visibility = "hidden"; // fix gecko rendering
dropon.parentNode.insertBefore(element, dropon);
if(dropon.parentNode!=oldParentNode)
Sortable.options(oldParentNode).onChange(element);
Sortable.options(dropon.parentNode).onChange(element);
}
} else {
Sortable.mark(dropon, 'after');
var nextElement = dropon.nextSibling || null;
if(nextElement != element) {
var oldParentNode = element.parentNode;
element.style.visibility = "hidden"; // fix gecko rendering
dropon.parentNode.insertBefore(element, nextElement);
if(dropon.parentNode!=oldParentNode)
Sortable.options(oldParentNode).onChange(element);
Sortable.options(dropon.parentNode).onChange(element);
}
}
},
onEmptyHover: function(element, dropon, overlap) {
var oldParentNode = element.parentNode;
var droponOptions = Sortable.options(dropon);
if(!Element.isParent(dropon, element)) {
var index;
var children = Sortable.findElements(dropon, {tag: droponOptions.tag, only: droponOptions.only});
var child = null;
if(children) {
var offset = Element.offsetSize(dropon, droponOptions.overlap) * (1.0 - overlap);
for (index = 0; index < children.length; index += 1) {
if (offset - Element.offsetSize (children[index], droponOptions.overlap) >= 0) {
offset -= Element.offsetSize (children[index], droponOptions.overlap);
} else if (offset - (Element.offsetSize (children[index], droponOptions.overlap) / 2) >= 0) {
child = index + 1 < children.length ? children[index + 1] : null;
break;
} else {
child = children[index];
break;
}
}
}
dropon.insertBefore(element, child);
Sortable.options(oldParentNode).onChange(element);
droponOptions.onChange(element);
}
},
unmark: function() {
if(Sortable._marker) Sortable._marker.hide();
},
mark: function(dropon, position) {
// mark on ghosting only
var sortable = Sortable.options(dropon.parentNode);
if(sortable && !sortable.ghosting) return;
if(!Sortable._marker) {
Sortable._marker =
($('dropmarker') || Element.extend(document.createElement('DIV'))).
hide().addClassName('dropmarker').setStyle({position:'absolute'});
document.getElementsByTagName("body").item(0).appendChild(Sortable._marker);
}
var offsets = Position.cumulativeOffset(dropon);
Sortable._marker.setStyle({left: offsets[0]+'px', top: offsets[1] + 'px'});
if(position=='after')
if(sortable.overlap == 'horizontal')
Sortable._marker.setStyle({left: (offsets[0]+dropon.clientWidth) + 'px'});
else
Sortable._marker.setStyle({top: (offsets[1]+dropon.clientHeight) + 'px'});
Sortable._marker.show();
},
_tree: function(element, options, parent) {
var children = Sortable.findElements(element, options) || [];
for (var i = 0; i < children.length; ++i) {
var match = children[i].id.match(options.format);
if (!match) continue;
var child = {
id: encodeURIComponent(match ? match[1] : null),
element: element,
parent: parent,
children: [],
position: parent.children.length,
container: $(children[i]).down(options.treeTag)
}
/* Get the element containing the children and recurse over it */
if (child.container)
this._tree(child.container, options, child)
parent.children.push (child);
}
return parent;
},
tree: function(element) {
element = $(element);
var sortableOptions = this.options(element);
var options = Object.extend({
tag: sortableOptions.tag,
treeTag: sortableOptions.treeTag,
only: sortableOptions.only,
name: element.id,
format: sortableOptions.format
}, arguments[1] || {});
var root = {
id: null,
parent: null,
children: [],
container: element,
position: 0
}
return Sortable._tree(element, options, root);
},
/* Construct a [i] index for a particular node */
_constructIndex: function(node) {
var index = '';
do {
if (node.id) index = '[' + node.position + ']' + index;
} while ((node = node.parent) != null);
return index;
},
sequence: function(element) {
element = $(element);
var options = Object.extend(this.options(element), arguments[1] || {});
return $(this.findElements(element, options) || []).map( function(item) {
return item.id.match(options.format) ? item.id.match(options.format)[1] : '';
});
},
setSequence: function(element, new_sequence) {
element = $(element);
var options = Object.extend(this.options(element), arguments[2] || {});
var nodeMap = {};
this.findElements(element, options).each( function(n) {
if (n.id.match(options.format))
nodeMap[n.id.match(options.format)[1]] = [n, n.parentNode];
n.parentNode.removeChild(n);
});
new_sequence.each(function(ident) {
var n = nodeMap[ident];
if (n) {
n[1].appendChild(n[0]);
delete nodeMap[ident];
}
});
},
serialize: function(element) {
element = $(element);
var options = Object.extend(Sortable.options(element), arguments[1] || {});
var name = encodeURIComponent(
(arguments[1] && arguments[1].name) ? arguments[1].name : element.id);
if (options.tree) {
return Sortable.tree(element, arguments[1]).children.map( function (item) {
return [name + Sortable._constructIndex(item) + "[id]=" +
encodeURIComponent(item.id)].concat(item.children.map(arguments.callee));
}).flatten().join('&');
} else {
return Sortable.sequence(element, arguments[1]).map( function(item) {
return name + "[]=" + encodeURIComponent(item);
}).join('&');
}
}
}
// Returns true if child is contained within element
Element.isParent = function(child, element) {
if (!child.parentNode || child == element) return false;
if (child.parentNode == element) return true;
return Element.isParent(child.parentNode, element);
}
Element.findChildren = function(element, only, recursive, tagName) {
if(!element.hasChildNodes()) return null;
tagName = tagName.toUpperCase();
if(only) only = [only].flatten();
var elements = [];
$A(element.childNodes).each( function(e) {
if(e.tagName && e.tagName.toUpperCase()==tagName &&
(!only || (Element.classNames(e).detect(function(v) { return only.include(v) }))))
elements.push(e);
if(recursive) {
var grandchildren = Element.findChildren(e, only, recursive, tagName);
if(grandchildren) elements.push(grandchildren);
}
});
return (elements.length>0 ? elements.flatten() : []);
}
Element.offsetSize = function (element, type) {
return element['offset' + ((type=='vertical' || type=='height') ? 'Height' : 'Width')];
}

1091
html/messages2/scriptaculous/src/effects.js vendored Executable file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,51 @@
// script.aculo.us scriptaculous.js v1.7.0_beta2, Mon Dec 18 23:38:56 CET 2006
// 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_beta2',
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();

View File

@ -0,0 +1,278 @@
// script.aculo.us slider.js v1.7.0_beta2, Mon Dec 18 23:38:56 CET 2006
// Copyright (c) 2005, 2006 Marty Haught, Thomas Fuchs
//
// 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/
if(!Control) var Control = {};
Control.Slider = Class.create();
// options:
// axis: 'vertical', or 'horizontal' (default)
//
// callbacks:
// onChange(value)
// onSlide(value)
Control.Slider.prototype = {
initialize: function(handle, track, options) {
var slider = this;
if(handle instanceof Array) {
this.handles = handle.collect( function(e) { return $(e) });
} else {
this.handles = [$(handle)];
}
this.track = $(track);
this.options = options || {};
this.axis = this.options.axis || 'horizontal';
this.increment = this.options.increment || 1;
this.step = parseInt(this.options.step || '1');
this.range = this.options.range || $R(0,1);
this.value = 0; // assure backwards compat
this.values = this.handles.map( function() { return 0 });
this.spans = this.options.spans ? this.options.spans.map(function(s){ return $(s) }) : false;
this.options.startSpan = $(this.options.startSpan || null);
this.options.endSpan = $(this.options.endSpan || null);
this.restricted = this.options.restricted || false;
this.maximum = this.options.maximum || this.range.end;
this.minimum = this.options.minimum || this.range.start;
// Will be used to align the handle onto the track, if necessary
this.alignX = parseInt(this.options.alignX || '0');
this.alignY = parseInt(this.options.alignY || '0');
this.trackLength = this.maximumOffset() - this.minimumOffset();
this.handleLength = this.isVertical() ?
(this.handles[0].offsetHeight != 0 ?
this.handles[0].offsetHeight : this.handles[0].style.height.replace(/px$/,"")) :
(this.handles[0].offsetWidth != 0 ? this.handles[0].offsetWidth :
this.handles[0].style.width.replace(/px$/,""));
this.active = false;
this.dragging = false;
this.disabled = false;
if(this.options.disabled) this.setDisabled();
// Allowed values array
this.allowedValues = this.options.values ? this.options.values.sortBy(Prototype.K) : false;
if(this.allowedValues) {
this.minimum = this.allowedValues.min();
this.maximum = this.allowedValues.max();
}
this.eventMouseDown = this.startDrag.bindAsEventListener(this);
this.eventMouseUp = this.endDrag.bindAsEventListener(this);
this.eventMouseMove = this.update.bindAsEventListener(this);
// Initialize handles in reverse (make sure first handle is active)
this.handles.each( function(h,i) {
i = slider.handles.length-1-i;
slider.setValue(parseFloat(
(slider.options.sliderValue instanceof Array ?
slider.options.sliderValue[i] : slider.options.sliderValue) ||
slider.range.start), i);
Element.makePositioned(h); // fix IE
Event.observe(h, "mousedown", slider.eventMouseDown);
});
Event.observe(this.track, "mousedown", this.eventMouseDown);
Event.observe(document, "mouseup", this.eventMouseUp);
Event.observe(document, "mousemove", this.eventMouseMove);
this.initialized = true;
},
dispose: function() {
var slider = this;
Event.stopObserving(this.track, "mousedown", this.eventMouseDown);
Event.stopObserving(document, "mouseup", this.eventMouseUp);
Event.stopObserving(document, "mousemove", this.eventMouseMove);
this.handles.each( function(h) {
Event.stopObserving(h, "mousedown", slider.eventMouseDown);
});
},
setDisabled: function(){
this.disabled = true;
},
setEnabled: function(){
this.disabled = false;
},
getNearestValue: function(value){
if(this.allowedValues){
if(value >= this.allowedValues.max()) return(this.allowedValues.max());
if(value <= this.allowedValues.min()) return(this.allowedValues.min());
var offset = Math.abs(this.allowedValues[0] - value);
var newValue = this.allowedValues[0];
this.allowedValues.each( function(v) {
var currentOffset = Math.abs(v - value);
if(currentOffset <= offset){
newValue = v;
offset = currentOffset;
}
});
return newValue;
}
if(value > this.range.end) return this.range.end;
if(value < this.range.start) return this.range.start;
return value;
},
setValue: function(sliderValue, handleIdx){
if(!this.active) {
this.activeHandleIdx = handleIdx || 0;
this.activeHandle = this.handles[this.activeHandleIdx];
this.updateStyles();
}
handleIdx = handleIdx || this.activeHandleIdx || 0;
if(this.initialized && this.restricted) {
if((handleIdx>0) && (sliderValue<this.values[handleIdx-1]))
sliderValue = this.values[handleIdx-1];
if((handleIdx < (this.handles.length-1)) && (sliderValue>this.values[handleIdx+1]))
sliderValue = this.values[handleIdx+1];
}
sliderValue = this.getNearestValue(sliderValue);
this.values[handleIdx] = sliderValue;
this.value = this.values[0]; // assure backwards compat
this.handles[handleIdx].style[this.isVertical() ? 'top' : 'left'] =
this.translateToPx(sliderValue);
this.drawSpans();
if(!this.dragging || !this.event) this.updateFinished();
},
setValueBy: function(delta, handleIdx) {
this.setValue(this.values[handleIdx || this.activeHandleIdx || 0] + delta,
handleIdx || this.activeHandleIdx || 0);
},
translateToPx: function(value) {
return Math.round(
((this.trackLength-this.handleLength)/(this.range.end-this.range.start)) *
(value - this.range.start)) + "px";
},
translateToValue: function(offset) {
return ((offset/(this.trackLength-this.handleLength) *
(this.range.end-this.range.start)) + this.range.start);
},
getRange: function(range) {
var v = this.values.sortBy(Prototype.K);
range = range || 0;
return $R(v[range],v[range+1]);
},
minimumOffset: function(){
return(this.isVertical() ? this.alignY : this.alignX);
},
maximumOffset: function(){
return(this.isVertical() ?
(this.track.offsetHeight != 0 ? this.track.offsetHeight :
this.track.style.height.replace(/px$/,"")) - this.alignY :
(this.track.offsetWidth != 0 ? this.track.offsetWidth :
this.track.style.width.replace(/px$/,"")) - this.alignY);
},
isVertical: function(){
return (this.axis == 'vertical');
},
drawSpans: function() {
var slider = this;
if(this.spans)
$R(0, this.spans.length-1).each(function(r) { slider.setSpan(slider.spans[r], slider.getRange(r)) });
if(this.options.startSpan)
this.setSpan(this.options.startSpan,
$R(0, this.values.length>1 ? this.getRange(0).min() : this.value ));
if(this.options.endSpan)
this.setSpan(this.options.endSpan,
$R(this.values.length>1 ? this.getRange(this.spans.length-1).max() : this.value, this.maximum));
},
setSpan: function(span, range) {
if(this.isVertical()) {
span.style.top = this.translateToPx(range.start);
span.style.height = this.translateToPx(range.end - range.start + this.range.start);
} else {
span.style.left = this.translateToPx(range.start);
span.style.width = this.translateToPx(range.end - range.start + this.range.start);
}
},
updateStyles: function() {
this.handles.each( function(h){ Element.removeClassName(h, 'selected') });
Element.addClassName(this.activeHandle, 'selected');
},
startDrag: function(event) {
if(Event.isLeftClick(event)) {
if(!this.disabled){
this.active = true;
var handle = Event.element(event);
var pointer = [Event.pointerX(event), Event.pointerY(event)];
var track = handle;
if(track==this.track) {
var offsets = Position.cumulativeOffset(this.track);
this.event = event;
this.setValue(this.translateToValue(
(this.isVertical() ? pointer[1]-offsets[1] : pointer[0]-offsets[0])-(this.handleLength/2)
));
var offsets = Position.cumulativeOffset(this.activeHandle);
this.offsetX = (pointer[0] - offsets[0]);
this.offsetY = (pointer[1] - offsets[1]);
} else {
// find the handle (prevents issues with Safari)
while((this.handles.indexOf(handle) == -1) && handle.parentNode)
handle = handle.parentNode;
if(this.handles.indexOf(handle)!=-1) {
this.activeHandle = handle;
this.activeHandleIdx = this.handles.indexOf(this.activeHandle);
this.updateStyles();
var offsets = Position.cumulativeOffset(this.activeHandle);
this.offsetX = (pointer[0] - offsets[0]);
this.offsetY = (pointer[1] - offsets[1]);
}
}
}
Event.stop(event);
}
},
update: function(event) {
if(this.active) {
if(!this.dragging) this.dragging = true;
this.draw(event);
// fix AppleWebKit rendering
if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);
Event.stop(event);
}
},
draw: function(event) {
var pointer = [Event.pointerX(event), Event.pointerY(event)];
var offsets = Position.cumulativeOffset(this.track);
pointer[0] -= this.offsetX + offsets[0];
pointer[1] -= this.offsetY + offsets[1];
this.event = event;
this.setValue(this.translateToValue( this.isVertical() ? pointer[1] : pointer[0] ));
if(this.initialized && this.options.onSlide)
this.options.onSlide(this.values.length>1 ? this.values : this.value, this);
},
endDrag: function(event) {
if(this.active && this.dragging) {
this.finishDrag(event, true);
Event.stop(event);
}
this.active = false;
this.dragging = false;
},
finishDrag: function(event, success) {
this.active = false;
this.dragging = false;
this.updateFinished();
},
updateFinished: function() {
if(this.initialized && this.options.onChange)
this.options.onChange(this.values.length>1 ? this.values : this.value, this);
this.event = null;
}
}

View File

@ -0,0 +1,564 @@
// script.aculo.us unittest.js v1.7.0_beta2, Mon Dec 18 23:38:56 CET 2006
// Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
// (c) 2005, 2006 Jon Tirsen (http://www.tirsen.com)
// (c) 2005, 2006 Michael Schuerig (http://www.schuerig.de/michael/)
//
// 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/
// experimental, Firefox-only
Event.simulateMouse = function(element, eventName) {
var options = Object.extend({
pointerX: 0,
pointerY: 0,
buttons: 0,
ctrlKey: false,
altKey: false,
shiftKey: false,
metaKey: false
}, arguments[2] || {});
var oEvent = document.createEvent("MouseEvents");
oEvent.initMouseEvent(eventName, true, true, document.defaultView,
options.buttons, options.pointerX, options.pointerY, options.pointerX, options.pointerY,
options.ctrlKey, options.altKey, options.shiftKey, options.metaKey, 0, $(element));
if(this.mark) Element.remove(this.mark);
this.mark = document.createElement('div');
this.mark.appendChild(document.createTextNode(" "));
document.body.appendChild(this.mark);
this.mark.style.position = 'absolute';
this.mark.style.top = options.pointerY + "px";
this.mark.style.left = options.pointerX + "px";
this.mark.style.width = "5px";
this.mark.style.height = "5px;";
this.mark.style.borderTop = "1px solid red;"
this.mark.style.borderLeft = "1px solid red;"
if(this.step)
alert('['+new Date().getTime().toString()+'] '+eventName+'/'+Test.Unit.inspect(options));
$(element).dispatchEvent(oEvent);
};
// Note: Due to a fix in Firefox 1.0.5/6 that probably fixed "too much", this doesn't work in 1.0.6 or DP2.
// You need to downgrade to 1.0.4 for now to get this working
// See https://bugzilla.mozilla.org/show_bug.cgi?id=289940 for the fix that fixed too much
Event.simulateKey = function(element, eventName) {
var options = Object.extend({
ctrlKey: false,
altKey: false,
shiftKey: false,
metaKey: false,
keyCode: 0,
charCode: 0
}, arguments[2] || {});
var oEvent = document.createEvent("KeyEvents");
oEvent.initKeyEvent(eventName, true, true, window,
options.ctrlKey, options.altKey, options.shiftKey, options.metaKey,
options.keyCode, options.charCode );
$(element).dispatchEvent(oEvent);
};
Event.simulateKeys = function(element, command) {
for(var i=0; i<command.length; i++) {
Event.simulateKey(element,'keypress',{charCode:command.charCodeAt(i)});
}
};
var Test = {}
Test.Unit = {};
// security exception workaround
Test.Unit.inspect = Object.inspect;
Test.Unit.Logger = Class.create();
Test.Unit.Logger.prototype = {
initialize: function(log) {
this.log = $(log);
if (this.log) {
this._createLogTable();
}
},
start: function(testName) {
if (!this.log) return;
this.testName = testName;
this.lastLogLine = document.createElement('tr');
this.statusCell = document.createElement('td');
this.nameCell = document.createElement('td');
this.nameCell.className = "nameCell";
this.nameCell.appendChild(document.createTextNode(testName));
this.messageCell = document.createElement('td');
this.lastLogLine.appendChild(this.statusCell);
this.lastLogLine.appendChild(this.nameCell);
this.lastLogLine.appendChild(this.messageCell);
this.loglines.appendChild(this.lastLogLine);
},
finish: function(status, summary) {
if (!this.log) return;
this.lastLogLine.className = status;
this.statusCell.innerHTML = status;
this.messageCell.innerHTML = this._toHTML(summary);
this.addLinksToResults();
},
message: function(message) {
if (!this.log) return;
this.messageCell.innerHTML = this._toHTML(message);
},
summary: function(summary) {
if (!this.log) return;
this.logsummary.innerHTML = this._toHTML(summary);
},
_createLogTable: function() {
this.log.innerHTML =
'<div id="logsummary"></div>' +
'<table id="logtable">' +
'<thead><tr><th>Status</th><th>Test</th><th>Message</th></tr></thead>' +
'<tbody id="loglines"></tbody>' +
'</table>';
this.logsummary = $('logsummary')
this.loglines = $('loglines');
},
_toHTML: function(txt) {
return txt.escapeHTML().replace(/\n/g,"<br/>");
},
addLinksToResults: function(){
$$("tr.failed .nameCell").each( function(td){ // todo: limit to children of this.log
td.title = "Run only this test"
Event.observe(td, 'click', function(){ window.location.search = "?tests=" + td.innerHTML;});
});
$$("tr.passed .nameCell").each( function(td){ // todo: limit to children of this.log
td.title = "Run all tests"
Event.observe(td, 'click', function(){ window.location.search = "";});
});
}
}
Test.Unit.Runner = Class.create();
Test.Unit.Runner.prototype = {
initialize: function(testcases) {
this.options = Object.extend({
testLog: 'testlog'
}, arguments[1] || {});
this.options.resultsURL = this.parseResultsURLQueryParameter();
this.options.tests = this.parseTestsQueryParameter();
if (this.options.testLog) {
this.options.testLog = $(this.options.testLog) || null;
}
if(this.options.tests) {
this.tests = [];
for(var i = 0; i < this.options.tests.length; i++) {
if(/^test/.test(this.options.tests[i])) {
this.tests.push(new Test.Unit.Testcase(this.options.tests[i], testcases[this.options.tests[i]], testcases["setup"], testcases["teardown"]));
}
}
} else {
if (this.options.test) {
this.tests = [new Test.Unit.Testcase(this.options.test, testcases[this.options.test], testcases["setup"], testcases["teardown"])];
} else {
this.tests = [];
for(var testcase in testcases) {
if(/^test/.test(testcase)) {
this.tests.push(
new Test.Unit.Testcase(
this.options.context ? ' -> ' + this.options.titles[testcase] : testcase,
testcases[testcase], testcases["setup"], testcases["teardown"]
));
}
}
}
}
this.currentTest = 0;
this.logger = new Test.Unit.Logger(this.options.testLog);
setTimeout(this.runTests.bind(this), 1000);
},
parseResultsURLQueryParameter: function() {
return window.location.search.parseQuery()["resultsURL"];
},
parseTestsQueryParameter: function(){
if (window.location.search.parseQuery()["tests"]){
return window.location.search.parseQuery()["tests"].split(',');
};
},
// Returns:
// "ERROR" if there was an error,
// "FAILURE" if there was a failure, or
// "SUCCESS" if there was neither
getResult: function() {
var hasFailure = false;
for(var i=0;i<this.tests.length;i++) {
if (this.tests[i].errors > 0) {
return "ERROR";
}
if (this.tests[i].failures > 0) {
hasFailure = true;
}
}
if (hasFailure) {
return "FAILURE";
} else {
return "SUCCESS";
}
},
postResults: function() {
if (this.options.resultsURL) {
new Ajax.Request(this.options.resultsURL,
{ method: 'get', parameters: 'result=' + this.getResult(), asynchronous: false });
}
},
runTests: function() {
var test = this.tests[this.currentTest];
if (!test) {
// finished!
this.postResults();
this.logger.summary(this.summary());
return;
}
if(!test.isWaiting) {
this.logger.start(test.name);
}
test.run();
if(test.isWaiting) {
this.logger.message("Waiting for " + test.timeToWait + "ms");
setTimeout(this.runTests.bind(this), test.timeToWait || 1000);
} else {
this.logger.finish(test.status(), test.summary());
this.currentTest++;
// tail recursive, hopefully the browser will skip the stackframe
this.runTests();
}
},
summary: function() {
var assertions = 0;
var failures = 0;
var errors = 0;
var messages = [];
for(var i=0;i<this.tests.length;i++) {
assertions += this.tests[i].assertions;
failures += this.tests[i].failures;
errors += this.tests[i].errors;
}
return (
(this.options.context ? this.options.context + ': ': '') +
this.tests.length + " tests, " +
assertions + " assertions, " +
failures + " failures, " +
errors + " errors");
}
}
Test.Unit.Assertions = Class.create();
Test.Unit.Assertions.prototype = {
initialize: function() {
this.assertions = 0;
this.failures = 0;
this.errors = 0;
this.messages = [];
},
summary: function() {
return (
this.assertions + " assertions, " +
this.failures + " failures, " +
this.errors + " errors" + "\n" +
this.messages.join("\n"));
},
pass: function() {
this.assertions++;
},
fail: function(message) {
this.failures++;
this.messages.push("Failure: " + message);
},
info: function(message) {
this.messages.push("Info: " + message);
},
error: function(error) {
this.errors++;
this.messages.push(error.name + ": "+ error.message + "(" + Test.Unit.inspect(error) +")");
},
status: function() {
if (this.failures > 0) return 'failed';
if (this.errors > 0) return 'error';
return 'passed';
},
assert: function(expression) {
var message = arguments[1] || 'assert: got "' + Test.Unit.inspect(expression) + '"';
try { expression ? this.pass() :
this.fail(message); }
catch(e) { this.error(e); }
},
assertEqual: function(expected, actual) {
var message = arguments[2] || "assertEqual";
try { (expected == actual) ? this.pass() :
this.fail(message + ': expected "' + Test.Unit.inspect(expected) +
'", actual "' + Test.Unit.inspect(actual) + '"'); }
catch(e) { this.error(e); }
},
assertInspect: function(expected, actual) {
var message = arguments[2] || "assertInspect";
try { (expected == actual.inspect()) ? this.pass() :
this.fail(message + ': expected "' + Test.Unit.inspect(expected) +
'", actual "' + Test.Unit.inspect(actual) + '"'); }
catch(e) { this.error(e); }
},
assertEnumEqual: function(expected, actual) {
var message = arguments[2] || "assertEnumEqual";
try { $A(expected).length == $A(actual).length &&
expected.zip(actual).all(function(pair) { return pair[0] == pair[1] }) ?
this.pass() : this.fail(message + ': expected ' + Test.Unit.inspect(expected) +
', actual ' + Test.Unit.inspect(actual)); }
catch(e) { this.error(e); }
},
assertNotEqual: function(expected, actual) {
var message = arguments[2] || "assertNotEqual";
try { (expected != actual) ? this.pass() :
this.fail(message + ': got "' + Test.Unit.inspect(actual) + '"'); }
catch(e) { this.error(e); }
},
assertIdentical: function(expected, actual) {
var message = arguments[2] || "assertIdentical";
try { (expected === actual) ? this.pass() :
this.fail(message + ': expected "' + Test.Unit.inspect(expected) +
'", actual "' + Test.Unit.inspect(actual) + '"'); }
catch(e) { this.error(e); }
},
assertNotIdentical: function(expected, actual) {
var message = arguments[2] || "assertNotIdentical";
try { !(expected === actual) ? this.pass() :
this.fail(message + ': expected "' + Test.Unit.inspect(expected) +
'", actual "' + Test.Unit.inspect(actual) + '"'); }
catch(e) { this.error(e); }
},
assertNull: function(obj) {
var message = arguments[1] || 'assertNull'
try { (obj==null) ? this.pass() :
this.fail(message + ': got "' + Test.Unit.inspect(obj) + '"'); }
catch(e) { this.error(e); }
},
assertMatch: function(expected, actual) {
var message = arguments[2] || 'assertMatch';
var regex = new RegExp(expected);
try { (regex.exec(actual)) ? this.pass() :
this.fail(message + ' : regex: "' + Test.Unit.inspect(expected) + ' did not match: ' + Test.Unit.inspect(actual) + '"'); }
catch(e) { this.error(e); }
},
assertHidden: function(element) {
var message = arguments[1] || 'assertHidden';
this.assertEqual("none", element.style.display, message);
},
assertNotNull: function(object) {
var message = arguments[1] || 'assertNotNull';
this.assert(object != null, message);
},
assertType: function(expected, actual) {
var message = arguments[2] || 'assertType';
try {
(actual.constructor == expected) ? this.pass() :
this.fail(message + ': expected "' + Test.Unit.inspect(expected) +
'", actual "' + (actual.constructor) + '"'); }
catch(e) { this.error(e); }
},
assertNotOfType: function(expected, actual) {
var message = arguments[2] || 'assertNotOfType';
try {
(actual.constructor != expected) ? this.pass() :
this.fail(message + ': expected "' + Test.Unit.inspect(expected) +
'", actual "' + (actual.constructor) + '"'); }
catch(e) { this.error(e); }
},
assertInstanceOf: function(expected, actual) {
var message = arguments[2] || 'assertInstanceOf';
try {
(actual instanceof expected) ? this.pass() :
this.fail(message + ": object was not an instance of the expected type"); }
catch(e) { this.error(e); }
},
assertNotInstanceOf: function(expected, actual) {
var message = arguments[2] || 'assertNotInstanceOf';
try {
!(actual instanceof expected) ? this.pass() :
this.fail(message + ": object was an instance of the not expected type"); }
catch(e) { this.error(e); }
},
assertRespondsTo: function(method, obj) {
var message = arguments[2] || 'assertRespondsTo';
try {
(obj[method] && typeof obj[method] == 'function') ? this.pass() :
this.fail(message + ": object doesn't respond to [" + method + "]"); }
catch(e) { this.error(e); }
},
assertReturnsTrue: function(method, obj) {
var message = arguments[2] || 'assertReturnsTrue';
try {
var m = obj[method];
if(!m) m = obj['is'+method.charAt(0).toUpperCase()+method.slice(1)];
m() ? this.pass() :
this.fail(message + ": method returned false"); }
catch(e) { this.error(e); }
},
assertReturnsFalse: function(method, obj) {
var message = arguments[2] || 'assertReturnsFalse';
try {
var m = obj[method];
if(!m) m = obj['is'+method.charAt(0).toUpperCase()+method.slice(1)];
!m() ? this.pass() :
this.fail(message + ": method returned true"); }
catch(e) { this.error(e); }
},
assertRaise: function(exceptionName, method) {
var message = arguments[2] || 'assertRaise';
try {
method();
this.fail(message + ": exception expected but none was raised"); }
catch(e) {
((exceptionName == null) || (e.name==exceptionName)) ? this.pass() : this.error(e);
}
},
assertElementsMatch: function() {
var expressions = $A(arguments), elements = $A(expressions.shift());
if (elements.length != expressions.length) {
this.fail('assertElementsMatch: size mismatch: ' + elements.length + ' elements, ' + expressions.length + ' expressions');
return false;
}
elements.zip(expressions).all(function(pair, index) {
var element = $(pair.first()), expression = pair.last();
if (element.match(expression)) return true;
this.fail('assertElementsMatch: (in index ' + index + ') expected ' + expression.inspect() + ' but got ' + element.inspect());
}.bind(this)) && this.pass();
},
assertElementMatches: function(element, expression) {
this.assertElementsMatch([element], expression);
},
benchmark: function(operation, iterations) {
var startAt = new Date();
(iterations || 1).times(operation);
var timeTaken = ((new Date())-startAt);
this.info((arguments[2] || 'Operation') + ' finished ' +
iterations + ' iterations in ' + (timeTaken/1000)+'s' );
return timeTaken;
},
_isVisible: function(element) {
element = $(element);
if(!element.parentNode) return true;
this.assertNotNull(element);
if(element.style && Element.getStyle(element, 'display') == 'none')
return false;
return this._isVisible(element.parentNode);
},
assertNotVisible: function(element) {
this.assert(!this._isVisible(element), Test.Unit.inspect(element) + " was not hidden and didn't have a hidden parent either. " + ("" || arguments[1]));
},
assertVisible: function(element) {
this.assert(this._isVisible(element), Test.Unit.inspect(element) + " was not visible. " + ("" || arguments[1]));
},
benchmark: function(operation, iterations) {
var startAt = new Date();
(iterations || 1).times(operation);
var timeTaken = ((new Date())-startAt);
this.info((arguments[2] || 'Operation') + ' finished ' +
iterations + ' iterations in ' + (timeTaken/1000)+'s' );
return timeTaken;
}
}
Test.Unit.Testcase = Class.create();
Object.extend(Object.extend(Test.Unit.Testcase.prototype, Test.Unit.Assertions.prototype), {
initialize: function(name, test, setup, teardown) {
Test.Unit.Assertions.prototype.initialize.bind(this)();
this.name = name;
if(typeof test == 'string') {
test = test.gsub(/(\.should[^\(]+\()/,'#{0}this,');
test = test.gsub(/(\.should[^\(]+)\(this,\)/,'#{1}(this)');
this.test = function() {
eval('with(this){'+test+'}');
}
} else {
this.test = test || function() {};
}
this.setup = setup || function() {};
this.teardown = teardown || function() {};
this.isWaiting = false;
this.timeToWait = 1000;
},
wait: function(time, nextPart) {
this.isWaiting = true;
this.test = nextPart;
this.timeToWait = time;
},
run: function() {
try {
try {
if (!this.isWaiting) this.setup.bind(this)();
this.isWaiting = false;
this.test.bind(this)();
} finally {
if(!this.isWaiting) {
this.teardown.bind(this)();
}
}
}
catch(e) { this.error(e); }
}
});
// *EXPERIMENTAL* BDD-style testing to please non-technical folk
// This draws many ideas from RSpec http://rspec.rubyforge.org/
Test.setupBDDExtensionMethods = function(){
var METHODMAP = {
shouldEqual: 'assertEqual',
shouldNotEqual: 'assertNotEqual',
shouldEqualEnum: 'assertEnumEqual',
shouldBeA: 'assertType',
shouldNotBeA: 'assertNotOfType',
shouldBeAn: 'assertType',
shouldNotBeAn: 'assertNotOfType',
shouldBeNull: 'assertNull',
shouldNotBeNull: 'assertNotNull',
shouldBe: 'assertReturnsTrue',
shouldNotBe: 'assertReturnsFalse',
shouldRespondTo: 'assertRespondsTo'
};
Test.BDDMethods = {};
for(m in METHODMAP) {
Test.BDDMethods[m] = eval(
'function(){'+
'var args = $A(arguments);'+
'var scope = args.shift();'+
'scope.'+METHODMAP[m]+'.apply(scope,(args || []).concat([this])); }');
}
[Array.prototype, String.prototype, Number.prototype].each(
function(p){ Object.extend(p, Test.BDDMethods) }
);
}
Test.context = function(name, spec, log){
Test.setupBDDExtensionMethods();
var compiledSpec = {};
var titles = {};
for(specName in spec) {
switch(specName){
case "setup":
case "teardown":
compiledSpec[specName] = spec[specName];
break;
default:
var testName = 'test'+specName.gsub(/\s+/,'-').camelize();
var body = spec[specName].toString().split('\n').slice(1);
if(/^\{/.test(body[0])) body = body.slice(1);
body.pop();
body = body.map(function(statement){
return statement.strip()
});
compiledSpec[testName] = body.join('\n');
titles[testName] = specName;
}
}
new Test.Unit.Runner(compiledSpec, { titles: titles, testLog: log || 'testlog', context: name });
};

174
html/messages2/style.css Executable file
View File

@ -0,0 +1,174 @@
fieldset {
width: 420px;
margin: 0 auto;
background: #f9b0a7;
padding: 5px;
padding-right: 0;
border: 2px ridge #212121;
padding-bottom: 15px;
}
h3 {
font: 18px "Trebuchet MS", Arial, Helvetica, sans-serif;
font-weight: bold;
text-transform: uppercase;
margin: 30px 0 30px 100px;
}
label {
width: 75px;
float: left;
font: 11px "Century Gothic", Arial, Helvetica, sans-serif;
text-transform: uppercase;
margin-top: 3px;
}
input {
float: left;
width: 335px;
margin-bottom: 5px;
}
.name {
width: 50px;
margin-left: 15px;
}
.half {
width: 135px;
}
select {
float: left;
}
.button {
float: left;
width: 150px;
margin-right: 5px;
}
.phone {
width: 30px;
float: left;
margin-right: 5px;
}
.phone3 {
width: 40px;
float: left;
margin-right: 5px;
}
.mobile {
width: 40px;
float: left;
margin-right: 35px;
}
.ext {
width: 30px;
margin-left: 5px;
}
.time {
width: 75px;
margin-left: 5px;
margin-right: 15px;
}
.time2 {
width: 75px;
margin-left: 81px;
margin-right: 15px;
}
* html .time2{ margin-left: 76px;}
:root .time2{ margin-left: 88px;}
:root .time {margin-left: 14px;}
textarea {
width: 330px;
height: 75px;
margin: 5px 7px 5px 0;
float: right;
}
#checkboxes {
float: left;
width: 400px;
background: #df9d8f;
padding: 5px;
border: 1px ridge #212121;
}
:root #checkboxes{ margin-bottom: 10px; }
.row1_label {
width: 110px;
margin-right: 0px;
font-size: 10px;
}
#checkboxes input {
width: 15px;
float: left;
margin-right: 0px;
margin-bottom: 5px;
}
.row2_label {
width: 100px;
margin-right: 0px;
margin-left: 10px;
font-size: 10px;
}
.row3_label {
width: 105px;
margin-right: 0px;
margin-left: 10px;
font-size: 10px;
}
.validation-advice {
position: absolute;
margin-top: 25px;
margin-left: -400px;
width: 200px;
padding: 5px;
background-color: #fff;
border: 1px ridge #212121;
font: 14px "Century Gothic", Arial, Helvetica, sans-serif;
font-weight: bold;
}
#advice-validate-message-callers_message{margin-left: -59px;}
#advice-validate-sign-signed{margin-top: -38px;}
#advice-validate-phone-phone{margin-left:-404px;}
#advice-validate-phone-phone-2{margin-left:-404px;}
#advice-validate-phone-phone-3{margin-left:-404px;}
:root #advice-validate-message-callers_message{margin-top: 190px; margin-left: 0px;}
:root #advice-validate-sign-signed{margin-top: -38px;}
:root #advice-validate-phone-phone{margin-left:0px;}
:root #advice-validate-phone-phone-2{margin-left:0px;}
:root #advice-validate-phone-phone-3{margin-left:0px;}
:root .validation-advice{ margin-left:0;}
#last {
margin-top: -45px;
margin-left: 241px;
}
#message{margin-top: 5px;}
#signed { margin-left: 120px;}
:root #signed {margin-left: 112px;}
:root #last{margin:3px 0 0 4px;}
:root .form-row-ff{clear:both;}
* html #bug{ display: inline-block;}
* html .ext{width: 25px;}

16
html/messages2/thankyou.html Executable file
View File

@ -0,0 +1,16 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled Document</title>
<style type="text/css">
#thanks{ width:420px;background: #f9b0a7 url(ab_logo_mods1_ff.jpg) no-repeat; margin: 0 auto;border: 2px ridge #212121; padding-bottom:15px;}
h3 {font: 18px "Trebuchet MS", Arial, Helvetica, sans-serif;font-weight: bold;text-transform: uppercase;margin: 30px 0 30px 100px;}
a {font: 14px "Century Gothic", Arial, Helvetica, sans-serif; margin-left: 100px;}
</style>
</head>
<body>
<div id="thanks"><h3>Thank You</h3><a href="index.html">Send Another Message</a></div>
</body>
</html>

280
html/messages2/validation.js Executable file
View File

@ -0,0 +1,280 @@
/*
* Really easy field validation with Prototype
* http://tetlaw.id.au/view/javascript/really-easy-field-validation
* Andrew Tetlaw
* Version 1.5.4.1 (2007-01-05)
*
* Copyright (c) 2007 Andrew Tetlaw
* 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.
*
*/
var Validator = Class.create();
Validator.prototype = {
initialize : function(className, error, test, options) {
if(typeof test == 'function'){
this.options = $H(options);
this._test = test;
} else {
this.options = $H(test);
this._test = function(){return true};
}
this.error = error || 'Validation failed.';
this.className = className;
},
test : function(v, elm) {
return (this._test(v,elm) && this.options.all(function(p){
return Validator.methods[p.key] ? Validator.methods[p.key](v,elm,p.value) : true;
}));
}
}
Validator.methods = {
pattern : function(v,elm,opt) {return Validation.get('IsEmpty').test(v) || opt.test(v)},
minLength : function(v,elm,opt) {return v.length >= opt},
maxLength : function(v,elm,opt) {return v.length <= opt},
min : function(v,elm,opt) {return v >= parseFloat(opt)},
max : function(v,elm,opt) {return v <= parseFloat(opt)},
notOneOf : function(v,elm,opt) {return $A(opt).all(function(value) {
return v != value;
})},
oneOf : function(v,elm,opt) {return $A(opt).any(function(value) {
return v == value;
})},
is : function(v,elm,opt) {return v == opt},
isNot : function(v,elm,opt) {return v != opt},
equalToField : function(v,elm,opt) {return v == $F(opt)},
notEqualToField : function(v,elm,opt) {return v != $F(opt)},
include : function(v,elm,opt) {return $A(opt).all(function(value) {
return Validation.get(value).test(v,elm);
})}
}
var Validation = Class.create();
Validation.prototype = {
initialize : function(form, options){
this.options = Object.extend({
onSubmit : true,
stopOnFirst : false,
immediate : false,
focusOnError : true,
useTitles : false,
onFormValidate : function(result, form) {},
onElementValidate : function(result, elm) {}
}, options || {});
this.form = $(form);
if(this.options.onSubmit) Event.observe(this.form,'submit',this.onSubmit.bind(this),false);
if(this.options.immediate) {
var useTitles = this.options.useTitles;
var callback = this.options.onElementValidate;
Form.getElements(this.form).each(function(input) { // Thanks Mike!
Event.observe(input, 'blur', function(ev) { Validation.validate(Event.element(ev),{useTitle : useTitles, onElementValidate : callback}); });
});
}
},
onSubmit : function(ev){
if(!this.validate()) Event.stop(ev);
},
validate : function() {
var result = false;
var useTitles = this.options.useTitles;
var callback = this.options.onElementValidate;
if(this.options.stopOnFirst) {
result = Form.getElements(this.form).all(function(elm) { return Validation.validate(elm,{useTitle : useTitles, onElementValidate : callback}); });
} else {
result = Form.getElements(this.form).collect(function(elm) { return Validation.validate(elm,{useTitle : useTitles, onElementValidate : callback}); }).all();
}
if(!result && this.options.focusOnError) {
Form.getElements(this.form).findAll(function(elm){return $(elm).hasClassName('validation-failed')}).first().focus()
}
this.options.onFormValidate(result, this.form);
return result;
},
reset : function() {
Form.getElements(this.form).each(Validation.reset);
}
}
Object.extend(Validation, {
validate : function(elm, options){
options = Object.extend({
useTitle : false,
onElementValidate : function(result, elm) {}
}, options || {});
elm = $(elm);
var cn = elm.classNames();
return result = cn.all(function(value) {
var test = Validation.test(value,elm,options.useTitle);
options.onElementValidate(test, elm);
return test;
});
},
test : function(name, elm, useTitle) {
var v = Validation.get(name);
var prop = '__advice'+name.camelize();
try {
if(Validation.isVisible(elm) && !v.test($F(elm), elm)) {
if(!elm[prop]) {
var advice = Validation.getAdvice(name, elm);
if(advice == null) {
var errorMsg = useTitle ? ((elm && elm.title) ? elm.title : v.error) : v.error;
advice = '<div class="validation-advice" id="advice-' + name + '-' + Validation.getElmID(elm) +'" style="display:none">' + errorMsg + '</div>'
switch (elm.type.toLowerCase()) {
case 'checkbox':
case 'radio':
var p = elm.parentNode;
if(p) {
new Insertion.Bottom(p, advice);
} else {
new Insertion.After(elm, advice);
}
break;
default:
new Insertion.After(elm, advice);
}
advice = Validation.getAdvice(name, elm);
}
if(typeof Effect == 'undefined') {
advice.style.display = 'block';
} else {
new Effect.Appear(advice, {duration : 1 });
}
}
elm[prop] = true;
elm.removeClassName('validation-passed');
elm.addClassName('validation-failed');
return false;
} else {
var advice = Validation.getAdvice(name, elm);
if(advice != null) advice.hide();
elm[prop] = '';
elm.removeClassName('validation-failed');
elm.addClassName('validation-passed');
return true;
}
} catch(e) {
throw(e)
}
},
isVisible : function(elm) {
while(elm.tagName != 'BODY') {
if(!$(elm).visible()) return false;
elm = elm.parentNode;
}
return true;
},
getAdvice : function(name, elm) {
return $('advice-' + name + '-' + Validation.getElmID(elm)) || $('advice-' + Validation.getElmID(elm));
},
getElmID : function(elm) {
return elm.id ? elm.id : elm.name;
},
reset : function(elm) {
elm = $(elm);
var cn = elm.classNames();
cn.each(function(value) {
var prop = '__advice'+value.camelize();
if(elm[prop]) {
var advice = Validation.getAdvice(value, elm);
advice.hide();
elm[prop] = '';
}
elm.removeClassName('validation-failed');
elm.removeClassName('validation-passed');
});
},
add : function(className, error, test, options) {
var nv = {};
nv[className] = new Validator(className, error, test, options);
Object.extend(Validation.methods, nv);
},
addAllThese : function(validators) {
var nv = {};
$A(validators).each(function(value) {
nv[value[0]] = new Validator(value[0], value[1], value[2], (value.length > 3 ? value[3] : {}));
});
Object.extend(Validation.methods, nv);
},
get : function(name) {
return Validation.methods[name] ? Validation.methods[name] : Validation.methods['_LikeNoIDIEverSaw_'];
},
methods : {
'_LikeNoIDIEverSaw_' : new Validator('_LikeNoIDIEverSaw_','',{})
}
});
Validation.add('IsEmpty', '', function(v) {
return ((v == null) || (v.length == 0)); // || /^\s+$/.test(v));
});
Validation.addAllThese([
['required', 'The above field is required.', function(v) {
return !Validation.get('IsEmpty').test(v);
}],
['validate-number', 'Please enter a valid number in this field.', function(v) {
return Validation.get('IsEmpty').test(v) || (!isNaN(v) && !/^\s+$/.test(v));
}],
['validate-digits', 'Please use numbers only in this field. please avoid spaces or other characters such as dots or commas.', function(v) {
return Validation.get('IsEmpty').test(v) || !/[^\d]/.test(v);
}],
['validate-alpha', 'Please use letters only (a-z) in this field.', function (v) {
return Validation.get('IsEmpty').test(v) || /^[a-zA-Z]+$/.test(v)
}],
['validate-alphanum', 'Please use only letters (a-z) or numbers (0-9) only in this field. No spaces or other characters are allowed.', function(v) {
return Validation.get('IsEmpty').test(v) || !/\W/.test(v)
}],
['validate-date', 'Please enter a valid date.', function(v) {
var test = new Date(v);
return Validation.get('IsEmpty').test(v) || !isNaN(test);
}],
['validate-email', 'Please enter a valid email address. For example fred@domain.com .', function (v) {
return Validation.get('IsEmpty').test(v) || /\w{1,}[@][\w\-]{1,}([.]([\w\-]{1,})){1,3}$/.test(v)
}],
['validate-url', 'Please enter a valid URL.', function (v) {
return Validation.get('IsEmpty').test(v) || /^(http|https|ftp):\/\/(([A-Z0-9][A-Z0-9_-]*)(\.[A-Z0-9][A-Z0-9_-]*)+)(:(\d+))?\/?/i.test(v)
}],
['validate-date-au', 'Please use this date format: dd/mm/yyyy. For example 17/03/2006 for the 17th of March, 2006.', function(v) {
if(Validation.get('IsEmpty').test(v)) return true;
var regex = /^(\d{2})\/(\d{2})\/(\d{4})$/;
if(!regex.test(v)) return false;
var d = new Date(v.replace(regex, '$2/$1/$3'));
return ( parseInt(RegExp.$2, 10) == (1+d.getMonth()) ) &&
(parseInt(RegExp.$1, 10) == d.getDate()) &&
(parseInt(RegExp.$3, 10) == d.getFullYear() );
}],
['validate-currency-dollar', 'Please enter a valid $ amount. For example $100.00 .', function(v) {
// [$]1[##][,###]+[.##]
// [$]1###+[.##]
// [$]0.##
// [$].##
return Validation.get('IsEmpty').test(v) || /^\$?\-?([1-9]{1}[0-9]{0,2}(\,[0-9]{3})*(\.[0-9]{0,2})?|[1-9]{1}\d*(\.[0-9]{0,2})?|0(\.[0-9]{0,2})?|(\.[0-9]{1,2})?)$/.test(v)
}],
['validate-selection', 'Please make a selection', function(v,elm){
return elm.options ? elm.selectedIndex > 0 : !Validation.get('IsEmpty').test(v);
}],
['validate-one-required', 'Please select one of the above options.', function (v,elm) {
var p = elm.parentNode;
var options = p.getElementsByTagName('INPUT');
return $A(options).any(function(elm) {
return $F(elm);
});
}]
]);