Index: openacs-4/packages/forums/lib/message/content-updater-oracle.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/forums/lib/message/Attic/content-updater-oracle.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/forums/lib/message/content-updater-oracle.xql 28 Jun 2006 20:30:28 -0000 1.1 @@ -0,0 +1,46 @@ + + + + oracle8.1.6 + + + + select message_id, + 0 as n_attachments, + subject, + content, + format, + person.name(user_id) as user_name, + to_char(posting_date, 'YYYY-MM-DD HH24:MI:SS') as posting_date_ansi, + tree.tree_level(tree_sortkey) as tree_level, + state, + user_id, + parent_id + from $table_name + where forum_id = :forum_id + and tree_sortkey between tree.left(:tree_sortkey) and tree.right(:tree_sortkey) + order by $order_by + + + + + + select message_id, + (select count(*) from attachments where object_id = message_id) as n_attachments, + subject, + content, + format, + person.name(user_id) as user_name, + to_char(posting_date, 'YYYY-MM-DD HH24:MI:SS') as posting_date_ansi, + tree.tree_level(tree_sortkey) as tree_level, + state, + user_id, + parent_id + from $table_name + where forum_id = :forum_id + and tree_sortkey between tree.left(:tree_sortkey) and tree.right(:tree_sortkey) + order by $order_by + + + + Index: openacs-4/packages/forums/lib/message/content-updater-postgresql.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/forums/lib/message/Attic/content-updater-postgresql.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/forums/lib/message/content-updater-postgresql.xql 28 Jun 2006 20:30:28 -0000 1.1 @@ -0,0 +1,51 @@ + + + + postgresql7.1 + + + + select message_id, + 0 as n_attachments, + subject, + content, + format, + person__name(user_id) as user_name, + to_char(posting_date, 'YYYY-MM-DD HH24:MI:SS') as posting_date_ansi, + tree_level(tree_sortkey) as tree_level, + state, + user_id, + parent_id, + open_p, + max_child_sortkey + from $table_name + where forum_id = :forum_id + and tree_sortkey between tree_left(:tree_sortkey) and tree_right(:tree_sortkey) + order by $order_by + + + + + + select message_id, + (select count(*) from attachments where object_id = message_id) as n_attachments, + subject, + content, + format, + person__name(user_id) as user_name, + to_char(posting_date, 'YYYY-MM-DD HH24:MI:SS') as posting_date_ansi, + tree_level(tree_sortkey) as tree_level, + state, + user_id, + parent_id, + open_p, + max_child_sortkey + from $table_name + where forum_id = :forum_id + and tree_sortkey between tree_left(:tree_sortkey) and tree_right(:tree_sortkey) + order by $order_by + + + + + Index: openacs-4/packages/forums/lib/message/content-updater.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/forums/lib/message/Attic/content-updater.adp,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/forums/lib/message/content-updater.adp 28 Jun 2006 20:30:28 -0000 1.1 @@ -0,0 +1,8 @@ +@message.content;noquote@ + +
+ #forums.Attachments# + +
+
+ Index: openacs-4/packages/forums/lib/message/content-updater.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/forums/lib/message/Attic/content-updater.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/forums/lib/message/content-updater.tcl 28 Jun 2006 20:30:28 -0000 1.1 @@ -0,0 +1,39 @@ +ad_page_contract { + + Gets the content of an specified message + + @author Veronica De La Cruz (veronica@viaro.net) + @creation-date 2006-04-21 + + +} + + + + +# Set some sql variables + +set forum_id $message(forum_id) +set tree_sortkey $message(tree_sortkey) + +if {[forum::attachments_enabled_p]} { + set query select_message_responses_attachments +} else { + set query select_message_responses +} + +# Find the ordering of messages so it can be consistent +# with the code that is in thread-chunk + +if { [string equal $forum(presentation_type) flat] } { + set order_by "fma.posting_date, fma.tree_sortkey" +} else { + set order_by "fma.tree_sortkey" +} + + +set message(content) [ad_html_text_convert -from $message(format) -to text/html -- $message(content)] + +# convert emoticons to images if the parameter is set +if { [string is true [parameter::get -parameter DisplayEmoticonsAsImagesP -default 0]] } { + set message(content) [forum::format::emoticons -content $message(content)]} Index: openacs-4/packages/forums/lib/message/row2.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/forums/lib/message/row2.adp,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/forums/lib/message/row2.adp 28 Jun 2006 20:30:28 -0000 1.1 @@ -0,0 +1,121 @@ +
+
+ + + + + + + +
+
+ + + + #forums.Expand_only_direct_reply_of_message# + #forums.Expand_all_messages# + #forums.Collapse_all_messages# + +
+ + +
+ + +
+   + @message.number@: + @message.subject@ + + +
@message.subject@ + + + +
@message.number@ + + + (response to @message.parent_number@) + +
+
#forums.Posted_by# @message.user_name@ on
+
+
+ + +
+ +
+ + + +
+
+ + @message.content;noquote@ + +
+ #forums.Attachments# + +
+
+
+
+
+
+ + + + + + + + + + + Index: openacs-4/packages/forums/lib/message/row2.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/forums/lib/message/row2.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/forums/lib/message/row2.tcl 28 Jun 2006 20:30:28 -0000 1.1 @@ -0,0 +1,90 @@ + +ad_page_contract { + + a message chunk to be included in a table listing of messages + + @author yon (yon@openforce.net) + @author arjun (arjun@openforce.net) + @creation-date 2002-06-02 + @cvs-id $Id: row2.tcl,v 1.1 2006/06/28 20:30:28 veronicac Exp $ + +} + +set viewer_id [ad_conn user_id] + + +if {![exists_and_not_null rownum]} { + set rownum 1 +} + +set message(content) [ad_html_text_convert -from $message(format) -to text/html -- $message(content)] + +# convert emoticons to images if the parameter is set +if { [string is true [parameter::get -parameter DisplayEmoticonsAsImagesP -default 0]] } { + set message(content) [forum::format::emoticons -content $message(content)]} + +# JCD: display subject only if changed from the root subject +if {![info exists root_subject]} { + set display_subject_p 1 +} else {thr regsub {^(Response to |\s*Re:\s*)*} $message(subject) {} subject + set display_subject_p [expr ![string equal $subject $root_subject]] +} + +if {[exists_and_not_null alt_template]} { + ad_return_template $alt_template +} +if {![info exists message(message_id)]} { + set message(message_id) none +} +if {![info exists message(tree_level)]} { + set message(tree_level) 0 +} + + + + +## New ## + +set max_number_messages [parameter::get -parameter max_number_messages_with_effects -default 120] + +set parent $message(message_id) +set direct_children_list [db_list children_list_name "select message_id from $table_name where message_id = $parent or parent_id = $parent order by message_id"] +set message_children_list [db_list select_message_children " SELECT fma.message_id \ + FROM forums_messages_approved fma \ + WHERE fma.forum_id = $forum_id \ + and fma.tree_sortkey between (select fm.tree_sortkey from forums_messages fm where fm.message_id = $parent) \ + and (select tree_right(fm.tree_sortkey) from forums_messages fm where fm.message_id = $parent) \ + ORDER BY fma.message_id "] + +# List of all the children given a message_id +if {[llength $message_children_list] == 0 } { + + set children_string "null" +} + +set children_string $message_children_list + +# List of the direct children of a message + +if {[llength $direct_children_list] == 0} { + + set children_direct_list "null" + } + + set children_direct_list "$direct_children_list" + +# Gets all the direct children of the main message +set childs [db_list get_childs "select message_id from $table_name where parent_id = $main_message_id or message_id = $main_message_id order by message_id"] + +set is_direct_child 0 + +set is_direct_children [lsearch $childs $parent] +if {$is_direct_children == -1 } { + set is_direct_child 0 +} else { + set is_direct_child 1 +} + +## Ends New ## +set allow_edit_own_p [parameter::get -parameter AllowUsersToEditOwnPostsP -default 0] +set own_p [expr [string equal $message(user_id) $viewer_id] && $allow_edit_own_p] Index: openacs-4/packages/forums/www/copy-random-message.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/forums/www/Attic/copy-random-message.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/forums/www/copy-random-message.tcl 28 Jun 2006 20:30:29 -0000 1.1 @@ -0,0 +1,97 @@ +ad_page_contract { + + View a random number of messages + +} { + rowcount:integer + forum_id:integer + message_id:integer + +} + +ns_log notice it's my page! +set mypage [ns_getform] +if {[string equal "" $mypage]} { + ns_log notice no form was submitted on my page +} else { + ns_log notice the following form was submitted on my page + ns_set print $mypage +} + + + +set return_url "[ad_conn package_url]message-view?message_id=$message_id" +set number_messages [expr $rowcount + 1] + + +ad_form -name random_message -export {return_url message_id forum_id rowcount} -form { + + {value:text {label "Number of messages to display"} + {html {size 3}}} + + +} -on_submit { + #ns_log notice "entro" + #form get_values random_message value return_url message_id forum_id + + set message_list [db_list select_list "select fma.message_id \ + from forums_messages_approved fma \ + where fma.forum_id = $forum_id \ + and fma.tree_sortkey between (select fm.tree_sortkey from forums_messages fm where fm.message_id = $message_id) \ + and (select tree_right(fm.tree_sortkey) from forums_messages fm where fm.message_id = $message_id) \ + order by fma.message_id"] + + for {set i 0} {$i < $value} {incr i} { + set reply [expr rand()] + set list_index [expr int([expr rand() * [llength $message_list]])] + set content_length [expr int ([expr rand() * 300])] + ns_log notice "tamaño: $content_length" + set subject [ad_generate_random_string] + set content [ad_generate_random_string $content_length] + ns_log notice "l:$list_index" + ns_log notice "s: $subject" + ns_log notice "c: $content" + set pato [llength $message_list] + ns_log notice "$pato" + + if {$reply < 0.5} { + set reply 0 + } else { + set reply 1 + } + + if {$reply == 1} { + set parent_id [lindex $message_list $list_index] + + set generated_message_id [forum::message::new \ + -forum_id $forum_id \ + -parent_id $parent_id \ + -subject $subject \ + -content $content] + + + } else { + + set generated_message_id [forum::message::new \ + -forum_id $forum_id \ + -parent_id $message_id \ + -subject $subject \ + -content $content] + + } + + lappend message_list $generated_message_id + + } + + + + } -after_submit { + + ad_returnredirect $return_url + ad_script_abort + + } + + + Index: openacs-4/packages/forums/www/crear-men.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/forums/www/Attic/crear-men.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/forums/www/crear-men.tcl 28 Jun 2006 20:30:29 -0000 1.1 @@ -0,0 +1,69 @@ +ad_page_contract { + + View a random number of messages + +} { + rowcount:integer + forum_id:integer + message_id:integer + number:integer + +} + +#set generate_number 5 +set return_url "[ad_conn package_url]message-view?message_id=$message_id" + +set message_list [db_list select_list "select fma.message_id \ + from forums_messages_approved fma \ + where fma.forum_id = $forum_id \ + and fma.tree_sortkey between (select fm.tree_sortkey from forums_messages fm where fm.message_id = $message_id) \ + and (select tree_right(fm.tree_sortkey) from forums_messages fm where fm.message_id = $message_id) \ + order by fma.message_id"] + + +for {set i 0} {$i < $number} {incr i} { + set reply [expr rand()] + set list_index [expr int([expr rand() * [llength $message_list]])] + set content_length [expr int ([expr rand() * 300])] + ns_log notice "tamaño: $content_length" + set subject [ad_generate_random_string] + set content [ad_generate_random_string $content_length] + ns_log notice "l:$list_index" + ns_log notice "s: $subject" + ns_log notice "c: $content" + set pato [llength $message_list] + ns_log notice "$pato" + + if {$reply < 0.5} { + set reply 0 + } else { + set reply 1 + } + + if {$reply == 1} { + set parent_id [lindex $message_list $list_index] + + set generated_message_id [forum::message::new \ + -forum_id $forum_id \ + -parent_id $parent_id \ + -subject $subject \ + -content $content] + + + } else { + + set generated_message_id [forum::message::new \ + -forum_id $forum_id \ + -parent_id $message_id \ + -subject $subject \ + -content $content] + + } + + lappend message_list $generated_message_id + + } + + ad_returnredirect $return_url + ad_script_abort + \ No newline at end of file Index: openacs-4/packages/forums/www/hola.html =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/forums/www/Attic/hola.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/forums/www/hola.html 28 Jun 2006 20:30:29 -0000 1.1 @@ -0,0 +1,3 @@ +This is a test for the div of the content +
+It will appear at the message's content Index: openacs-4/packages/forums/www/load-message-content.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/forums/www/load-message-content.adp,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/forums/www/load-message-content.adp 28 Jun 2006 20:30:29 -0000 1.1 @@ -0,0 +1,4 @@ + Index: openacs-4/packages/forums/www/load-message-content.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/forums/www/load-message-content.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/forums/www/load-message-content.tcl 28 Jun 2006 20:30:29 -0000 1.1 @@ -0,0 +1,23 @@ +ad_page_contract { + + Update the content of an specified message, for preloading purpuoses + + @author Veronica De La Cruz (veronica@viaro.net) + @creation-date 2006-04-21 + + +} { + message_id:integer,notnull + {table_name "forums_messages" } +} + + +# Get the message information +forum::message::get -message_id $message_id -array message +if {![array exists message]} { + ns_returnnotfound + ad_script_abort +} + +# Load up the forum information +forum::get -forum_id $message(forum_id) -array forum Index: openacs-4/packages/forums/www/other.txt =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/forums/www/Attic/other.txt,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/forums/www/other.txt 28 Jun 2006 20:30:29 -0000 1.1 @@ -0,0 +1,16 @@ +set main_message_id $message(root_message_id) +set forum_id $message(forum_id) +set all_children_list [db_list children_list "select fma.message_id\ +from forums_messages_approved fma where fma.forum_id = :forum_id\ +and fma.tree_sortkey between (select fm.tree_sortkey from forums_messages fm where fm.message_id = :main_message_id)\ + and (select tree_right(fm.tree_sortkey) from forums_messages fm where fm.message_id = :main_message_id) order by fma.message_id "] + +set main_string "" +foreach all_children $all_children_list { + + append main_string "$all_children " + +} + +ns_log notice "$main_string" + \ No newline at end of file Index: openacs-4/packages/forums/www/random-message.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/forums/www/Attic/random-message.adp,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/forums/www/random-message.adp 28 Jun 2006 20:30:29 -0000 1.1 @@ -0,0 +1,20 @@ + + Create a random number of messages + + + + + + + + + + + + + +The total number of messages in thread are : @rowcount@ +
+
+ + Index: openacs-4/packages/forums/www/random-message.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/forums/www/Attic/random-message.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/forums/www/random-message.tcl 28 Jun 2006 20:30:29 -0000 1.1 @@ -0,0 +1,76 @@ +ad_page_contract { + + Create a specified number of messages, with a random content + @author Veronica De La Cruz (veronica@viaro.net) + @creation-date 2006-03-15 + +} { + + rowcount:integer + forum_id:integer + message_id:integer + +} + + + +set return_url "[ad_conn package_url]message-view?message_id=$message_id" + +#List of the ids of all the messages that are currently on the thread. +set message_list [db_list select_list "select fma.message_id \ + from forums_messages_approved fma \ + where fma.forum_id = $forum_id \ + and fma.tree_sortkey between (select fm.tree_sortkey from forums_messages fm where fm.message_id = $message_id) \ + and (select tree_right(fm.tree_sortkey) from forums_messages fm where fm.message_id = $message_id) \ + order by fma.message_id"] + + +ad_form -name random_message -export {return_url message_id forum_id rowcount} -form { + + {value:text {label "Number of messages to create:"} + {html {size 3}}} + + +} -on_submit { + + for {set i 0} {$i < $value} {incr i} { + + set list_index [expr int([expr rand() * [llength $message_list]])] + set content_length [expr int ([expr rand() * 50])] + set subject [ad_generate_random_string] + set content [ad_generate_random_string $content_length] + + + for {set j 0} {$j < $content_length} {incr j} { + + append content [ad_generate_random_string 5000] + append content " " + + } + + # Choose randomly any message to be the parent_id + set parent_id [lindex $message_list $list_index] + + # Create the message + set generated_message_id [forum::message::new \ + -forum_id $forum_id \ + -parent_id $parent_id \ + -subject $subject \ + -content $content] + + # Include in the ids list the generated messages + lappend message_list $generated_message_id + + } + + + + } -after_submit { + + ad_returnredirect $return_url + ad_script_abort + + } + + + Index: openacs-4/packages/forums/www/random.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/forums/www/Attic/random.adp,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/forums/www/random.adp 28 Jun 2006 20:30:29 -0000 1.1 @@ -0,0 +1,32 @@ + + + Display a random number of messages + + + + + + + + + + + + + + + + + + + + + + + +The total number of messages in thread are : @number_of_messages@ +
+
+ + + Index: openacs-4/packages/forums/www/random.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/forums/www/Attic/random.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/forums/www/random.tcl 28 Jun 2006 20:30:29 -0000 1.1 @@ -0,0 +1,53 @@ +ad_page_contract { + + Create a random number of messages + +} { + + rowcount:integer + forum_id:integer + message_id:integer + +} + + +set number_of_messages $rowcount +set return_url "[ad_conn package_url]/message-view?message_id=$message_id" + +set message_list [db_list select_list "select fma.message_id \ + from forums_messages_approved fma \ + where fma.forum_id = $forum_id \ + and fma.tree_sortkey between (select fm.tree_sortkey from forums_messages fm where fm.message_id = $message_id) \ + and (select tree_right(fm.tree_sortkey) from forums_messages fm where fm.message_id = $message_id) \ + order by fma.message_id"] + +form create random_message + +element create random_message generate_number -datatype integer \ + -label "Number of messages to display" \ + -widget text \ + -html {size 5} + + + template::form::get_values random_message + ns_log notice "ffd: $generate_number" + + + + + +if {[template::form::is_valid random_message]} { + ns_log notice "" + + form get_values random_message + ns_log notice "ffd: $generate_number" + + ad_returnredirect "[ad_conn package_url]/crear-men?rowcount=$rowcount&forum_id=$forum_id&message_id=$message_id&number=$generate_number" + + ad_script_abort + +} + +#set f [ template::element::get_value random_message generate_number] + + #ns_log notice "dslk:generate_number" Index: openacs-4/packages/forums/www/resources/- =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/forums/www/resources/Attic/-,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/forums/www/resources/- 28 Jun 2006 20:30:29 -0000 1.1 @@ -0,0 +1,1806 @@ +// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) +// Contributors: +// Justin Palmer (http://encytemedia.com/) +// Mark Pilgrim (http://diveintomark.org/) +// Martin Bialasinki +// +// See scriptaculous.js for full license. + +/* ------------- element ext -------------- */ + +// converts rgb() and #xxx to #xxxxxx format, +// returns self (or first argument) if not convertable +String.prototype.parseColor = function() { + var color = '#'; + if(this.slice(0,4) == 'rgb(') { + var cols = this.slice(4,this.length-1).split(','); + var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3); + } else { + if(this.slice(0,1) == '#') { + if(this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase(); + if(this.length==7) color = this.toLowerCase(); + } + } + return(color.length==7 ? color : (arguments[0] || this)); +} + +Element.collectTextNodes = function(element) { + return $A($(element).childNodes).collect( function(node) { + return (node.nodeType==3 ? node.nodeValue : + (node.hasChildNodes() ? Element.collectTextNodes(node) : '')); + }).flatten().join(''); +} + +Element.collectTextNodesIgnoreClass = function(element, className) { + return $A($(element).childNodes).collect( function(node) { + return (node.nodeType==3 ? node.nodeValue : + ((node.hasChildNodes() && !Element.hasClassName(node,className)) ? + Element.collectTextNodes(node) : '')); + }).flatten().join(''); +} + +Element.setStyle = function(element, style) { + element = $(element); + for(k in style) element.style[k.camelize()] = style[k]; +} + +Element.setContentZoom = function(element, percent) { + Element.setStyle(element, {fontSize: (percent/100) + 'em'}); + if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0); +} + +Element.getOpacity = function(element){ + var opacity; + if (opacity = Element.getStyle(element, 'opacity')) + return parseFloat(opacity); + if (opacity = (Element.getStyle(element, 'filter') || '').match(/alpha\(opacity=(.*)\)/)) + if(opacity[1]) return parseFloat(opacity[1]) / 100; + return 1.0; +} + +Element.setOpacity = function(element, value){ + element= $(element); + if (value == 1){ + Element.setStyle(element, { opacity: + (/Gecko/.test(navigator.userAgent) && !/Konqueror|Safari|KHTML/.test(navigator.userAgent)) ? + 0.999999 : null }); + if(/MSIE/.test(navigator.userAgent)) + Element.setStyle(element, {filter: Element.getStyle(element,'filter').replace(/alpha\([^\)]*\)/gi,'')}); + } else { + if(value < 0.00001) value = 0; + Element.setStyle(element, {opacity: value}); + if(/MSIE/.test(navigator.userAgent)) + Element.setStyle(element, + { filter: Element.getStyle(element,'filter').replace(/alpha\([^\)]*\)/gi,'') + + 'alpha(opacity='+value*100+')' }); + } +} + +Element.getInlineOpacity = function(element){ + return $(element).style.opacity || ''; +} + +Element.childrenWithClassName = function(element, className) { + return $A($(element).getElementsByTagName('*')).select( + function(c) { return Element.hasClassName(c, className) }); +} + +Array.prototype.call = function() { + var args = arguments; + this.each(function(f){ f.apply(this, args) }); +} + +/*--------------------------------------------------------------------------*/ + +var Effect = { + tagifyText: function(element) { + var tagifyStyle = 'position:relative'; + if(/MSIE/.test(navigator.userAgent)) tagifyStyle += ';zoom:1'; + element = $(element); + $A(element.childNodes).each( function(child) { + if(child.nodeType==3) { + child.nodeValue.toArray().each( function(character) { + element.insertBefore( + Builder.node('span',{style: tagifyStyle}, + character == ' ' ? String.fromCharCode(160) : character), + child); + }); + Element.remove(child); + } + }); + }, + multiple: function(element, effect) { + var elements; + if(((typeof element == 'object') || + (typeof element == 'function')) && + (element.length)) + elements = element; + else + elements = $(element).childNodes; + + var options = Object.extend({ + speed: 0.1, + delay: 0.0 + }, arguments[2] || {}); + var masterDelay = options.delay; + + $A(elements).each( function(element, index) { + new effect(element, Object.extend(options, { delay: index * options.speed + masterDelay })); + }); + }, + PAIRS: { + 'slide': ['SlideDown','SlideUp'], + 'blind': ['BlindDown','BlindUp'], + 'appear': ['Appear','Fade'] + }, + toggle: function(element, effect) { + element = $(element); + effect = (effect || 'appear').toLowerCase(); + var options = Object.extend({ + queue: { position:'end', scope:(element.id || 'global') } + }, arguments[2] || {}); + Effect[Element.visible(element) ? + Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options); + } +}; + +var Effect2 = Effect; // deprecated + +/* ------------- transitions ------------- */ + +Effect.Transitions = {} + +Effect.Transitions.linear = function(pos) { + return pos; +} +Effect.Transitions.sinoidal = function(pos) { + return (-Math.cos(pos*Math.PI)/2) + 0.5; +} +Effect.Transitions.reverse = function(pos) { + return 1-pos; +} +Effect.Transitions.flicker = function(pos) { + return ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4; +} +Effect.Transitions.wobble = function(pos) { + return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5; +} +Effect.Transitions.pulse = function(pos) { + return (Math.floor(pos*10) % 2 == 0 ? + (pos*10-Math.floor(pos*10)) : 1-(pos*10-Math.floor(pos*10))); +} +Effect.Transitions.none = function(pos) { + return 0; +} +Effect.Transitions.full = function(pos) { + return 1; +} + +/* ------------- core effects ------------- */ + +Effect.ScopedQueue = Class.create(); +Object.extend(Object.extend(Effect.ScopedQueue.prototype, Enumerable), { + initialize: function() { + this.effects = []; + this.interval = null; + }, + _each: function(iterator) { + this.effects._each(iterator); + }, + add: function(effect) { + var timestamp = new Date().getTime(); + + var position = (typeof effect.options.queue == 'string') ? + effect.options.queue : effect.options.queue.position; + + switch(position) { + case 'front': + // move unstarted effects after this effect + this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) { + e.startOn += effect.finishOn; + e.finishOn += effect.finishOn; + }); + break; + case 'end': + // start effect after last queued effect has finished + timestamp = this.effects.pluck('finishOn').max() || timestamp; + break; + } + + effect.startOn += timestamp; + effect.finishOn += timestamp; + this.effects.push(effect); + if(!this.interval) + this.interval = setInterval(this.loop.bind(this), 40); + }, + remove: function(effect) { + this.effects = this.effects.reject(function(e) { return e==effect }); + if(this.effects.length == 0) { + clearInterval(this.interval); + this.interval = null; + } + }, + loop: function() { + var timePos = new Date().getTime(); + this.effects.invoke('loop', timePos); + } +}); + +Effect.Queues = { + instances: $H(), + get: function(queueName) { + if(typeof queueName != 'string') return queueName; + + if(!this.instances[queueName]) + this.instances[queueName] = new Effect.ScopedQueue(); + + return this.instances[queueName]; + } +} +Effect.Queue = Effect.Queues.get('global'); + +Effect.DefaultOptions = { + transition: Effect.Transitions.sinoidal, + duration: 1.0, // seconds + fps: 25.0, // max. 25fps due to Effect.Queue implementation + sync: false, // true for combining + from: 0.0, + to: 1.0, + delay: 0.0, + queue: 'parallel' +} + +Effect.Base = function() {}; +Effect.Base.prototype = { + position: null, + start: function(options) { + this.options = Object.extend(Object.extend({},Effect.DefaultOptions), options || {}); + this.currentFrame = 0; + this.state = 'idle'; + this.startOn = this.options.delay*1000; + this.finishOn = this.startOn + (this.options.duration*1000); + this.event('beforeStart'); + if(!this.options.sync) + Effect.Queues.get(typeof this.options.queue == 'string' ? + 'global' : this.options.queue.scope).add(this); + }, + loop: function(timePos) { + if(timePos >= this.startOn) { + if(timePos >= this.finishOn) { + this.render(1.0); + this.cancel(); + this.event('beforeFinish'); + if(this.finish) this.finish(); + this.event('afterFinish'); + return; + } + var pos = (timePos - this.startOn) / (this.finishOn - this.startOn); + var frame = Math.round(pos * this.options.fps * this.options.duration); + if(frame > this.currentFrame) { + this.render(pos); + this.currentFrame = frame; + } + } + }, + render: function(pos) { + if(this.state == 'idle') { + this.state = 'running'; + this.event('beforeSetup'); + if(this.setup) this.setup(); + this.event('afterSetup'); + } + if(this.state == 'running') { + if(this.options.transition) pos = this.options.transition(pos); + pos *= (this.options.to-this.options.from); + pos += this.options.from; + this.position = pos; + this.event('beforeUpdate'); + if(this.update) this.update(pos); + this.event('afterUpdate'); + } + }, + cancel: function() { + if(!this.options.sync) + Effect.Queues.get(typeof this.options.queue == 'string' ? + 'global' : this.options.queue.scope).remove(this); + this.state = 'finished'; + }, + event: function(eventName) { + if(this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this); + if(this.options[eventName]) this.options[eventName](this); + }, + inspect: function() { + return '#'; + } +} + +Effect.Parallel = Class.create(); +Object.extend(Object.extend(Effect.Parallel.prototype, Effect.Base.prototype), { + initialize: function(effects) { + this.effects = effects || []; + this.start(arguments[1]); + }, + update: function(position) { + this.effects.invoke('render', position); + }, + finish: function(position) { + this.effects.each( function(effect) { + effect.render(1.0); + effect.cancel(); + effect.event('beforeFinish'); + if(effect.finish) effect.finish(position); + effect.event('afterFinish'); + }); + } +}); + +Effect.Opacity = Class.create(); +Object.extend(Object.extend(Effect.Opacity.prototype, Effect.Base.prototype), { + initialize: function(element) { + this.element = $(element); + // make this work on IE on elements without 'layout' + if(/MSIE/.test(navigator.userAgent) && (!this.element.hasLayout)) + Element.setStyle(this.element, {zoom: 1}); + var options = Object.extend({ + from: Element.getOpacity(this.element) || 0.0, + to: 1.0 + }, arguments[1] || {}); + this.start(options); + }, + update: function(position) { + Element.setOpacity(this.element, position); + } +}); + +Effect.Move = Class.create(); +Object.extend(Object.extend(Effect.Move.prototype, Effect.Base.prototype), { + initialize: function(element) { + this.element = $(element); + var options = Object.extend({ + x: 0, + y: 0, + mode: 'relative' + }, arguments[1] || {}); + this.start(options); + }, + setup: function() { + // Bug in Opera: Opera returns the "real" position of a static element or + // relative element that does not have top/left explicitly set. + // ==> Always set top and left for position relative elements in your stylesheets + // (to 0 if you do not need them) + Element.makePositioned(this.element); + this.originalLeft = parseFloat(Element.getStyle(this.element,'left') || '0'); + this.originalTop = parseFloat(Element.getStyle(this.element,'top') || '0'); + if(this.options.mode == 'absolute') { + // absolute movement, so we need to calc deltaX and deltaY + this.options.x = this.options.x - this.originalLeft; + this.options.y = this.options.y - this.originalTop; + } + }, + update: function(position) { + Element.setStyle(this.element, { + left: this.options.x * position + this.originalLeft + 'px', + top: this.options.y * position + this.originalTop + 'px' + }); + } +}); + +// for backwards compatibility +Effect.MoveBy = function(element, toTop, toLeft) { + return new Effect.Move(element, + Object.extend({ x: toLeft, y: toTop }, arguments[3] || {})); +}; + +Effect.Scale = Class.create(); +Object.extend(Object.extend(Effect.Scale.prototype, Effect.Base.prototype), { + initialize: function(element, percent) { + this.element = $(element) + var options = Object.extend({ + scaleX: true, + scaleY: true, + scaleContent: true, + scaleFromCenter: false, + scaleMode: 'box', // 'box' or 'contents' or {} with provided values + scaleFrom: 100.0, + scaleTo: percent + }, arguments[2] || {}); + this.start(options); + }, + setup: function() { + this.restoreAfterFinish = this.options.restoreAfterFinish || false; + this.elementPositioning = Element.getStyle(this.element,'position'); + + this.originalStyle = {}; + ['top','left','width','height','fontSize'].each( function(k) { + this.originalStyle[k] = this.element.style[k]; + }.bind(this)); + + this.originalTop = this.element.offsetTop; + this.originalLeft = this.element.offsetLeft; + + var fontSize = Element.getStyle(this.element,'font-size') || '100%'; + ['em','px','%'].each( function(fontSizeType) { + if(fontSize.indexOf(fontSizeType)>0) { + this.fontSize = parseFloat(fontSize); + this.fontSizeType = fontSizeType; + } + }.bind(this)); + + this.factor = (this.options.scaleTo - this.options.scaleFrom)/100; + + this.dims = null; + if(this.options.scaleMode=='box') + this.dims = [this.element.offsetHeight, this.element.offsetWidth]; + if(/^content/.test(this.options.scaleMode)) + this.dims = [this.element.scrollHeight, this.element.scrollWidth]; + if(!this.dims) + this.dims = [this.options.scaleMode.originalHeight, + this.options.scaleMode.originalWidth]; + }, + update: function(position) { + var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position); + if(this.options.scaleContent && this.fontSize) + Element.setStyle(this.element, {fontSize: this.fontSize * currentScale + this.fontSizeType }); + this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale); + }, + finish: function(position) { + if (this.restoreAfterFinish) Element.setStyle(this.element, this.originalStyle); + }, + setDimensions: function(height, width) { + var d = {}; + if(this.options.scaleX) d.width = width + 'px'; + if(this.options.scaleY) d.height = height + 'px'; + if(this.options.scaleFromCenter) { + var topd = (height - this.dims[0])/2; + var leftd = (width - this.dims[1])/2; + if(this.elementPositioning == 'absolute') { + if(this.options.scaleY) d.top = this.originalTop-topd + 'px'; + if(this.options.scaleX) d.left = this.originalLeft-leftd + 'px'; + } else { + if(this.options.scaleY) d.top = -topd + 'px'; + if(this.options.scaleX) d.left = -leftd + 'px'; + } + } + Element.setStyle(this.element, d); + } +}); + +Effect.Highlight = Class.create(); +Object.extend(Object.extend(Effect.Highlight.prototype, Effect.Base.prototype), { + initialize: function(element) { + this.element = $(element); + var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || {}); + this.start(options); + }, + setup: function() { + // Prevent executing on elements not in the layout flow + if(Element.getStyle(this.element, 'display')=='none') { this.cancel(); return; } + // Disable background image during the effect + this.oldStyle = { + backgroundImage: Element.getStyle(this.element, 'background-image') }; + Element.setStyle(this.element, {backgroundImage: 'none'}); + if(!this.options.endcolor) + this.options.endcolor = Element.getStyle(this.element, 'background-color').parseColor('#ffffff'); + if(!this.options.restorecolor) + this.options.restorecolor = Element.getStyle(this.element, 'background-color'); + // init color calculations + this._base = $R(0,2).map(function(i){ return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16) }.bind(this)); + this._delta = $R(0,2).map(function(i){ return parseInt(this.options.endcolor.slice(i*2+1,i*2+3),16)-this._base[i] }.bind(this)); + }, + update: function(position) { + Element.setStyle(this.element,{backgroundColor: $R(0,2).inject('#',function(m,v,i){ + return m+(Math.round(this._base[i]+(this._delta[i]*position)).toColorPart()); }.bind(this)) }); + }, + finish: function() { + Element.setStyle(this.element, Object.extend(this.oldStyle, { + backgroundColor: this.options.restorecolor + })); + } +}); + +Effect.ScrollTo = Class.create(); +Object.extend(Object.extend(Effect.ScrollTo.prototype, Effect.Base.prototype), { + initialize: function(element) { + this.element = $(element); + this.start(arguments[1] || {}); + }, + setup: function() { + Position.prepare(); + var offsets = Position.cumulativeOffset(this.element); + if(this.options.offset) offsets[1] += this.options.offset; + var max = window.innerHeight ? + window.height - window.innerHeight : + document.body.scrollHeight - + (document.documentElement.clientHeight ? + document.documentElement.clientHeight : document.body.clientHeight); + this.scrollStart = Position.deltaY; + this.delta = (offsets[1] > max ? max : offsets[1]) - this.scrollStart; + }, + update: function(position) { + Position.prepare(); + window.scrollTo(Position.deltaX, + this.scrollStart + (position*this.delta)); + } +}); + +/* ------------- combination effects ------------- */ + +Effect.Fade = function(element) { + var oldOpacity = Element.getInlineOpacity(element); + var options = Object.extend({ + from: Element.getOpacity(element) || 1.0, + to: 0.0, + afterFinishInternal: function(effect) { with(Element) { + if(effect.options.to!=0) return; + hide(effect.element); + setStyle(effect.element, {opacity: oldOpacity}); }} + }, arguments[1] || {}); + return new Effect.Opacity(element,options); +} + +Effect.Appear = function(element) { + var options = Object.extend({ + from: (Element.getStyle(element, 'display') == 'none' ? 0.0 : Element.getOpacity(element) || 0.0), + to: 1.0, + beforeSetup: function(effect) { with(Element) { + setOpacity(effect.element, effect.options.from); + show(effect.element); }} + }, arguments[1] || {}); + return new Effect.Opacity(element,options); +} + +Effect.Puff = function(element) { + element = $(element); + var oldStyle = { opacity: Element.getInlineOpacity(element), position: Element.getStyle(element, 'position') }; + return new Effect.Parallel( + [ new Effect.Scale(element, 200, + { sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }), + new Effect.Opacity(element, { sync: true, to: 0.0 } ) ], + Object.extend({ duration: 1.0, + beforeSetupInternal: function(effect) { with(Element) { + setStyle(effect.effects[0].element, {position: 'absolute'}); }}, + afterFinishInternal: function(effect) { with(Element) { + hide(effect.effects[0].element); + setStyle(effect.effects[0].element, oldStyle); }} + }, arguments[1] || {}) + ); +} + +Effect.BlindUp = function(element) { + element = $(element); + Element.makeClipping(element); + return new Effect.Scale(element, 0, + Object.extend({ scaleContent: false, + scaleX: false, + restoreAfterFinish: true, + afterFinishInternal: function(effect) { with(Element) { + [hide, undoClipping].call(effect.element); }} + }, arguments[1] || {}) + ); +} + +Effect.BlindDown = function(element) { + element = $(element); + var oldHeight = Element.getStyle(element, 'height'); + var elementDimensions = Element.getDimensions(element); + return new Effect.Scale(element, 100, + Object.extend({ scaleContent: false, + scaleX: false, + scaleFrom: 0, + scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width}, + restoreAfterFinish: true, + afterSetup: function(effect) { with(Element) { + makeClipping(effect.element); + setStyle(effect.element, {height: '0px'}); + show(effect.element); + }}, + afterFinishInternal: function(effect) { with(Element) { + undoClipping(effect.element); + setStyle(effect.element, {height: oldHeight}); + }} + }, arguments[1] || {}) + ); +} + +Effect.SwitchOff = function(element) { + element = $(element); + var oldOpacity = Element.getInlineOpacity(element); + return new Effect.Appear(element, { + duration: 0.4, + from: 0, + transition: Effect.Transitions.flicker, + afterFinishInternal: function(effect) { + new Effect.Scale(effect.element, 1, { + duration: 0.3, scaleFromCenter: true, + scaleX: false, scaleContent: false, restoreAfterFinish: true, + beforeSetup: function(effect) { with(Element) { + [makePositioned,makeClipping].call(effect.element); + }}, + afterFinishInternal: function(effect) { with(Element) { + [hide,undoClipping,undoPositioned].call(effect.element); + setStyle(effect.element, {opacity: oldOpacity}); + }} + }) + } + }); +} + +Effect.DropOut = function(element) { + element = $(element); + var oldStyle = { + top: Element.getStyle(element, 'top'), + left: Element.getStyle(element, 'left'), + opacity: Element.getInlineOpacity(element) }; + return new Effect.Parallel( + [ new Effect.Move(element, {x: 0, y: 100, sync: true }), + new Effect.Opacity(element, { sync: true, to: 0.0 }) ], + Object.extend( + { duration: 0.5, + beforeSetup: function(effect) { with(Element) { + makePositioned(effect.effects[0].element); }}, + afterFinishInternal: function(effect) { with(Element) { + [hide, undoPositioned].call(effect.effects[0].element); + setStyle(effect.effects[0].element, oldStyle); }} + }, arguments[1] || {})); +} + +Effect.Shake = function(element) { + element = $(element); + var oldStyle = { + top: Element.getStyle(element, 'top'), + left: Element.getStyle(element, 'left') }; + return new Effect.Move(element, + { x: 20, y: 0, duration: 0.05, afterFinishInternal: function(effect) { + new Effect.Move(effect.element, + { x: -40, y: 0, duration: 0.1, afterFinishInternal: function(effect) { + new Effect.Move(effect.element, + { x: 40, y: 0, duration: 0.1, afterFinishInternal: function(effect) { + new Effect.Move(effect.element, + { x: -40, y: 0, duration: 0.1, afterFinishInternal: function(effect) { + new Effect.Move(effect.element, + { x: 40, y: 0, duration: 0.1, afterFinishInternal: function(effect) { + new Effect.Move(effect.element, + { x: -20, y: 0, duration: 0.05, afterFinishInternal: function(effect) { with(Element) { + undoPositioned(effect.element); + setStyle(effect.element, oldStyle); + }}}) }}) }}) }}) }}) }}); +} + +Effect.SlideDown = function(element) { + element = $(element); + Element.cleanWhitespace(element); + // SlideDown need to have the content of the element wrapped in a container element with fixed height! + var oldInnerBottom = Element.getStyle(element.firstChild, 'bottom'); + var elementDimensions = Element.getDimensions(element); + return new Effect.Scale(element, 100, Object.extend({ + scaleContent: false, + scaleX: false, + scaleFrom: 0, + scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width}, + restoreAfterFinish: true, + afterSetup: function(effect) { with(Element) { + makePositioned(effect.element); + makePositioned(effect.element.firstChild); + if(window.opera) setStyle(effect.element, {top: ''}); + makeClipping(effect.element); + setStyle(effect.element, {height: '0px'}); + show(element); }}, + afterUpdateInternal: function(effect) { with(Element) { + setStyle(effect.element.firstChild, {bottom: + (effect.dims[0] - effect.element.clientHeight) + 'px' }); }}, + afterFinishInternal: function(effect) { with(Element) { + undoClipping(effect.element); + undoPositioned(effect.element.firstChild); + undoPositioned(effect.element); + setStyle(effect.element.firstChild, {bottom: oldInnerBottom}); }} + }, arguments[1] || {}) + ); +} + +Effect.SlideUp = function(element) { + element = $(element); + Element.cleanWhitespace(element); + var oldInnerBottom = Element.getStyle(element.firstChild, 'bottom'); + return new Effect.Scale(element, 0, + Object.extend({ scaleContent: false, + scaleX: false, + scaleMode: 'box', + scaleFrom: 100, + restoreAfterFinish: true, + beforeStartInternal: function(effect) { with(Element) { + makePositioned(effect.element); + makePositioned(effect.element.firstChild); + if(window.opera) setStyle(effect.element, {top: ''}); + makeClipping(effect.element); + show(element); }}, + afterUpdateInternal: function(effect) { with(Element) { + setStyle(effect.element.firstChild, {bottom: + (effect.dims[0] - effect.element.clientHeight) + 'px' }); }}, + afterFinishInternal: function(effect) { with(Element) { + [hide, undoClipping].call(effect.element); + undoPositioned(effect.element.firstChild); + undoPositioned(effect.element); + setStyle(effect.element.firstChild, {bottom: oldInnerBottom}); }} + }, arguments[1] || {}) + ); +} + +// Bug in opera makes the TD containing this element expand for a instance after finish +Effect.Squish = function(element) { + return new Effect.Scale(element, window.opera ? 1 : 0, + { restoreAfterFinish: true, + beforeSetup: function(effect) { with(Element) { + makeClipping(effect.element); }}, + afterFinishInternal: function(effect) { with(Element) { + hide(effect.element); + undoClipping(effect.element); }} + }); +} + +Effect.Grow = function(element) { + element = $(element); + var options = Object.extend({ + direction: 'center', + moveTransistion: Effect.Transitions.sinoidal, + scaleTransition: Effect.Transitions.sinoidal, + opacityTransition: Effect.Transitions.full + }, arguments[1] || {}); + var oldStyle = { + top: element.style.top, + left: element.style.left, + height: element.style.height, + width: element.style.width, + opacity: Element.getInlineOpacity(element) }; + + var dims = Element.getDimensions(element); + var initialMoveX, initialMoveY; + var moveX, moveY; + + switch (options.direction) { + case 'top-left': + initialMoveX = initialMoveY = moveX = moveY = 0; + break; + case 'top-right': + initialMoveX = dims.width; + initialMoveY = moveY = 0; + moveX = -dims.width; + break; + case 'bottom-left': + initialMoveX = moveX = 0; + initialMoveY = dims.height; + moveY = -dims.height; + break; + case 'bottom-right': + initialMoveX = dims.width; + initialMoveY = dims.height; + moveX = -dims.width; + moveY = -dims.height; + break; + case 'center': + initialMoveX = dims.width / 2; + initialMoveY = dims.height / 2; + moveX = -dims.width / 2; + moveY = -dims.height / 2; + break; + } + + return new Effect.Move(element, { + x: initialMoveX, + y: initialMoveY, + duration: 0.01, + beforeSetup: function(effect) { with(Element) { + hide(effect.element); + makeClipping(effect.element); + makePositioned(effect.element); + }}, + afterFinishInternal: function(effect) { + new Effect.Parallel( + [ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }), + new Effect.Move(effect.element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }), + new Effect.Scale(effect.element, 100, { + scaleMode: { originalHeight: dims.height, originalWidth: dims.width }, + sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true}) + ], Object.extend({ + beforeSetup: function(effect) { with(Element) { + setStyle(effect.effects[0].element, {height: '0px'}); + show(effect.effects[0].element); }}, + afterFinishInternal: function(effect) { with(Element) { + [undoClipping, undoPositioned].call(effect.effects[0].element); + setStyle(effect.effects[0].element, oldStyle); }} + }, options) + ) + } + }); +} + +Effect.Shrink = function(element) { + element = $(element); + var options = Object.extend({ + direction: 'center', + moveTransistion: Effect.Transitions.sinoidal, + scaleTransition: Effect.Transitions.sinoidal, + opacityTransition: Effect.Transitions.none + }, arguments[1] || {}); + var oldStyle = { + top: element.style.top, + left: element.style.left, + height: element.style.height, + width: element.style.width, + opacity: Element.getInlineOpacity(element) }; + + var dims = Element.getDimensions(element); + var moveX, moveY; + + switch (options.direction) { + case 'top-left': + moveX = moveY = 0; + break; + case 'top-right': + moveX = dims.width; + moveY = 0; + break; + case 'bottom-left': + moveX = 0; + moveY = dims.height; + break; + case 'bottom-right': + moveX = dims.width; + moveY = dims.height; + break; + case 'center': + moveX = dims.width / 2; + moveY = dims.height / 2; + break; + } + + return new Effect.Parallel( + [ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }), + new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true}), + new Effect.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }) + ], Object.extend({ + beforeStartInternal: function(effect) { with(Element) { + [makePositioned, makeClipping].call(effect.effects[0].element) }}, + afterFinishInternal: function(effect) { with(Element) { + [hide, undoClipping, undoPositioned].call(effect.effects[0].element); + setStyle(effect.effects[0].element, oldStyle); }} + }, options) + ); +} + +Effect.Pulsate = function(element) { + element = $(element); + var options = arguments[1] || {}; + var oldOpacity = Element.getInlineOpacity(element); + var transition = options.transition || Effect.Transitions.sinoidal; + var reverser = function(pos){ return transition(1-Effect.Transitions.pulse(pos)) }; + reverser.bind(transition); + return new Effect.Opacity(element, + Object.extend(Object.extend({ duration: 3.0, from: 0, + afterFinishInternal: function(effect) { Element.setStyle(effect.element, {opacity: oldOpacity}); } + }, options), {transition: reverser})); +} + +Effect.Fold = function(element) { + element = $(element); + var oldStyle = { + top: element.style.top, + left: element.style.left, + width: element.style.width, + height: element.style.height }; + Element.makeClipping(element); + return new Effect.Scale(element, 5, Object.extend({ + scaleContent: false, + scaleX: false, + afterFinishInternal: function(effect) { + new Effect.Scale(element, 1, { + scaleContent: false, + scaleY: false, + afterFinishInternal: function(effect) { with(Element) { + [hide, undoClipping].call(effect.element); + setStyle(effect.element, oldStyle); + }} }); + }}, arguments[1] || {})); +} +// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) +// Contributors: +// Justin Palmer (http://encytemedia.com/) +// Mark Pilgrim (http://diveintomark.org/) +// Martin Bialasinki +// +// See scriptaculous.js for full license. + +/* ------------- element ext -------------- */ + +// converts rgb() and #xxx to #xxxxxx format, +// returns self (or first argument) if not convertable +String.prototype.parseColor = function() { + var color = '#'; + if(this.slice(0,4) == 'rgb(') { + var cols = this.slice(4,this.length-1).split(','); + var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3); + } else { + if(this.slice(0,1) == '#') { + if(this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase(); + if(this.length==7) color = this.toLowerCase(); + } + } + return(color.length==7 ? color : (arguments[0] || this)); +} + +Element.collectTextNodes = function(element) { + return $A($(element).childNodes).collect( function(node) { + return (node.nodeType==3 ? node.nodeValue : + (node.hasChildNodes() ? Element.collectTextNodes(node) : '')); + }).flatten().join(''); +} + +Element.collectTextNodesIgnoreClass = function(element, className) { + return $A($(element).childNodes).collect( function(node) { + return (node.nodeType==3 ? node.nodeValue : + ((node.hasChildNodes() && !Element.hasClassName(node,className)) ? + Element.collectTextNodes(node) : '')); + }).flatten().join(''); +} + +Element.setStyle = function(element, style) { + element = $(element); + for(k in style) element.style[k.camelize()] = style[k]; +} + +Element.setContentZoom = function(element, percent) { + Element.setStyle(element, {fontSize: (percent/100) + 'em'}); + if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0); +} + +Element.getOpacity = function(element){ + var opacity; + if (opacity = Element.getStyle(element, 'opacity')) + return parseFloat(opacity); + if (opacity = (Element.getStyle(element, 'filter') || '').match(/alpha\(opacity=(.*)\)/)) + if(opacity[1]) return parseFloat(opacity[1]) / 100; + return 1.0; +} + +Element.setOpacity = function(element, value){ + element= $(element); + if (value == 1){ + Element.setStyle(element, { opacity: + (/Gecko/.test(navigator.userAgent) && !/Konqueror|Safari|KHTML/.test(navigator.userAgent)) ? + 0.999999 : null }); + if(/MSIE/.test(navigator.userAgent)) + Element.setStyle(element, {filter: Element.getStyle(element,'filter').replace(/alpha\([^\)]*\)/gi,'')}); + } else { + if(value < 0.00001) value = 0; + Element.setStyle(element, {opacity: value}); + if(/MSIE/.test(navigator.userAgent)) + Element.setStyle(element, + { filter: Element.getStyle(element,'filter').replace(/alpha\([^\)]*\)/gi,'') + + 'alpha(opacity='+value*100+')' }); + } +} + +Element.getInlineOpacity = function(element){ + return $(element).style.opacity || ''; +} + +Element.childrenWithClassName = function(element, className) { + return $A($(element).getElementsByTagName('*')).select( + function(c) { return Element.hasClassName(c, className) }); +} + +Array.prototype.call = function() { + var args = arguments; + this.each(function(f){ f.apply(this, args) }); +} + +/*--------------------------------------------------------------------------*/ + +var Effect = { + tagifyText: function(element) { + var tagifyStyle = 'position:relative'; + if(/MSIE/.test(navigator.userAgent)) tagifyStyle += ';zoom:1'; + element = $(element); + $A(element.childNodes).each( function(child) { + if(child.nodeType==3) { + child.nodeValue.toArray().each( function(character) { + element.insertBefore( + Builder.node('span',{style: tagifyStyle}, + character == ' ' ? String.fromCharCode(160) : character), + child); + }); + Element.remove(child); + } + }); + }, + multiple: function(element, effect) { + var elements; + if(((typeof element == 'object') || + (typeof element == 'function')) && + (element.length)) + elements = element; + else + elements = $(element).childNodes; + + var options = Object.extend({ + speed: 0.1, + delay: 0.0 + }, arguments[2] || {}); + var masterDelay = options.delay; + + $A(elements).each( function(element, index) { + new effect(element, Object.extend(options, { delay: index * options.speed + masterDelay })); + }); + }, + PAIRS: { + 'slide': ['SlideDown','SlideUp'], + 'blind': ['BlindDown','BlindUp'], + 'appear': ['Appear','Fade'] + }, + toggle: function(element, effect) { + element = $(element); + effect = (effect || 'appear').toLowerCase(); + var options = Object.extend({ + queue: { position:'end', scope:(element.id || 'global') } + }, arguments[2] || {}); + Effect[Element.visible(element) ? + Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options); + } +}; + +var Effect2 = Effect; // deprecated + +/* ------------- transitions ------------- */ + +Effect.Transitions = {} + +Effect.Transitions.linear = function(pos) { + return pos; +} +Effect.Transitions.sinoidal = function(pos) { + return (-Math.cos(pos*Math.PI)/2) + 0.5; +} +Effect.Transitions.reverse = function(pos) { + return 1-pos; +} +Effect.Transitions.flicker = function(pos) { + return ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4; +} +Effect.Transitions.wobble = function(pos) { + return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5; +} +Effect.Transitions.pulse = function(pos) { + return (Math.floor(pos*10) % 2 == 0 ? + (pos*10-Math.floor(pos*10)) : 1-(pos*10-Math.floor(pos*10))); +} +Effect.Transitions.none = function(pos) { + return 0; +} +Effect.Transitions.full = function(pos) { + return 1; +} + +/* ------------- core effects ------------- */ + +Effect.ScopedQueue = Class.create(); +Object.extend(Object.extend(Effect.ScopedQueue.prototype, Enumerable), { + initialize: function() { + this.effects = []; + this.interval = null; + }, + _each: function(iterator) { + this.effects._each(iterator); + }, + add: function(effect) { + var timestamp = new Date().getTime(); + + var position = (typeof effect.options.queue == 'string') ? + effect.options.queue : effect.options.queue.position; + + switch(position) { + case 'front': + // move unstarted effects after this effect + this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) { + e.startOn += effect.finishOn; + e.finishOn += effect.finishOn; + }); + break; + case 'end': + // start effect after last queued effect has finished + timestamp = this.effects.pluck('finishOn').max() || timestamp; + break; + } + + effect.startOn += timestamp; + effect.finishOn += timestamp; + this.effects.push(effect); + if(!this.interval) + this.interval = setInterval(this.loop.bind(this), 40); + }, + remove: function(effect) { + this.effects = this.effects.reject(function(e) { return e==effect }); + if(this.effects.length == 0) { + clearInterval(this.interval); + this.interval = null; + } + }, + loop: function() { + var timePos = new Date().getTime(); + this.effects.invoke('loop', timePos); + } +}); + +Effect.Queues = { + instances: $H(), + get: function(queueName) { + if(typeof queueName != 'string') return queueName; + + if(!this.instances[queueName]) + this.instances[queueName] = new Effect.ScopedQueue(); + + return this.instances[queueName]; + } +} +Effect.Queue = Effect.Queues.get('global'); + +Effect.DefaultOptions = { + transition: Effect.Transitions.sinoidal, + duration: 1.0, // seconds + fps: 25.0, // max. 25fps due to Effect.Queue implementation + sync: false, // true for combining + from: 0.0, + to: 1.0, + delay: 0.0, + queue: 'parallel' +} + +Effect.Base = function() {}; +Effect.Base.prototype = { + position: null, + start: function(options) { + this.options = Object.extend(Object.extend({},Effect.DefaultOptions), options || {}); + this.currentFrame = 0; + this.state = 'idle'; + this.startOn = this.options.delay*1000; + this.finishOn = this.startOn + (this.options.duration*1000); + this.event('beforeStart'); + if(!this.options.sync) + Effect.Queues.get(typeof this.options.queue == 'string' ? + 'global' : this.options.queue.scope).add(this); + }, + loop: function(timePos) { + if(timePos >= this.startOn) { + if(timePos >= this.finishOn) { + this.render(1.0); + this.cancel(); + this.event('beforeFinish'); + if(this.finish) this.finish(); + this.event('afterFinish'); + return; + } + var pos = (timePos - this.startOn) / (this.finishOn - this.startOn); + var frame = Math.round(pos * this.options.fps * this.options.duration); + if(frame > this.currentFrame) { + this.render(pos); + this.currentFrame = frame; + } + } + }, + render: function(pos) { + if(this.state == 'idle') { + this.state = 'running'; + this.event('beforeSetup'); + if(this.setup) this.setup(); + this.event('afterSetup'); + } + if(this.state == 'running') { + if(this.options.transition) pos = this.options.transition(pos); + pos *= (this.options.to-this.options.from); + pos += this.options.from; + this.position = pos; + this.event('beforeUpdate'); + if(this.update) this.update(pos); + this.event('afterUpdate'); + } + }, + cancel: function() { + if(!this.options.sync) + Effect.Queues.get(typeof this.options.queue == 'string' ? + 'global' : this.options.queue.scope).remove(this); + this.state = 'finished'; + }, + event: function(eventName) { + if(this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this); + if(this.options[eventName]) this.options[eventName](this); + }, + inspect: function() { + return '#'; + } +} + +Effect.Parallel = Class.create(); +Object.extend(Object.extend(Effect.Parallel.prototype, Effect.Base.prototype), { + initialize: function(effects) { + this.effects = effects || []; + this.start(arguments[1]); + }, + update: function(position) { + this.effects.invoke('render', position); + }, + finish: function(position) { + this.effects.each( function(effect) { + effect.render(1.0); + effect.cancel(); + effect.event('beforeFinish'); + if(effect.finish) effect.finish(position); + effect.event('afterFinish'); + }); + } +}); + +Effect.Opacity = Class.create(); +Object.extend(Object.extend(Effect.Opacity.prototype, Effect.Base.prototype), { + initialize: function(element) { + this.element = $(element); + // make this work on IE on elements without 'layout' + if(/MSIE/.test(navigator.userAgent) && (!this.element.hasLayout)) + Element.setStyle(this.element, {zoom: 1}); + var options = Object.extend({ + from: Element.getOpacity(this.element) || 0.0, + to: 1.0 + }, arguments[1] || {}); + this.start(options); + }, + update: function(position) { + Element.setOpacity(this.element, position); + } +}); + +Effect.Move = Class.create(); +Object.extend(Object.extend(Effect.Move.prototype, Effect.Base.prototype), { + initialize: function(element) { + this.element = $(element); + var options = Object.extend({ + x: 0, + y: 0, + mode: 'relative' + }, arguments[1] || {}); + this.start(options); + }, + setup: function() { + // Bug in Opera: Opera returns the "real" position of a static element or + // relative element that does not have top/left explicitly set. + // ==> Always set top and left for position relative elements in your stylesheets + // (to 0 if you do not need them) + Element.makePositioned(this.element); + this.originalLeft = parseFloat(Element.getStyle(this.element,'left') || '0'); + this.originalTop = parseFloat(Element.getStyle(this.element,'top') || '0'); + if(this.options.mode == 'absolute') { + // absolute movement, so we need to calc deltaX and deltaY + this.options.x = this.options.x - this.originalLeft; + this.options.y = this.options.y - this.originalTop; + } + }, + update: function(position) { + Element.setStyle(this.element, { + left: this.options.x * position + this.originalLeft + 'px', + top: this.options.y * position + this.originalTop + 'px' + }); + } +}); + +// for backwards compatibility +Effect.MoveBy = function(element, toTop, toLeft) { + return new Effect.Move(element, + Object.extend({ x: toLeft, y: toTop }, arguments[3] || {})); +}; + +Effect.Scale = Class.create(); +Object.extend(Object.extend(Effect.Scale.prototype, Effect.Base.prototype), { + initialize: function(element, percent) { + this.element = $(element) + var options = Object.extend({ + scaleX: true, + scaleY: true, + scaleContent: true, + scaleFromCenter: false, + scaleMode: 'box', // 'box' or 'contents' or {} with provided values + scaleFrom: 100.0, + scaleTo: percent + }, arguments[2] || {}); + this.start(options); + }, + setup: function() { + this.restoreAfterFinish = this.options.restoreAfterFinish || false; + this.elementPositioning = Element.getStyle(this.element,'position'); + + this.originalStyle = {}; + ['top','left','width','height','fontSize'].each( function(k) { + this.originalStyle[k] = this.element.style[k]; + }.bind(this)); + + this.originalTop = this.element.offsetTop; + this.originalLeft = this.element.offsetLeft; + + var fontSize = Element.getStyle(this.element,'font-size') || '100%'; + ['em','px','%'].each( function(fontSizeType) { + if(fontSize.indexOf(fontSizeType)>0) { + this.fontSize = parseFloat(fontSize); + this.fontSizeType = fontSizeType; + } + }.bind(this)); + + this.factor = (this.options.scaleTo - this.options.scaleFrom)/100; + + this.dims = null; + if(this.options.scaleMode=='box') + this.dims = [this.element.offsetHeight, this.element.offsetWidth]; + if(/^content/.test(this.options.scaleMode)) + this.dims = [this.element.scrollHeight, this.element.scrollWidth]; + if(!this.dims) + this.dims = [this.options.scaleMode.originalHeight, + this.options.scaleMode.originalWidth]; + }, + update: function(position) { + var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position); + if(this.options.scaleContent && this.fontSize) + Element.setStyle(this.element, {fontSize: this.fontSize * currentScale + this.fontSizeType }); + this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale); + }, + finish: function(position) { + if (this.restoreAfterFinish) Element.setStyle(this.element, this.originalStyle); + }, + setDimensions: function(height, width) { + var d = {}; + if(this.options.scaleX) d.width = width + 'px'; + if(this.options.scaleY) d.height = height + 'px'; + if(this.options.scaleFromCenter) { + var topd = (height - this.dims[0])/2; + var leftd = (width - this.dims[1])/2; + if(this.elementPositioning == 'absolute') { + if(this.options.scaleY) d.top = this.originalTop-topd + 'px'; + if(this.options.scaleX) d.left = this.originalLeft-leftd + 'px'; + } else { + if(this.options.scaleY) d.top = -topd + 'px'; + if(this.options.scaleX) d.left = -leftd + 'px'; + } + } + Element.setStyle(this.element, d); + } +}); + +Effect.Highlight = Class.create(); +Object.extend(Object.extend(Effect.Highlight.prototype, Effect.Base.prototype), { + initialize: function(element) { + this.element = $(element); + var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || {}); + this.start(options); + }, + setup: function() { + // Prevent executing on elements not in the layout flow + if(Element.getStyle(this.element, 'display')=='none') { this.cancel(); return; } + // Disable background image during the effect + this.oldStyle = { + backgroundImage: Element.getStyle(this.element, 'background-image') }; + Element.setStyle(this.element, {backgroundImage: 'none'}); + if(!this.options.endcolor) + this.options.endcolor = Element.getStyle(this.element, 'background-color').parseColor('#ffffff'); + if(!this.options.restorecolor) + this.options.restorecolor = Element.getStyle(this.element, 'background-color'); + // init color calculations + this._base = $R(0,2).map(function(i){ return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16) }.bind(this)); + this._delta = $R(0,2).map(function(i){ return parseInt(this.options.endcolor.slice(i*2+1,i*2+3),16)-this._base[i] }.bind(this)); + }, + update: function(position) { + Element.setStyle(this.element,{backgroundColor: $R(0,2).inject('#',function(m,v,i){ + return m+(Math.round(this._base[i]+(this._delta[i]*position)).toColorPart()); }.bind(this)) }); + }, + finish: function() { + Element.setStyle(this.element, Object.extend(this.oldStyle, { + backgroundColor: this.options.restorecolor + })); + } +}); + +Effect.ScrollTo = Class.create(); +Object.extend(Object.extend(Effect.ScrollTo.prototype, Effect.Base.prototype), { + initialize: function(element) { + this.element = $(element); + this.start(arguments[1] || {}); + }, + setup: function() { + Position.prepare(); + var offsets = Position.cumulativeOffset(this.element); + if(this.options.offset) offsets[1] += this.options.offset; + var max = window.innerHeight ? + window.height - window.innerHeight : + document.body.scrollHeight - + (document.documentElement.clientHeight ? + document.documentElement.clientHeight : document.body.clientHeight); + this.scrollStart = Position.deltaY; + this.delta = (offsets[1] > max ? max : offsets[1]) - this.scrollStart; + }, + update: function(position) { + Position.prepare(); + window.scrollTo(Position.deltaX, + this.scrollStart + (position*this.delta)); + } +}); + +/* ------------- combination effects ------------- */ + +Effect.Fade = function(element) { + var oldOpacity = Element.getInlineOpacity(element); + var options = Object.extend({ + from: Element.getOpacity(element) || 1.0, + to: 0.0, + afterFinishInternal: function(effect) { with(Element) { + if(effect.options.to!=0) return; + hide(effect.element); + setStyle(effect.element, {opacity: oldOpacity}); }} + }, arguments[1] || {}); + return new Effect.Opacity(element,options); +} + +Effect.Appear = function(element) { + var options = Object.extend({ + from: (Element.getStyle(element, 'display') == 'none' ? 0.0 : Element.getOpacity(element) || 0.0), + to: 1.0, + beforeSetup: function(effect) { with(Element) { + setOpacity(effect.element, effect.options.from); + show(effect.element); }} + }, arguments[1] || {}); + return new Effect.Opacity(element,options); +} + +Effect.Puff = function(element) { + element = $(element); + var oldStyle = { opacity: Element.getInlineOpacity(element), position: Element.getStyle(element, 'position') }; + return new Effect.Parallel( + [ new Effect.Scale(element, 200, + { sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }), + new Effect.Opacity(element, { sync: true, to: 0.0 } ) ], + Object.extend({ duration: 1.0, + beforeSetupInternal: function(effect) { with(Element) { + setStyle(effect.effects[0].element, {position: 'absolute'}); }}, + afterFinishInternal: function(effect) { with(Element) { + hide(effect.effects[0].element); + setStyle(effect.effects[0].element, oldStyle); }} + }, arguments[1] || {}) + ); +} + +Effect.BlindUp = function(element) { + element = $(element); + Element.makeClipping(element); + return new Effect.Scale(element, 0, + Object.extend({ scaleContent: false, + scaleX: false, + restoreAfterFinish: true, + afterFinishInternal: function(effect) { with(Element) { + [hide, undoClipping].call(effect.element); }} + }, arguments[1] || {}) + ); +} + +Effect.BlindDown = function(element) { + element = $(element); + var oldHeight = Element.getStyle(element, 'height'); + var elementDimensions = Element.getDimensions(element); + return new Effect.Scale(element, 100, + Object.extend({ scaleContent: false, + scaleX: false, + scaleFrom: 0, + scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width}, + restoreAfterFinish: true, + afterSetup: function(effect) { with(Element) { + makeClipping(effect.element); + setStyle(effect.element, {height: '0px'}); + show(effect.element); + }}, + afterFinishInternal: function(effect) { with(Element) { + undoClipping(effect.element); + setStyle(effect.element, {height: oldHeight}); + }} + }, arguments[1] || {}) + ); +} + +Effect.SwitchOff = function(element) { + element = $(element); + var oldOpacity = Element.getInlineOpacity(element); + return new Effect.Appear(element, { + duration: 0.4, + from: 0, + transition: Effect.Transitions.flicker, + afterFinishInternal: function(effect) { + new Effect.Scale(effect.element, 1, { + duration: 0.3, scaleFromCenter: true, + scaleX: false, scaleContent: false, restoreAfterFinish: true, + beforeSetup: function(effect) { with(Element) { + [makePositioned,makeClipping].call(effect.element); + }}, + afterFinishInternal: function(effect) { with(Element) { + [hide,undoClipping,undoPositioned].call(effect.element); + setStyle(effect.element, {opacity: oldOpacity}); + }} + }) + } + }); +} + +Effect.DropOut = function(element) { + element = $(element); + var oldStyle = { + top: Element.getStyle(element, 'top'), + left: Element.getStyle(element, 'left'), + opacity: Element.getInlineOpacity(element) }; + return new Effect.Parallel( + [ new Effect.Move(element, {x: 0, y: 100, sync: true }), + new Effect.Opacity(element, { sync: true, to: 0.0 }) ], + Object.extend( + { duration: 0.5, + beforeSetup: function(effect) { with(Element) { + makePositioned(effect.effects[0].element); }}, + afterFinishInternal: function(effect) { with(Element) { + [hide, undoPositioned].call(effect.effects[0].element); + setStyle(effect.effects[0].element, oldStyle); }} + }, arguments[1] || {})); +} + +Effect.Shake = function(element) { + element = $(element); + var oldStyle = { + top: Element.getStyle(element, 'top'), + left: Element.getStyle(element, 'left') }; + return new Effect.Move(element, + { x: 20, y: 0, duration: 0.05, afterFinishInternal: function(effect) { + new Effect.Move(effect.element, + { x: -40, y: 0, duration: 0.1, afterFinishInternal: function(effect) { + new Effect.Move(effect.element, + { x: 40, y: 0, duration: 0.1, afterFinishInternal: function(effect) { + new Effect.Move(effect.element, + { x: -40, y: 0, duration: 0.1, afterFinishInternal: function(effect) { + new Effect.Move(effect.element, + { x: 40, y: 0, duration: 0.1, afterFinishInternal: function(effect) { + new Effect.Move(effect.element, + { x: -20, y: 0, duration: 0.05, afterFinishInternal: function(effect) { with(Element) { + undoPositioned(effect.element); + setStyle(effect.element, oldStyle); + }}}) }}) }}) }}) }}) }}); +} + +Effect.SlideDown = function(element) { + element = $(element); + Element.cleanWhitespace(element); + // SlideDown need to have the content of the element wrapped in a container element with fixed height! + var oldInnerBottom = Element.getStyle(element.firstChild, 'bottom'); + var elementDimensions = Element.getDimensions(element); + return new Effect.Scale(element, 100, Object.extend({ + scaleContent: false, + scaleX: false, + scaleFrom: 0, + scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width}, + restoreAfterFinish: true, + afterSetup: function(effect) { with(Element) { + makePositioned(effect.element); + makePositioned(effect.element.firstChild); + if(window.opera) setStyle(effect.element, {top: ''}); + makeClipping(effect.element); + setStyle(effect.element, {height: '0px'}); + show(element); }}, + afterUpdateInternal: function(effect) { with(Element) { + setStyle(effect.element.firstChild, {bottom: + (effect.dims[0] - effect.element.clientHeight) + 'px' }); }}, + afterFinishInternal: function(effect) { with(Element) { + undoClipping(effect.element); + undoPositioned(effect.element.firstChild); + undoPositioned(effect.element); + setStyle(effect.element.firstChild, {bottom: oldInnerBottom}); }} + }, arguments[1] || {}) + ); +} + +Effect.SlideUp = function(element) { + element = $(element); + Element.cleanWhitespace(element); + var oldInnerBottom = Element.getStyle(element.firstChild, 'bottom'); + return new Effect.Scale(element, 0, + Object.extend({ scaleContent: false, + scaleX: false, + scaleMode: 'box', + scaleFrom: 100, + restoreAfterFinish: true, + beforeStartInternal: function(effect) { with(Element) { + makePositioned(effect.element); + makePositioned(effect.element.firstChild); + if(window.opera) setStyle(effect.element, {top: ''}); + makeClipping(effect.element); + show(element); }}, + afterUpdateInternal: function(effect) { with(Element) { + setStyle(effect.element.firstChild, {bottom: + (effect.dims[0] - effect.element.clientHeight) + 'px' }); }}, + afterFinishInternal: function(effect) { with(Element) { + [hide, undoClipping].call(effect.element); + undoPositioned(effect.element.firstChild); + undoPositioned(effect.element); + setStyle(effect.element.firstChild, {bottom: oldInnerBottom}); }} + }, arguments[1] || {}) + ); +} + +// Bug in opera makes the TD containing this element expand for a instance after finish +Effect.Squish = function(element) { + return new Effect.Scale(element, window.opera ? 1 : 0, + { restoreAfterFinish: true, + beforeSetup: function(effect) { with(Element) { + makeClipping(effect.element); }}, + afterFinishInternal: function(effect) { with(Element) { + hide(effect.element); + undoClipping(effect.element); }} + }); +} + +Effect.Grow = function(element) { + element = $(element); + var options = Object.extend({ + direction: 'center', + moveTransistion: Effect.Transitions.sinoidal, + scaleTransition: Effect.Transitions.sinoidal, + opacityTransition: Effect.Transitions.full + }, arguments[1] || {}); + var oldStyle = { + top: element.style.top, + left: element.style.left, + height: element.style.height, + width: element.style.width, + opacity: Element.getInlineOpacity(element) }; + + var dims = Element.getDimensions(element); + var initialMoveX, initialMoveY; + var moveX, moveY; + + switch (options.direction) { + case 'top-left': + initialMoveX = initialMoveY = moveX = moveY = 0; + break; + case 'top-right': + initialMoveX = dims.width; + initialMoveY = moveY = 0; + moveX = -dims.width; + break; + case 'bottom-left': + initialMoveX = moveX = 0; + initialMoveY = dims.height; + moveY = -dims.height; + break; + case 'bottom-right': + initialMoveX = dims.width; + initialMoveY = dims.height; + moveX = -dims.width; + moveY = -dims.height; + break; + case 'center': + initialMoveX = dims.width / 2; + initialMoveY = dims.height / 2; + moveX = -dims.width / 2; + moveY = -dims.height / 2; + break; + } + + return new Effect.Move(element, { + x: initialMoveX, + y: initialMoveY, + duration: 0.01, + beforeSetup: function(effect) { with(Element) { + hide(effect.element); + makeClipping(effect.element); + makePositioned(effect.element); + }}, + afterFinishInternal: function(effect) { + new Effect.Parallel( + [ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }), + new Effect.Move(effect.element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }), + new Effect.Scale(effect.element, 100, { + scaleMode: { originalHeight: dims.height, originalWidth: dims.width }, + sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true}) + ], Object.extend({ + beforeSetup: function(effect) { with(Element) { + setStyle(effect.effects[0].element, {height: '0px'}); + show(effect.effects[0].element); }}, + afterFinishInternal: function(effect) { with(Element) { + [undoClipping, undoPositioned].call(effect.effects[0].element); + setStyle(effect.effects[0].element, oldStyle); }} + }, options) + ) + } + }); +} + +Effect.Shrink = function(element) { + element = $(element); + var options = Object.extend({ + direction: 'center', + moveTransistion: Effect.Transitions.sinoidal, + scaleTransition: Effect.Transitions.sinoidal, + opacityTransition: Effect.Transitions.none + }, arguments[1] || {}); + var oldStyle = { + top: element.style.top, + left: element.style.left, + height: element.style.height, + width: element.style.width, + opacity: Element.getInlineOpacity(element) }; + + var dims = Element.getDimensions(element); + var moveX, moveY; + + switch (options.direction) { + case 'top-left': + moveX = moveY = 0; + break; + case 'top-right': + moveX = dims.width; + moveY = 0; + break; + case 'bottom-left': + moveX = 0; + moveY = dims.height; + break; + case 'bottom-right': + moveX = dims.width; + moveY = dims.height; + break; + case 'center': + moveX = dims.width / 2; + moveY = dims.height / 2; + break; + } + + return new Effect.Parallel( + [ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }), + new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true}), + new Effect.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }) + ], Object.extend({ + beforeStartInternal: function(effect) { with(Element) { + [makePositioned, makeClipping].call(effect.effects[0].element) }}, + afterFinishInternal: function(effect) { with(Element) { + [hide, undoClipping, undoPositioned].call(effect.effects[0].element); + setStyle(effect.effects[0].element, oldStyle); }} + }, options) + ); +} + +Effect.Pulsate = function(element) { + element = $(element); + var options = arguments[1] || {}; + var oldOpacity = Element.getInlineOpacity(element); + var transition = options.transition || Effect.Transitions.sinoidal; + var reverser = function(pos){ return transition(1-Effect.Transitions.pulse(pos)) }; + reverser.bind(transition); + return new Effect.Opacity(element, + Object.extend(Object.extend({ duration: 3.0, from: 0, + afterFinishInternal: function(effect) { Element.setStyle(effect.element, {opacity: oldOpacity}); } + }, options), {transition: reverser})); +} + +Effect.Fold = function(element) { + element = $(element); + var oldStyle = { + top: element.style.top, + left: element.style.left, + width: element.style.width, + height: element.style.height }; + Element.makeClipping(element); + return new Effect.Scale(element, 5, Object.extend({ + scaleContent: false, + scaleX: false, + afterFinishInternal: function(effect) { + new Effect.Scale(element, 1, { + scaleContent: false, + scaleY: false, + afterFinishInternal: function(effect) { with(Element) { + [hide, undoClipping].call(effect.element); + setStyle(effect.element, oldStyle); + }} }); + }}, arguments[1] || {})); +} Index: openacs-4/packages/forums/www/resources/Forward16.gif =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/forums/www/resources/Forward16.gif,v diff -u Binary files differ Index: openacs-4/packages/forums/www/resources/ReplyAll16.gif =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/forums/www/resources/ReplyAll16.gif,v diff -u Binary files differ Index: openacs-4/packages/forums/www/resources/collapseAll.png =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/forums/www/resources/collapseAll.png,v diff -u Binary files differ Index: openacs-4/packages/forums/www/resources/collapse_all.png =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/forums/www/resources/collapse_all.png,v diff -u Binary files differ Index: openacs-4/packages/forums/www/resources/collapse_content.css =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/forums/www/resources/collapse_content.css,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/forums/www/resources/collapse_content.css 28 Jun 2006 20:30:29 -0000 1.1 @@ -0,0 +1,3 @@ +#forum-thread .content { + display: none; +} Index: openacs-4/packages/forums/www/resources/del.png =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/forums/www/resources/del.png,v diff -u Binary files differ Index: openacs-4/packages/forums/www/resources/delete.gif =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/forums/www/resources/delete.gif,v diff -u Binary files differ Index: openacs-4/packages/forums/www/resources/delete.png =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/forums/www/resources/delete.png,v diff -u Binary files differ Index: openacs-4/packages/forums/www/resources/expand.png =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/forums/www/resources/expand.png,v diff -u Binary files differ Index: openacs-4/packages/forums/www/resources/expand2.png =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/forums/www/resources/expand2.png,v diff -u Binary files differ Index: openacs-4/packages/forums/www/resources/expandAll.png =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/forums/www/resources/expandAll.png,v diff -u Binary files differ Index: openacs-4/packages/forums/www/resources/expandO.png =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/forums/www/resources/expandO.png,v diff -u Binary files differ Index: openacs-4/packages/forums/www/resources/expand_all.png =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/forums/www/resources/expand_all.png,v diff -u Binary files differ Index: openacs-4/packages/forums/www/resources/forward.png =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/forums/www/resources/forward.png,v diff -u Binary files differ Index: openacs-4/packages/forums/www/resources/fwd.png =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/forums/www/resources/fwd.png,v diff -u Binary files differ Index: openacs-4/packages/forums/www/resources/message-effects.js =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/forums/www/resources/message-effects.js,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/forums/www/resources/message-effects.js 28 Jun 2006 20:30:29 -0000 1.1 @@ -0,0 +1,338 @@ +/* +- Script for collapse or expand the parent message and all his childs +- It uses the scriptaculous libraries for the effects + +Autor: Veronica De La Cruz + +*/ + +// Libraries to be included in this script are the +// scriptaculuos's libraries of ajaxhelper + + +// Some global variables, used in dynamicExpand() + +var expand_symbol ='+'; +var collapse_symbol ='-'; + +// This function only creates an array by a giving string of characters +// separated by blank space + +function getChildsArray(childrenString) { + + var childrenArray = new Array(); + var aux = childrenString; + var aux2 = ""; + var pos = childrenString.indexOf(" "); + var childrenStringLength = childrenString.length; + var i = 0; + var j = 0; + + // Separate all the children + + while(j <= childrenStringLength) { + + if (pos == -1){ + aux2= aux.substring(j); + childrenArray[i] = aux2; + break; + } + + childrenArray[i]= aux.substring(j,pos); + j=pos+1; + pos = childrenString.indexOf(" ",j); + i++; + } + + + return childrenArray; + + } + + +// Function that return the element properties and id + +function getId(id) { + if(document.getElementById) + return document.getElementById(id); + else if(document.all) + return document.all(id); + return false; +} + + +/* + FUNCTION: + expandChilds + + PARAMETERS: + - parentID: contains only the message_id + - childrenString: contains a string of all the children of the current message separate by + blank space + + FORMAT OF PARAMETERS: + + - parentID : message_id ; Example: 2343 + - childrenString : childrenmessage_id childrenmessage_id ; Example: 23324 32 31 321 + +*/ + + + +function expandChilds(parentID, childrenString){ + + //Get the parentID in a portable manner + + var objectParent = getId('content'+parentID); + var actionObjectParent = getId('actions'+parentID); + var parentSymbol = getId('toggle'+parentID); + var subject = getId('subject' +parentID); + var joinAll = getId('join'+parentID); + var parentStyle = Element.getStyle(objectParent,'display'); + + + //Only if the parentID message has any children + + if (childrenString != null) { + + var childArray = getChildsArray(childrenString); + + + // Make that the parent message and all his children + // take part on the effect + + + for (var i=0;i< childArray.length;i++){ + + + var objectChild = getId('content'+childArray[i]); + var objectAction= getId('actions'+childArray[i]); + var objectSymbol= getId('toggle'+childArray[i]); + var objectSubject= getId('subject'+childArray[i]); + var objectJoin = getId('join'+childArray[i]); + + var objectStyle = Element.getStyle(objectChild,'display'); + + // Change the state of the individual collapse/expand + + if (objectStyle == 'none') { + objectSymbol.innerHTML = collapse_symbol; + } + + + Element.show(objectChild); + Element.show(objectAction); + Element.hide(objectJoin); + Element.show(objectSubject); + + + } + + } + // Change the state of the individual collapse/expand + + if (parentStyle == 'none') { + parentSymbol.innerHTML = collapse_symbol; + } + + Element.show(objectParent); + Element.show(actionObjectParent); + Element.show(subject); + Element.hide(joinAll); + + + + } + + + + +// The same as expandsChilds but collapse the contents of the message + +function collapseChilds(parentID, childrenString){ + + //Get the parentID in a portable manner + + var objectParent = getId('content'+parentID); + var actionObjectParent = getId('actions'+parentID); + var parentSymbol = getId('toggle'+parentID); + var subject = getId('subject'+parentID); + var joinAll = getId('join'+parentID); + + var parentStyle = Element.getStyle(objectParent,'display'); + + //Only if the parentID message has any children + + if (childrenString != null) { + + var childArray = getChildsArray(childrenString); + + + // Make that the parent message and all his children + // take part on the efect + + + for (var i=0;i< childArray.length;i++){ + + var objectChild = getId('content'+childArray[i]); + var objectAction= getId('actions'+childArray[i]); + var objectSymbol= getId('toggle'+childArray[i]); + var objectSubject= getId('subject'+childArray[i]); + var objectJoin = getId('join'+childArray[i]); + var objectStyle = Element.getStyle(objectChild,'display'); + + + // Change the state of the individual collapse/expand + + if (objectStyle == 'block') { + objectSymbol.innerHTML = expand_symbol; + } + + Element.hide(objectChild); + Element.hide(objectAction); + Element.hide(objectSubject); + Element.show(objectJoin); + Element.setStyle(objectJoin,{display:'inline-block'}); + } + + } + // Change the state of the individual collapse/expand + + if (parentStyle == 'block') { + parentSymbol.innerHTML = expand_symbol; + } + + Element.hide(objectParent); + Element.hide(actionObjectParent); + Element.hide(subject); + Element.show(joinAll); + Element.setStyle(joinAll,{display:'inline-block'}); +} + +/* + FUNCTION: dynamicExpand + + PARAMETERS: the id of the element to be expanded or collapsed + + USE CASE: for individual functionality for expand or collapse + messages +*/ + + + function dynamicExpand(targetID) { + + var objectTargetID = getId('content'+targetID); + var objectAction= getId('actions'+targetID); + var symbolLink = getId('toggle'+targetID); + var objectSubject = getId('subject'+targetID); + var objectJoin = getId('join'+targetID); + var objectStyle = Element.getStyle(objectTargetID,'display'); + + + if(!symbolLink || !objectTargetID) return; + + // If the message is collapse we want that + // the symbol to be displayed is the expand one. + + if (objectStyle == 'none') { + + symbolLink.innerHTML = collapse_symbol; + Element.hide(objectJoin); + Element.show(objectTargetID); + Element.show(objectAction); + Element.show(objectSubject); + + + } + else { + + symbolLink.innerHTML = expand_symbol; + + Element.show(objectJoin); + Element.setStyle(objectJoin,{display:'inline-block'}); + Element.hide(objectTargetID); + Element.hide(objectAction); + Element.hide(objectSubject); + + + + + } + + } + +/*Show expanded only the direct children of the main message when the + page is loaded */ + + function showExpandedOnLoad( parentID, directChildrenString, allChildrenString) { + + var directChildren = getChildsArray(directChildrenString); + var allChildren = getChildsArray(allChildrenString); + + for (var i=0;i< directChildren.length;i++){ + for (var j=0;j< allChildren.length;j++){ + if (allChildren[j] == directChildren[i]){ + allChildren[j]= undefined; + break; + } + continue; + } + } + + for (var j=0;j< allChildren.length;j++) { + if(allChildren[j] != undefined){ + collapseOnLoad(allChildren[j]); + loadContent(allChildren[j]); + } + } + } + + +//------------------------------ + + +/* The same as expandsChilds but collapse the contents of the message*/ + +function collapseOnLoad(parentID){ + + //Get the parentID in a portable manner + + var actionObjectParent = getId('actions'+parentID); + var parentSymbol = getId('toggle'+parentID); + var subject = getId('subject'+parentID); + var joinAll = getId('join'+parentID); + + + // Change the state of the individual collapse/expand + + + parentSymbol.innerHTML = expand_symbol; + + // Collapse the message contents + + Element.hide(actionObjectParent); + Element.hide(subject); + Element.show(joinAll); + Element.setStyle(joinAll,{display:'inline-block'}); + +} + +/* + Loads the content of a given message. + parameters: messageID (the ID of the message that the content is required) +*/ + +function loadContent(messageID) { + + var containerID = getId('content'+ messageID); + var symbol = getId('toggle'+ messageID); + var url = 'load-message-content'; + var par = 'message_id='+messageID; + + + Element.setStyle(containerID, {display:'none'}); + + // This is the function that preloads the message's contents + var ajax = new Ajax.Updater(containerID, url, {asynchronous:'true', method:'post', parameters: par}); + +} Index: openacs-4/packages/forums/www/resources/reeply.png =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/forums/www/resources/reeply.png,v diff -u Binary files differ Index: openacs-4/packages/forums/www/resources/reply.gif =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/forums/www/resources/reply.gif,v diff -u Binary files differ Index: openacs-4/packages/forums/www/resources/reply.png =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/forums/www/resources/reply.png,v diff -u Binary files differ Index: openacs-4/packages/forums/www/resources/services.png =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/forums/www/resources/services.png,v diff -u Binary files differ